// CHECKSTYLE:FileLength:OFF
/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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.pentaho.di.ui.core.widget;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.events.SelectionListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
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.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
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.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.pentaho.di.core.Condition;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.Props;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.exception.KettleValueException;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaFactory;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.undo.TransAction;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.dialog.EnterConditionDialog;
import org.pentaho.di.ui.core.dialog.ErrorDialog;
import org.pentaho.di.ui.core.gui.GUIResource;
/**
* Widget to display or modify data, displayed in a Table format.
*
* @author Matt
* @since 27-05-2003
*/
public class TableView extends Composite {
private static Class<?> PKG = TableView.class; // for i18n purposes, needed by Translator2!!
private Composite parent;
private ColumnInfo[] columns;
private int rows;
private boolean readonly;
private int buttonRownr;
private int buttonColnr;
private String buttonContent;
private boolean previousShift;
private int selectionStart;
public Table table;
private TableEditor editor;
private TableColumn[] tablecolumn;
private PropsUI props;
private Control text;
private CCombo combo;
private Button button;
private TableItem activeTableItem;
private int activeTableColumn;
private int activeTableRow;
private KeyListener lsKeyText, lsKeyCombo;
private FocusAdapter lsFocusText, lsFocusCombo;
private ModifyListener lsModCombo;
private TraverseListener lsTraverse;
private int sortfield;
private int sortfieldLast;
private boolean sortingDescending;
private Boolean sortingDescendingLast;
private boolean sortable;
private int lastRowCount;
private boolean fieldChanged;
private Menu mRow;
private ModifyListener lsMod, lsUndo, lsContent;
private Clipboard clipboard;
// The following Image and Graphics Context are used for font metrics. We only
// want them created once.
private static Image dummyImage;
private static GC dummyGC;
private Font gridFont;
// private int last_carret_position;
private ArrayList<TransAction> undo;
private int undoPosition;
private String[] beforeEdit;
private MenuItem miEditUndo, miEditRedo;
private static final String CLIPBOARD_DELIMITER = "\t";
private Condition condition;
private Color defaultBackgroundColor;
private Map<String, Color> usedColors;
private ColumnInfo numberColumn;
protected int textWidgetCaretPosition;
private VariableSpace variables;
private boolean showingBlueNullValues;
private boolean showingConversionErrorsInline;
private boolean isTextButton = false;
private boolean addIndexColumn = true;
public TableView( VariableSpace space, Composite parent, int style, ColumnInfo[] columnInfo, int nrRows,
ModifyListener lsm, PropsUI pr ) {
this( space, parent, style, columnInfo, nrRows, false, lsm, pr );
}
public TableView( VariableSpace space, Composite parent, int style, ColumnInfo[] columnInfo, int nrRows,
boolean readOnly, ModifyListener lsm, PropsUI pr ) {
this( space, parent, style, columnInfo, nrRows, false, lsm, pr, true );
}
public TableView( VariableSpace space, Composite parent, int style, ColumnInfo[] columnInfo, int nrRows,
boolean readOnly, ModifyListener lsm, PropsUI pr, final boolean addIndexColumn ) {
super( parent, SWT.NO_BACKGROUND | SWT.NO_FOCUS | SWT.NO_MERGE_PAINTS | SWT.NO_RADIO_GROUP );
this.parent = parent;
this.columns = columnInfo;
this.rows = nrRows;
this.props = pr;
this.readonly = readOnly;
this.clipboard = null;
this.variables = space;
this.addIndexColumn = addIndexColumn;
sortfield = 0;
sortfieldLast = -1;
sortingDescending = false;
sortingDescendingLast = null;
sortable = true;
selectionStart = -1;
previousShift = false;
usedColors = new Hashtable<String, Color>();
condition = null;
lsMod = lsm;
clearUndo();
numberColumn = new ColumnInfo( "#", ColumnInfo.COLUMN_TYPE_TEXT, true, true );
ValueMetaInterface numberColumnValueMeta = new ValueMetaInteger( "#" );
numberColumnValueMeta.setConversionMask( "####0" );
numberColumn.setValueMeta( numberColumnValueMeta );
lsUndo = new ModifyListener() {
@Override
public void modifyText( ModifyEvent arg0 ) {
fieldChanged = true;
}
};
if ( TableView.dummyGC == null ) {
Display disp = parent.getDisplay();
TableView.dummyImage = new Image( disp, 1, 1 );
TableView.dummyGC = new GC( TableView.dummyImage );
gridFont = new Font( disp, props.getGridFont() );
TableView.dummyGC.setFont( gridFont );
}
FormLayout controlLayout = new FormLayout();
controlLayout.marginLeft = 0;
controlLayout.marginRight = 0;
controlLayout.marginTop = 0;
controlLayout.marginBottom = 0;
setLayout( controlLayout );
// setLayout(new GridLayout());
// Create table, add columns & rows...
table = new Table( this, style | SWT.MULTI );
props.setLook( table, Props.WIDGET_STYLE_TABLE );
table.setLinesVisible( true );
// table.setLayout(new FormLayout());
// table.setLayoutData(new GridData(GridData.FILL_BOTH));
FormData fdTable = new FormData();
fdTable.left = new FormAttachment( 0, 0 );
fdTable.right = new FormAttachment( 100, 0 );
fdTable.top = new FormAttachment( 0, 0 );
fdTable.bottom = new FormAttachment( 100, 0 );
table.setLayoutData( fdTable );
tablecolumn = new TableColumn[columns.length + 1];
tablecolumn[0] = new TableColumn( table, SWT.RIGHT );
tablecolumn[0].setResizable( true );
tablecolumn[0].setText( "#" );
tablecolumn[0].setWidth( addIndexColumn ? 25 : 0 );
tablecolumn[0].setAlignment( SWT.RIGHT );
for ( int i = 0; i < columns.length; i++ ) {
int allignment = columns[i].getAllignement();
tablecolumn[i + 1] = new TableColumn( table, allignment );
tablecolumn[i + 1].setResizable( true );
if ( columns[i].getName() != null ) {
tablecolumn[i + 1].setText( columns[i].getName() );
}
if ( columns[i].getToolTip() != null ) {
tablecolumn[i + 1].setToolTipText( ( columns[i].getToolTip() ) );
}
ValueMetaInterface valueMeta = columns[i].getValueMeta();
if ( valueMeta != null && valueMeta.isNumeric() ) {
tablecolumn[i + 1].setAlignment( SWT.RIGHT );
}
tablecolumn[i + 1].pack();
}
table.setHeaderVisible( true );
table.setLinesVisible( true );
// Set the default values...
if ( rows > 0 ) {
table.setItemCount( rows );
} else {
table.setItemCount( 1 );
}
// Get the background color of item 0, before anything happened with it,
// that's the default color.
defaultBackgroundColor = table.getItem( 0 ).getBackground();
setRowNums();
// Set the sort sign on the first column. (0)
table.setSortColumn( table.getColumn( sortfield ) );
table.setSortDirection( sortingDescending ? SWT.DOWN : SWT.UP );
// create a ControlEditor field to edit the contents of a cell
editor = new TableEditor( table );
editor.grabHorizontal = true;
editor.grabVertical = true;
mRow = new Menu( table );
MenuItem miRowInsBef = new MenuItem( mRow, SWT.NONE );
miRowInsBef.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.InsertBeforeRow" ) ) );
MenuItem miRowInsAft = new MenuItem( mRow, SWT.NONE );
miRowInsAft.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.InsertAfterRow" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
MenuItem miRowUp = new MenuItem( mRow, SWT.NONE );
miRowUp.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.MoveUp" ) ) );
MenuItem miRowDown = new MenuItem( mRow, SWT.NONE );
miRowDown.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.MoveDown" ) ) );
MenuItem miCol1 = new MenuItem( mRow, SWT.NONE );
miCol1.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.OptimalSizeWithHeader" ) ) );
MenuItem miCol2 = new MenuItem( mRow, SWT.NONE );
miCol2.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.OptimalSizeWithoutHeader" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
MenuItem miClear = new MenuItem( mRow, SWT.NONE );
miClear.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.ClearAll" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
MenuItem miSelAll = new MenuItem( mRow, SWT.NONE );
miSelAll.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.SelectAll" ) ) );
MenuItem miUnselAll = new MenuItem( mRow, SWT.NONE );
miUnselAll.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.ClearSelection" ) ) );
MenuItem miFilter = new MenuItem( mRow, SWT.NONE );
miFilter.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.FilteredSelection" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
MenuItem miClipAll = new MenuItem( mRow, SWT.NONE );
miClipAll.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.CopyToClipboard" ) ) );
MenuItem miPasteAll = new MenuItem( mRow, SWT.NONE );
miPasteAll.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.PasteFromClipboard" ) ) );
MenuItem miCutAll = new MenuItem( mRow, SWT.NONE );
miCutAll
.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.CutSelected" ) ) );
MenuItem miDelAll = new MenuItem( mRow, SWT.NONE );
miDelAll.setText( OsHelper.customizeMenuitemText( BaseMessages
.getString( PKG, "TableView.menu.DeleteSelected" ) ) );
MenuItem miKeep = new MenuItem( mRow, SWT.NONE );
miKeep
.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.KeepSelected" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
MenuItem miCopyToAll = new MenuItem( mRow, SWT.NONE );
miCopyToAll.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.CopyFieldToAllRows" ) ) );
new MenuItem( mRow, SWT.SEPARATOR );
miEditUndo = new MenuItem( mRow, SWT.NONE );
miEditRedo = new MenuItem( mRow, SWT.NONE );
setUndoMenu();
if ( readonly ) {
miRowInsBef.setEnabled( false );
miRowInsAft.setEnabled( false );
miRowUp.setEnabled( false );
miRowDown.setEnabled( false );
miClear.setEnabled( false );
miCopyToAll.setEnabled( false );
miPasteAll.setEnabled( false );
miDelAll.setEnabled( false );
miCutAll.setEnabled( false );
miKeep.setEnabled( false );
}
SelectionAdapter lsRowInsBef = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
insertRowBefore();
}
};
SelectionAdapter lsRowInsAft = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
insertRowAfter();
}
};
SelectionAdapter lsCol1 = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
optWidth( true );
}
};
SelectionAdapter lsCol2 = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
optWidth( false );
}
};
SelectionAdapter lsRowUp = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
moveRows( -1 );
}
};
SelectionAdapter lsRowDown = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
moveRows( +1 );
}
};
SelectionAdapter lsClear = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
clearAll( true );
}
};
SelectionAdapter lsClipAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
clipSelected();
}
};
SelectionAdapter lsCopyToAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
copyToAll();
}
};
SelectionAdapter lsSelAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
selectAll();
}
};
SelectionAdapter lsUnselAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
unselectAll();
}
};
SelectionAdapter lsPasteAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
pasteSelected();
}
};
SelectionAdapter lsCutAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
cutSelected();
}
};
SelectionAdapter lsDelAll = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
delSelected();
}
};
SelectionAdapter lsKeep = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
keepSelected();
}
};
SelectionAdapter lsFilter = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
setFilter();
}
};
SelectionAdapter lsEditUndo = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
undoAction();
}
};
SelectionAdapter lsEditRedo = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
redoAction();
}
};
miRowInsBef.addSelectionListener( lsRowInsBef );
miRowInsAft.addSelectionListener( lsRowInsAft );
miCol1.addSelectionListener( lsCol1 );
miCol2.addSelectionListener( lsCol2 );
miRowUp.addSelectionListener( lsRowUp );
miRowDown.addSelectionListener( lsRowDown );
miClear.addSelectionListener( lsClear );
miClipAll.addSelectionListener( lsClipAll );
miCopyToAll.addSelectionListener( lsCopyToAll );
miSelAll.addSelectionListener( lsSelAll );
miUnselAll.addSelectionListener( lsUnselAll );
miPasteAll.addSelectionListener( lsPasteAll );
miCutAll.addSelectionListener( lsCutAll );
miDelAll.addSelectionListener( lsDelAll );
miKeep.addSelectionListener( lsKeep );
miFilter.addSelectionListener( lsFilter );
miEditUndo.addSelectionListener( lsEditUndo );
miEditRedo.addSelectionListener( lsEditRedo );
table.setMenu( mRow );
lsFocusText = new FocusAdapter() {
@Override
public void focusLost( FocusEvent e ) {
final Display d = Display.getCurrent();
if ( table.isDisposed() ) {
return;
}
final TableItem row = activeTableItem;
if ( row == null ) {
return;
}
final int colnr = activeTableColumn;
final int rownr = table.indexOf( row );
final Control ftext = text;
final String[] fBeforeEdit = beforeEdit;
// Save the position of the caret for the focus-dropping popup-dialogs
// The content is then in contentDestination
textWidgetCaretPosition = getTextWidgetCaretPosition( colnr );
final String value = getTextWidgetValue( colnr );
final Runnable worker = new Runnable() {
@Override
public void run() {
try {
if ( row.isDisposed() ) {
return;
}
row.setText( colnr, value );
ftext.dispose();
String[] afterEdit = getItemText( row );
checkChanged( new String[][]{ fBeforeEdit }, new String[][]{ afterEdit }, new int[]{ rownr } );
} catch ( Exception ignored ) {
// widget is disposed, ignore
}
}
};
// force the immediate update
if ( !row.isDisposed() ) {
row.setText( colnr, value );
}
if ( columns[colnr - 1].getType() == ColumnInfo.COLUMN_TYPE_TEXT_BUTTON ) {
try {
Thread.sleep( 500 );
} catch ( InterruptedException ignored ) {
// ignored
}
Runnable r = new Runnable() {
@Override
public void run() {
d.asyncExec( worker );
}
};
Thread t = new Thread( r );
t.start();
} else {
worker.run();
}
}
};
lsFocusCombo = new FocusAdapter() {
@Override
public void focusLost( FocusEvent e ) {
TableItem row = activeTableItem;
if ( row == null ) {
return;
}
int colnr = activeTableColumn;
int rownr = table.indexOf( row );
if ( colnr > 0 ) {
try {
row.setText( colnr, combo.getText() );
} catch ( Exception exc ) {
// Eat widget disposed error
}
String[] afterEdit = getItemText( row );
if ( afterEdit != null ) {
checkChanged( new String[][]{ beforeEdit }, new String[][]{ afterEdit }, new int[]{ rownr } );
}
}
combo.dispose();
}
};
lsModCombo = new ModifyListener() {
@Override
public void modifyText( ModifyEvent e ) {
TableItem row = activeTableItem;
if ( row == null ) {
return;
}
int colnr = activeTableColumn;
int rownr = table.indexOf( row );
row.setText( colnr, combo.getText() );
String[] afterEdit = getItemText( row );
checkChanged( new String[][]{ beforeEdit }, new String[][]{ afterEdit }, new int[]{ rownr } );
}
};
// Catch the keys pressed when editing a Text-field...
lsKeyText = new KeyAdapter() {
@Override
public void keyPressed( KeyEvent e ) {
boolean right = false;
boolean left = false;
/*
* left = e.keyCode == SWT.ARROW_LEFT && last_carret_position==0;
*
* if (text!=null && !text.isDisposed()) right = e.keyCode == SWT.ARROW_RIGHT &&
* last_carret_position==text.getText().length();
*/
// "ENTER": close the text editor and copy the data over
// We edit the data after moving to another cell, only if editNextCell =
// true;
if ( e.character == SWT.CR
|| e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.TAB || left || right ) {
if ( activeTableItem == null ) {
return;
}
applyTextChange( activeTableItem, activeTableRow, activeTableColumn );
int maxcols = table.getColumnCount();
int maxrows = table.getItemCount();
boolean editNextCell = false;
if ( e.keyCode == SWT.ARROW_DOWN && activeTableRow < maxrows - 1 ) {
activeTableRow++;
editNextCell = true;
}
if ( e.keyCode == SWT.ARROW_UP && activeTableRow > 0 ) {
activeTableRow--;
editNextCell = true;
}
// TAB
if ( ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) == 0 ) ) || right ) {
activeTableColumn++;
editNextCell = true;
}
// Shift Tab
if ( ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) != 0 ) ) || left ) {
activeTableColumn--;
editNextCell = true;
}
if ( activeTableColumn < 1 ) { // from SHIFT-TAB
activeTableColumn = maxcols - 1;
if ( activeTableRow > 0 ) {
activeTableRow--;
}
}
if ( activeTableColumn >= maxcols ) { // from TAB
activeTableColumn = 1;
activeTableRow++;
}
// Tab beyond last line: add a line to table!
if ( activeTableRow >= maxrows ) {
TableItem item = new TableItem( table, SWT.NONE, activeTableRow );
item.setText( 1, "" );
setRowNums();
}
activeTableItem = table.getItem( activeTableRow ); // just to make sure!
if ( editNextCell ) {
edit( activeTableRow, activeTableColumn );
} else {
if ( e.keyCode == SWT.ARROW_DOWN && activeTableRow == maxrows - 1 ) {
insertRowAfter();
}
}
} else if ( e.keyCode == SWT.ESC ) {
text.dispose();
// setFocus();
table.setFocus();
}
// last_carret_position = text.isDisposed()?-1:text.getCaretPosition();
}
};
// Catch the keys pressed when editing a Combo field
lsKeyCombo = new KeyAdapter() {
@Override
public void keyPressed( KeyEvent e ) {
boolean ctrl = ( ( e.stateMask & SWT.MOD1 ) != 0 );
// CTRL-V --> Paste selected infomation...
if ( e.keyCode == 'v' && ctrl ) {
e.doit = false;
if ( clipboard != null ) {
clipboard.dispose();
clipboard = null;
}
clipboard = new Clipboard( getDisplay() );
TextTransfer tran = TextTransfer.getInstance();
String text = (String) clipboard.getContents( tran );
combo.setText( text );
return;
}
boolean right = false;
boolean left = false;
// "ENTER": close the text editor and copy the data over
if ( e.keyCode == SWT.CR || e.keyCode == SWT.TAB || left || right ) {
if ( activeTableItem == null ) {
return;
}
applyComboChange( activeTableItem, activeTableRow, activeTableColumn );
String[] afterEdit = getItemText( activeTableItem );
checkChanged(
new String[][]{ beforeEdit }, new String[][]{ afterEdit }, new int[]{ activeTableRow } );
int maxcols = table.getColumnCount();
int maxrows = table.getItemCount();
boolean sel = false;
// TAB
if ( ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) == 0 ) ) || right ) {
activeTableColumn++;
sel = true;
}
// Shift Tab
if ( ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) != 0 ) ) || right ) {
activeTableColumn--;
sel = true;
}
if ( activeTableColumn < 1 ) { // from SHIFT-TAB
activeTableColumn = maxcols - 1;
if ( activeTableRow > 0 ) {
activeTableRow--;
}
}
if ( activeTableColumn >= maxcols ) { // from TAB
activeTableColumn = 1;
activeTableRow++;
}
// Tab beyond last line: add a line to table!
if ( activeTableRow >= maxrows ) {
TableItem item = new TableItem( table, SWT.NONE, activeTableRow );
item.setText( 1, "" );
setRowNums();
}
if ( sel ) {
edit( activeTableRow, activeTableColumn );
}
table.setFocus();
} else if ( e.keyCode == SWT.ESC ) {
if ( activeTableItem != null ) {
activeTableItem.setText( activeTableColumn, beforeEdit[activeTableColumn - 1] );
}
combo.dispose();
table.setFocus();
e.doit = false;
}
// last_carret_position = combo.isDisposed()?-1:0;
}
};
/*
* It seems there is an other keyListener active to help control the cursor. There is support for keys like
* LEFT/RIGHT/UP/DOWN/HOME/END/etc It presents us with a problem because we only get the position of the row/column
* AFTER the other listener did it's job. Therefor we added global variables prev_rownr and prev_colnr
*/
KeyListener lsKeyTable = new KeyAdapter() {
@Override
public void keyPressed( KeyEvent e ) {
if ( activeTableItem == null ) {
return;
}
int maxcols = table.getColumnCount();
int maxrows = table.getItemCount();
boolean shift = ( e.stateMask & SWT.SHIFT ) != 0;
if ( !previousShift && shift || selectionStart < 0 ) {
// Shift is pressed down: reset start of selection
// No start of selection known? reset as well.
selectionStart = activeTableRow;
}
previousShift = shift;
boolean ctrl = ( ( e.stateMask & SWT.MOD1 ) != 0 );
// Move rows up or down shortcuts...
if ( !readonly && e.keyCode == SWT.ARROW_DOWN && ctrl ) {
moveRows( +1 );
e.doit = false;
return;
}
if ( !readonly && e.keyCode == SWT.ARROW_UP && ctrl ) {
moveRows( -1 );
e.doit = false;
return;
}
// Select extra row down
if ( e.keyCode == SWT.ARROW_DOWN && shift ) {
activeTableRow++;
if ( activeTableRow >= maxrows ) {
activeTableRow = maxrows - 1;
}
selectRows( selectionStart, activeTableRow );
// activeTableItem = table.getItem(activeTableRow);
table.showItem( table.getItem( activeTableRow ) );
e.doit = false;
return;
}
// Select extra row up
if ( e.keyCode == SWT.ARROW_UP && shift ) {
activeTableRow--;
if ( activeTableRow < 0 ) {
activeTableRow = 0;
}
selectRows( activeTableRow, selectionStart );
// activeTableItem = table.getItem(activeTableRow);
table.showItem( table.getItem( activeTableRow ) );
e.doit = false;
return;
}
// Select all rows until end
if ( e.keyCode == SWT.HOME && shift ) {
activeTableRow = 0;
// Select all indeces from "from_selection" to "row"
selectRows( selectionStart, activeTableRow );
table.showItem( activeTableItem );
e.doit = false;
return;
}
// Select extra row up
if ( e.keyCode == SWT.END && shift ) {
activeTableRow = maxrows;
selectRows( selectionStart, activeTableRow );
table.showItem( activeTableItem );
e.doit = false;
return;
}
// Move cursor: set selection on the row in question.
if ( ( e.keyCode == SWT.ARROW_DOWN && !shift )
|| ( e.keyCode == SWT.ARROW_UP && !shift ) || ( e.keyCode == SWT.HOME && !shift )
|| ( e.keyCode == SWT.END && !shift ) ) {
switch ( e.keyCode ) {
case SWT.ARROW_DOWN:
activeTableRow++;
if ( activeTableRow >= maxrows ) {
if ( !readonly ) {
insertRowAfter();
} else {
activeTableRow = maxrows - 1;
}
}
break;
case SWT.ARROW_UP:
activeTableRow--;
if ( activeTableRow < 0 ) {
activeTableRow = 0;
}
break;
case SWT.HOME:
activeTableRow = 0;
break;
case SWT.END:
activeTableRow = maxrows - 1;
break;
default:
break;
}
setPosition( activeTableRow, activeTableColumn );
table.deselectAll();
table.select( activeTableRow );
table.showItem( table.getItem( activeTableRow ) );
e.doit = false;
return;
}
// CTRL-A --> Select All lines
if ( e.keyCode == 'a' && ctrl ) {
e.doit = false;
selectAll();
return;
}
// ESC --> unselect all
if ( e.keyCode == SWT.ESC ) {
e.doit = false;
unselectAll();
selectRows( activeTableRow, activeTableRow );
setFocus();
// table.setFocus();
return;
}
// CTRL-C --> Copy selected lines to clipboard
if ( e.keyCode == 'c' && ctrl ) {
e.doit = false;
clipSelected();
return;
}
// CTRL-K --> keep only selected lines
if ( !readonly && e.keyCode == 'k' && ctrl ) {
e.doit = false;
keepSelected();
return;
}
// CTRL-X --> Cut selected infomation...
if ( !readonly && e.keyCode == 'x' && ctrl ) {
e.doit = false;
cutSelected();
return;
}
// CTRL-V --> Paste selected infomation...
if ( !readonly && e.keyCode == 'v' && ctrl ) {
e.doit = false;
pasteSelected();
return;
}
// F3 --> optimal width including headers
if ( e.keyCode == SWT.F3 ) {
e.doit = false;
optWidth( true );
return;
}
// DEL --> delete selected lines
if ( !readonly && e.keyCode == SWT.DEL ) {
e.doit = false;
delSelected();
return;
}
// F4 --> optimal width excluding headers
if ( e.keyCode == SWT.F4 ) {
e.doit = false;
optWidth( false );
return;
}
// CTRL-Y --> redo action
if ( e.keyCode == 'y' && ctrl ) {
e.doit = false;
redoAction();
return;
}
// CTRL-Z --> undo action
if ( e.keyCode == 'z' && ctrl ) {
e.doit = false;
undoAction();
return;
}
// Return: edit the first field in the row.
if ( e.keyCode == SWT.CR || e.keyCode == SWT.ARROW_RIGHT || e.keyCode == SWT.TAB ) {
activeTableColumn = 1;
edit( activeTableRow, activeTableColumn );
e.doit = false;
return;
}
if ( activeTableColumn > 0 ) {
boolean textChar =
( e.character >= 'a' && e.character <= 'z' )
|| ( e.character >= 'A' && e.character <= 'Z' ) || ( e.character >= '0' && e.character <= '9' )
|| ( e.character == ' ' ) || ( e.character == '_' ) || ( e.character == ',' )
|| ( e.character == '.' ) || ( e.character == '+' ) || ( e.character == '-' )
|| ( e.character == '*' ) || ( e.character == '/' ) || ( e.character == ';' );
// setSelection(row, rownr, colnr);
// character a-z, A-Z, 0-9: start typing...
if ( e.character == SWT.CR || e.keyCode == SWT.F2 || textChar ) {
boolean selectText = true;
char extraChar = 0;
if ( textChar ) {
extraChar = e.character;
selectText = false;
}
e.doit = false;
edit( activeTableRow, activeTableColumn, selectText, extraChar );
}
if ( e.character == SWT.TAB ) {
// TAB
if ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) == 0 ) ) {
activeTableColumn++;
}
// Shift Tab
if ( e.keyCode == SWT.TAB && ( ( e.stateMask & SWT.SHIFT ) != 0 ) ) {
activeTableColumn--;
}
if ( activeTableColumn < 1 ) { // from SHIFT-TAB
activeTableColumn = maxcols - 1;
if ( activeTableRow > 0 ) {
activeTableRow--;
}
}
if ( activeTableColumn >= maxcols ) { // from TAB
activeTableColumn = 1;
activeTableRow++;
}
// Tab beyond last line: add a line to table!
if ( activeTableRow >= maxrows ) {
TableItem item = new TableItem( table, SWT.NONE, activeTableRow );
item.setText( 1, "" );
setRowNums();
}
// row = table.getItem(rownr);
e.doit = false;
edit( activeTableRow, activeTableColumn );
}
}
setFocus();
table.setFocus();
}
};
table.addKeyListener( lsKeyTable );
// Table listens to the mouse:
MouseAdapter lsMouseT = new MouseAdapter() {
@Override
public void mouseDown( MouseEvent event ) {
if ( activeTableItem != null
&& editor != null
&& editor.getEditor() != null
&& !editor.getEditor().isDisposed() ) {
if ( activeTableColumn > 0 ) {
switch ( columns[activeTableColumn - 1].getType() ) {
case ColumnInfo.COLUMN_TYPE_TEXT:
applyTextChange( activeTableItem, activeTableRow, activeTableColumn );
break;
case ColumnInfo.COLUMN_TYPE_CCOMBO:
applyComboChange( activeTableItem, activeTableRow, activeTableColumn );
break;
}
}
}
//if ( event.button == 1 ) {
boolean rightClick = event.button == 3;
if ( event.button == 1 || rightClick ) {
boolean shift = ( event.stateMask & SWT.SHIFT ) != 0;
boolean control = ( event.stateMask & SWT.MOD1 ) != 0;
if ( !shift && !control ) {
Rectangle clientArea = table.getClientArea();
Point pt = new Point( event.x, event.y );
int index = table.getTopIndex();
while ( index < table.getItemCount() ) {
boolean visible = false;
final TableItem item = table.getItem( index );
for ( int i = 0; i < table.getColumnCount(); i++ ) {
Rectangle rect = item.getBounds( i );
if ( rect.contains( pt ) ) {
activeTableItem = item;
activeTableColumn = i;
activeTableRow = index;
if ( !rightClick ) {
editSelected();
}
return;
} else {
if ( i == table.getColumnCount() - 1 && // last column
pt.x > rect.x + rect.width && // to the right
pt.y >= rect.y && pt.y <= rect.y + rect.height // same
// height
// as this
// visible
// item
) {
return; // don't do anything when clicking to the right of
// the grid.
}
}
if ( !visible && rect.intersects( clientArea ) ) {
visible = true;
}
}
if ( !visible ) {
return;
}
index++;
}
if ( rightClick ) {
return;
}
// OK, so they clicked in the table and we did not go into the
// invisible: below the last line!
// Position on last row, 1st column and add a new line...
setPosition( table.getItemCount() - 1, 1 );
insertRowAfter();
}
}
}
};
table.addMouseListener( lsMouseT );
// Add support for sorted columns!
//
final int nrcols = tablecolumn.length;
for ( int i = 0; i < nrcols; i++ ) {
final int colnr = i;
Listener lsSort = new Listener() {
@Override
public void handleEvent( Event e ) {
// Sorting means: clear undo information!
clearUndo();
sortTable( colnr );
}
};
tablecolumn[i].addListener( SWT.Selection, lsSort );
}
lsTraverse = new TraverseListener() {
@Override
public void keyTraversed( TraverseEvent e ) {
e.doit = false;
}
};
table.addTraverseListener( lsTraverse );
// cursor.addTraverseListener(lsTraverse);
// Clean up the clipboard
addDisposeListener( new DisposeListener() {
@Override
public void widgetDisposed( DisposeEvent e ) {
if ( clipboard != null ) {
clipboard.dispose();
clipboard = null;
}
if ( gridFont != null ) {
gridFont.dispose();
}
}
} );
// Drag & drop source!
// Drag & Drop for table-viewer
Transfer[] ttypes = new Transfer[]{ TextTransfer.getInstance() };
DragSource ddSource = new DragSource( table, DND.DROP_MOVE | DND.DROP_COPY );
ddSource.setTransfer( ttypes );
ddSource.addDragListener( new DragSourceListener() {
@Override
public void dragStart( DragSourceEvent event ) {
}
@Override
public void dragSetData( DragSourceEvent event ) {
event.data = "TableView" + Const.CR + getSelectedText();
}
@Override
public void dragFinished( DragSourceEvent event ) {
}
} );
table.layout();
table.pack();
optWidth( true );
layout();
pack();
}
protected String getTextWidgetValue( int colNr ) {
boolean b = columns[colNr - 1].isUsingVariables();
if ( b ) {
return ( (TextVar) text ).getText();
} else {
return ( (Text) text ).getText();
}
}
protected int getTextWidgetCaretPosition( int colNr ) {
boolean b = columns[colNr - 1].isUsingVariables();
if ( b ) {
return ( (TextVar) text ).getTextWidget().getCaretPosition();
} else {
return ( (Text) text ).getCaretPosition();
}
}
public void sortTable( int colnr ) {
if ( !sortable ) {
return;
}
if ( sortfield == colnr ) {
sortingDescending = ( !sortingDescending );
} else {
sortfield = colnr;
sortingDescending = false;
}
sortTable( sortfield, sortingDescending );
}
public void setSelection( int[] selectedItems ) {
table.select( selectedItems );
}
public void sortTable( int sortField, boolean sortingDescending ) {
boolean shouldRefresh = false;
if ( this.sortfieldLast == -1 && this.sortingDescendingLast == null ) {
// first time through, so update
shouldRefresh = true;
this.sortfieldLast = this.sortfield;
this.sortingDescendingLast = new Boolean( this.sortingDescending );
this.sortfield = sortField;
this.sortingDescending = sortingDescending;
}
if ( sortfieldLast != this.sortfield ) {
this.sortfieldLast = this.sortfield;
this.sortfield = sortField;
shouldRefresh = true;
}
if ( sortingDescendingLast != this.sortingDescending ) {
this.sortingDescendingLast = this.sortingDescending;
this.sortingDescending = sortingDescending;
shouldRefresh = true;
}
if ( !shouldRefresh && table.getItemCount() == lastRowCount ) {
return;
}
try {
// First, get all info and put it in a Vector of Rows...
TableItem[] items = table.getItems();
List<Object[]> v = new ArrayList<Object[]>();
// First create the row metadata for the grid
//
final RowMetaInterface rowMeta = new RowMeta();
// First values are the color name + value!
rowMeta.addValueMeta( new ValueMetaString( "colorname" ) );
rowMeta.addValueMeta( new ValueMetaInteger( "color" ) );
for ( int j = 0; j < table.getColumnCount(); j++ ) {
ColumnInfo colInfo;
if ( j > 0 ) {
colInfo = columns[j - 1];
} else {
colInfo = numberColumn;
}
ValueMetaInterface valueMeta = colInfo.getValueMeta();
if ( j == sortField ) {
valueMeta.setSortedDescending( sortingDescending );
}
rowMeta.addValueMeta( valueMeta );
}
final RowMetaInterface sourceRowMeta = rowMeta.cloneToType( ValueMetaInterface.TYPE_STRING );
final RowMetaInterface conversionRowMeta = rowMeta.clone();
// Set it all to string...
// Also set the storage value metadata: this will allow us to convert back
// and forth without a problem.
//
for ( int i = 0; i < sourceRowMeta.size(); i++ ) {
ValueMetaInterface sourceValueMeta = sourceRowMeta.getValueMeta( i );
sourceValueMeta.setStorageType( ValueMetaInterface.STORAGE_TYPE_NORMAL );
ValueMetaInterface conversionMetaData = conversionRowMeta.getValueMeta( i );
conversionMetaData.setStorageType( ValueMetaInterface.STORAGE_TYPE_NORMAL );
// Meaning: this string comes from an Integer/Number/Date/etc.
//
sourceRowMeta.getValueMeta( i ).setConversionMetadata( conversionMetaData );
}
// Now populate a list of data rows...
//
for ( int i = 0; i < items.length; i++ ) {
TableItem item = items[i];
Object[] r = new Object[table.getColumnCount() + 2];
// First values are the color name + value!
Color bg = item.getBackground();
if ( !bg.equals( defaultBackgroundColor ) ) {
String colorName = "bg " + bg.toString();
r[0] = colorName;
r[1] = new Long( ( bg.getRed() << 16 ) + ( bg.getGreen() << 8 ) + ( bg.getBlue() ) );
// Save it in the used colors map!
usedColors.put( colorName, bg );
}
for ( int j = 0; j < table.getColumnCount(); j++ ) {
String data = item.getText( j );
if ( GUIResource.getInstance().getColorBlue().equals( item.getForeground( j ) ) ) {
data = null;
}
ValueMetaInterface sourceValueMeta = sourceRowMeta.getValueMeta( j + 2 );
try {
r[j + 2] = sourceValueMeta.convertDataUsingConversionMetaData( data );
} catch ( Exception e ) {
if ( isShowingConversionErrorsInline() ) {
r[j + 2] = Const.getStackTracker( e );
} else {
throw e;
}
}
}
v.add( r );
}
final int[] sortIndex = new int[]{ sortField + 2 };
// Sort the vector!
Collections.sort( v, new Comparator<Object[]>() {
@Override
public int compare( Object[] r1, Object[] r2 ) {
try {
return conversionRowMeta.compare( r1, r2, sortIndex );
} catch ( KettleValueException e ) {
throw new RuntimeException( "Error comparing rows", e );
}
}
} );
// Clear the table
table.removeAll();
// Refill the table
for ( int i = 0; i < v.size(); i++ ) {
Object[] r = v.get( i );
TableItem item = new TableItem( table, SWT.NONE );
String colorName = (String) r[0];
Long colorValue = (Long) r[1];
if ( colorValue != null ) {
// Get it from the map
//
Color bg = usedColors.get( colorName );
if ( bg != null ) {
item.setBackground( bg );
}
}
for ( int j = 2; j < r.length; j++ ) {
String string = conversionRowMeta.getString( r, j );
if ( showingBlueNullValues && string == null ) {
string = "<null>";
item.setForeground( j - 2, GUIResource.getInstance().getColorBlue() );
} else {
item.setForeground( j - 2, GUIResource.getInstance().getColorBlack() );
}
if ( string != null ) {
item.setText( j - 2, string );
}
}
}
table.setSortColumn( table.getColumn( sortfield ) );
table.setSortDirection( sortingDescending ? SWT.DOWN : SWT.UP );
lastRowCount = table.getItemCount();
} catch ( Exception e ) {
new ErrorDialog( this.getShell(), BaseMessages.getString( PKG, "TableView.ErrorDialog.title" ), BaseMessages
.getString( PKG, "TableView.ErrorDialog.description" ), e );
}
}
private void selectRows( int from, int to ) {
table.deselectAll();
if ( from == to ) {
table.select( from );
} else {
if ( from > to ) {
table.select( to, from );
} else {
table.select( from, to );
}
}
}
private void applyTextChange( TableItem row, int rownr, int colnr ) {
String textData = getTextWidgetValue( colnr );
row.setText( colnr, textData );
text.dispose();
table.setFocus();
String[] afterEdit = getItemText( row );
checkChanged( new String[][]{ beforeEdit }, new String[][]{ afterEdit }, new int[]{ rownr } );
selectionStart = -1;
fireContentChangedListener( rownr, colnr, textData );
}
/**
* Inform the content listener that content changed.
*
* @param rownr
* @param colnr
* @param textData
*/
private void fireContentChangedListener( int rownr, int colnr, String textData ) {
if ( lsContent != null ) {
Event event = new Event();
event.data = textData;
event.widget = table;
event.x = rownr;
event.y = colnr;
lsContent.modifyText( new ModifyEvent( event ) );
}
}
private void applyComboChange( TableItem row, int rownr, int colnr ) {
String textData = combo.getText();
row.setText( colnr, textData );
combo.dispose();
String[] afterEdit = getItemText( row );
checkChanged( new String[][]{ beforeEdit }, new String[][]{ afterEdit }, new int[]{ rownr } );
selectionStart = -1;
fireContentChangedListener( rownr, colnr, textData );
}
public void addModifyListener( ModifyListener ls ) {
lsMod = ls;
}
public void setColumnInfo( int idx, ColumnInfo col ) {
columns[idx] = col;
}
public void setColumnText( int idx, String text ) {
TableColumn col = table.getColumn( idx );
col.setText( text );
}
public void setColumnToolTip( int idx, String text ) {
columns[idx].setToolTip( text );
}
private void editSelected() {
if ( activeTableItem == null ) {
return;
}
if ( activeTableColumn > 0 ) {
edit( activeTableRow, activeTableColumn );
} else {
selectRows( activeTableRow, activeTableRow );
}
}
private void checkChanged( String[][] before, String[][] after, int[] index ) {
// Did we change anything: if so, add undo information
if ( fieldChanged ) {
TransAction ta = new TransAction();
ta.setChanged( before, after, index );
addUndo( ta );
}
}
private void setModified() {
if ( lsMod != null ) {
Event e = new Event();
e.widget = this;
lsMod.modifyText( new ModifyEvent( e ) );
}
}
private void insertRowBefore() {
if ( readonly ) {
return;
}
TableItem row = activeTableItem;
if ( row == null ) {
return;
}
int rownr = table.indexOf( row );
TableItem item = new TableItem( table, SWT.NONE, rownr );
item.setText( 1, "" );
// Add undo information
TransAction ta = new TransAction();
String[] str = getItemText( item );
ta.setNew( new String[][]{ str }, new int[]{ rownr } );
addUndo( ta );
setRowNums();
edit( rownr, 1 );
}
private void insertRowAfter() {
if ( readonly ) {
return;
}
TableItem row = activeTableItem;
if ( row == null ) {
return;
}
int rownr = table.indexOf( row );
TableItem item = new TableItem( table, SWT.NONE, rownr + 1 );
item.setText( 1, "" );
// Add undo information
TransAction ta = new TransAction();
String[] str = getItemText( item );
ta.setNew( new String[][]{ str }, new int[]{ rownr + 1 } );
addUndo( ta );
setRowNums();
edit( rownr + 1, 1 );
}
public void clearAll() {
clearAll( false );
}
public void clearAll( boolean ask ) {
int id = SWT.YES;
if ( ask ) {
MessageBox mb = new MessageBox( parent.getShell(), SWT.YES | SWT.NO | SWT.ICON_QUESTION );
mb.setMessage( BaseMessages.getString( PKG, "TableView.MessageBox.ClearTable.message" ) );
mb.setText( BaseMessages.getString( PKG, "TableView.MessageBox.ClearTable.title" ) );
id = mb.open();
}
if ( id == SWT.YES ) {
table.removeAll();
new TableItem( table, SWT.NONE );
if ( !readonly ) {
edit( 0, 1 );
}
this.setModified(); // timh
}
}
private void moveRows( int offset ) {
if ( ( offset != 1 ) && ( offset != -1 ) ) {
return;
}
int[] selectionIndicies = table.getSelectionIndices();
int selectedIndex = table.getSelectionIndex();
// selectionIndicies is not guaranteed to be in any order so must sort
// before using
Arrays.sort( selectionIndicies );
if ( offset == 1 ) {
if ( selectionIndicies[selectionIndicies.length - 1] >= table.getItemCount() - 1 ) {
// If the last row in the table is selected then don't move any rows
// down
return;
}
selectionIndicies = moveRowsDown( selectionIndicies );
} else {
if ( selectionIndicies[0] == 0 ) {
// If the first row in the table is selected then don't move any rows up
return;
}
selectionIndicies = moveRowsUp( selectionIndicies );
}
activeTableRow = selectedIndex + offset;
table.setSelection( activeTableRow );
table.setSelection( selectionIndicies );
activeTableItem = table.getItem( activeTableRow );
}
private int[] moveRowsDown( int[] selectionIndicies ) {
// Move the selected rows down starting with the lowest row
for ( int i = selectionIndicies.length - 1; i >= 0; i-- ) {
int row = selectionIndicies[i];
int newRow = row + 1;
moveRow( row, newRow );
TransAction ta = new TransAction();
ta.setItemMove( new int[]{ row }, new int[]{ newRow } );
addUndo( ta );
selectionIndicies[i] = newRow;
}
return selectionIndicies;
}
private int[] moveRowsUp( int[] selectionIndicies ) {
// Move the selected rows up starting with the highest row
for ( int i = 0; i < selectionIndicies.length; i++ ) {
int row = selectionIndicies[i];
int newRow = row - 1;
moveRow( row, newRow );
TransAction ta = new TransAction();
ta.setItemMove( new int[]{ row }, new int[]{ newRow } );
addUndo( ta );
selectionIndicies[i] = newRow;
}
return selectionIndicies;
}
private void moveRow( int from, int to ) {
TableItem rowfrom = table.getItem( from );
TableItem rowto = table.getItem( to );
// Grab the strings on that line...
String[] strfrom = getItemText( rowfrom );
String[] strto = getItemText( rowto );
// Copy the content
for ( int i = 0; i < strfrom.length; i++ ) {
rowfrom.setText( i + 1, strto[i] );
rowto.setText( i + 1, strfrom[i] );
}
setModified();
}
private void copyToAll() {
TableItem row = activeTableItem;
if ( row == null || row.isDisposed() ) {
return;
}
int colnr = activeTableColumn;
if ( colnr == 0 ) {
return;
}
String str = row.getText( colnr );
// Get undo information: all columns
int size = table.getItemCount();
String[][] before = new String[size][];
String[][] after = new String[size][];
int[] index = new int[size];
for ( int i = 0; i < table.getItemCount(); i++ ) {
TableItem item = table.getItem( i );
index[i] = i;
before[i] = getItemText( item );
item.setText( colnr, str );
after[i] = getItemText( item );
}
// Add the undo information!
TransAction ta = new TransAction();
ta.setChanged( before, after, index );
addUndo( ta );
}
private void selectAll() {
table.selectAll();
}
private void unselectAll() {
table.deselectAll();
}
private void clipSelected() {
if ( clipboard != null ) {
clipboard.dispose();
clipboard = null;
}
clipboard = new Clipboard( getDisplay() );
TextTransfer tran = TextTransfer.getInstance();
String clip = getSelectedText();
if ( clip == null ) {
return;
}
clipboard.setContents( new String[]{ clip }, new Transfer[]{ tran } );
}
private String getSelectedText() {
String selection = "";
for ( int c = 1; c < table.getColumnCount(); c++ ) {
TableColumn tc = table.getColumn( c );
if ( c > 1 ) {
selection += CLIPBOARD_DELIMITER;
}
selection += tc.getText();
}
selection += Const.CR;
TableItem[] items = table.getSelection();
if ( items.length == 0 ) {
return null;
}
for ( int r = 0; r < items.length; r++ ) {
TableItem ti = items[r];
for ( int c = 1; c < table.getColumnCount(); c++ ) {
if ( c > 1 ) {
selection += CLIPBOARD_DELIMITER;
}
selection += ti.getText( c );
}
selection += Const.CR;
}
return selection;
}
/*
* Example: ----------------------------------------------------------------- Field in stream;Dimension field
* TIME;TIME DATA_TYPE;DATA_TYPE MAP_TYPE;MAP_TYPE RESOLUTION;RESOLUTION START_TIME;START_TIME
* -----------------------------------------------------------------
*
* !! Paste at the end of the table! --> Create new table item for every line
*/
private int getCurrentRownr() {
if ( table.getItemCount() <= 1 ) {
return 0;
}
TableItem row = activeTableItem;
if ( row == null ) {
return 0;
}
int rownr = table.indexOf( row );
if ( rownr < 0 ) {
rownr = 0;
}
return rownr;
}
private void pasteSelected() {
int rownr = getCurrentRownr();
if ( clipboard != null ) {
clipboard.dispose();
clipboard = null;
}
clipboard = new Clipboard( getDisplay() );
TextTransfer tran = TextTransfer.getInstance();
String text = (String) clipboard.getContents( tran );
if ( text != null ) {
String[] lines = text.split( Const.CR );
if ( lines.length > 1 ) {
// ALlocate complete paste grid!
String[][] grid = new String[lines.length - 1][];
int[] idx = new int[lines.length - 1];
for ( int i = 1; i < lines.length; i++ ) {
grid[i - 1] = lines[i].split( "\t" );
idx[i - 1] = rownr + i;
addItem( idx[i - 1], grid[i - 1] );
}
TransAction ta = new TransAction();
ta.setNew( grid, idx );
addUndo( ta );
}
if ( rownr == 0 && table.getItemCount() > rownr + 1 ) {
// Empty row at rownr?
// Remove it!
if ( isEmpty( rownr, -1 ) ) {
table.remove( rownr );
}
}
setRowNums();
unEdit();
setModified();
}
}
private void addItem( int pos, String[] str ) {
TableItem item = new TableItem( table, SWT.NONE, pos );
for ( int i = 0; i < str.length; i++ ) {
item.setText( i + 1, str[i] );
}
setModified();
}
private void cutSelected() {
clipSelected(); // copy selected lines to clipboard
delSelected();
}
private void delSelected() {
if ( nrNonEmpty() == 0 ) {
return;
}
// Which items do we delete?
int[] items = table.getSelectionIndices();
if ( items.length == 0 ) {
return;
}
// Save undo information
String[][] before = new String[items.length][];
for ( int i = 0; i < items.length; i++ ) {
TableItem ti = table.getItem( items[i] );
before[i] = getItemText( ti );
}
TransAction ta = new TransAction();
ta.setDelete( before, items );
addUndo( ta );
TableItem row = activeTableItem;
if ( row == null ) {
return;
}
int rowbefore = table.indexOf( row );
// Delete selected items.
table.remove( items );
if ( table.getItemCount() == 0 ) {
TableItem item = new TableItem( table, SWT.NONE );
// Save undo infomation!
String[] stritem = getItemText( item );
ta = new TransAction();
ta.setNew( new String[][]{ stritem }, new int[]{ 0 } );
addUndo( ta );
}
// If the last row is gone, put the selection back on last-1!
if ( rowbefore >= table.getItemCount() ) {
rowbefore = table.getItemCount() - 1;
}
// After the delete, we put the cursor on the same row as before (if we can)
if ( rowbefore < table.getItemCount() && table.getItemCount() > 0 ) {
setPosition( rowbefore, 1 );
table.setSelection( rowbefore );
activeTableRow = rowbefore;
}
setRowNums();
setModified();
}
private void keepSelected() {
// Which items are selected?
int[] sels = table.getSelectionIndices();
int size = table.getItemCount();
// Which items do we delete?
int[] items = new int[size - sels.length];
if ( items.length == 0 ) {
return; // everything is selected: keep everything, do nothing.
}
// Set the item-indices to delete...
int nr = 0;
for ( int i = 0; i < table.getItemCount(); i++ ) {
boolean selected = false;
for ( int j = 0; j < sels.length && !selected; j++ ) {
if ( sels[j] == i ) {
selected = true;
}
}
if ( !selected ) {
items[nr] = i;
nr++;
}
}
// Save undo information
String[][] before = new String[items.length][];
for ( int i = 0; i < items.length; i++ ) {
TableItem ti = table.getItem( items[i] );
before[i] = getItemText( ti );
}
TransAction ta = new TransAction();
ta.setDelete( before, items );
addUndo( ta );
// Delete selected items.
table.remove( items );
if ( table.getItemCount() == 0 ) {
TableItem item = new TableItem( table, SWT.NONE );
// Save undo infomation!
String[] stritem = getItemText( item );
ta = new TransAction();
ta.setNew( new String[][]{ stritem }, new int[]{ 0 } );
addUndo( ta );
}
/*
* try { table.getRow(); } catch(Exception e) // Index is too high: lower to last available value {
* setPosition(table.getItemCount()-1, 1); }
*/
setRowNums();
setModified();
}
private void setPosition( int rownr, int colnr ) {
activeTableColumn = colnr;
activeTableRow = rownr;
if ( rownr >= 0 ) {
activeTableItem = table.getItem( rownr );
}
}
public void edit( int rownr, int colnr ) {
setPosition( rownr, colnr );
edit( rownr, colnr, true, (char) 0 );
}
private void edit( int rownr, int colnr, boolean selectText, char extra ) {
selectionStart = -1;
TableItem row = table.getItem( rownr );
Control oldEditor = editor.getEditor();
if ( oldEditor != null && !oldEditor.isDisposed() ) {
try {
oldEditor.dispose();
} catch ( SWTException swte ) {
// Eat "Widget Is Disposed Exception" : did you ever!!!
}
}
activeTableItem = table.getItem( activeTableRow ); // just to make sure, clean
// up afterwards.
table.showItem( row );
table.setSelection( new TableItem[]{ row } );
if ( columns.length == 0 ) {
return;
}
switch ( columns[colnr - 1].getType() ) {
case ColumnInfo.COLUMN_TYPE_TEXT:
isTextButton = false;
editText( row, rownr, colnr, selectText, extra, columns[colnr - 1] );
break;
case ColumnInfo.COLUMN_TYPE_CCOMBO:
case ColumnInfo.COLUMN_TYPE_FORMAT:
editCombo( row, rownr, colnr );
break;
case ColumnInfo.COLUMN_TYPE_BUTTON:
editButton( row, rownr, colnr );
break;
case ColumnInfo.COLUMN_TYPE_TEXT_BUTTON:
if ( columns[colnr - 1].shouldRenderTextVarButton() ) {
isTextButton = true;
} else {
isTextButton = false;
}
editText( row, rownr, colnr, selectText, extra, columns[colnr - 1] );
break;
default:
break;
}
}
private String[] getItemText( TableItem row ) {
if ( row.isDisposed() ) {
return null;
}
String[] retval = new String[table.getColumnCount() - 1];
for ( int i = 0; i < retval.length; i++ ) {
retval[i] = row.getText( i + 1 );
}
return retval;
}
private void editText( TableItem row, final int rownr, final int colnr, boolean selectText, char extra,
ColumnInfo columnInfo ) {
beforeEdit = getItemText( row );
fieldChanged = false;
ColumnInfo colinfo = columns[colnr - 1];
if ( colinfo.isReadOnly() ) {
return;
}
if ( colinfo.getDisabledListener() != null ) {
boolean disabled = colinfo.getDisabledListener().isFieldDisabled( rownr );
if ( disabled ) {
return;
}
}
if ( text != null && !text.isDisposed() ) {
text.dispose();
}
if ( colinfo.getSelectionAdapter() != null ) {
Event e = new Event();
e.widget = this;
e.x = colnr;
e.y = rownr;
columns[colnr - 1].getSelectionAdapter().widgetSelected( new SelectionEvent( e ) );
return;
}
String content = row.getText( colnr ) + ( extra != 0 ? "" + extra : "" );
String tooltip = columns[colnr - 1].getToolTip();
final boolean useVariables = columns[colnr - 1].isUsingVariables();
final boolean passwordField = columns[colnr - 1].isPasswordField();
final ModifyListener modifyListener = new ModifyListener() {
@Override
public void modifyText( ModifyEvent me ) {
setColumnWidthBasedOnTextField( colnr, useVariables );
}
};
if ( useVariables ) {
GetCaretPositionInterface getCaretPositionInterface = new GetCaretPositionInterface() {
@Override
public int getCaretPosition() {
return ( (TextVar) text ).getTextWidget().getCaretPosition();
}
};
// The text widget will be disposed when we get here
// So we need to write to the table row
//
InsertTextInterface insertTextInterface = new InsertTextInterface() {
@Override
public void insertText( String string, int position ) {
StringBuilder buffer = new StringBuilder( table.getItem( rownr ).getText( colnr ) );
buffer.insert( position, string );
table.getItem( rownr ).setText( colnr, buffer.toString() );
int newPosition = position + string.length();
edit( rownr, colnr );
( (TextVar) text ).setSelection( newPosition );
( (TextVar) text ).showSelection();
setColumnWidthBasedOnTextField( colnr, useVariables );
}
};
final TextVar textWidget;
if ( passwordField ) {
textWidget = new PasswordTextVar( variables, table, SWT.NONE, getCaretPositionInterface, insertTextInterface );
} else if ( isTextButton ) {
textWidget =
new TextVarButton( variables, table, SWT.NONE, getCaretPositionInterface, insertTextInterface,
columnInfo.getTextVarButtonSelectionListener() );
} else {
textWidget = new TextVar( variables, table, SWT.NONE, getCaretPositionInterface, insertTextInterface );
}
text = textWidget;
textWidget.setText( content );
if ( lsMod != null ) {
textWidget.addModifyListener( lsMod );
}
textWidget.addModifyListener( lsUndo );
textWidget.setSelection( content.length() );
// last_carret_position = content.length();
textWidget.addKeyListener( lsKeyText );
// Make the column larger so we can still see the string we're entering...
textWidget.addModifyListener( modifyListener );
if ( selectText ) {
textWidget.selectAll();
}
if ( tooltip != null ) {
textWidget.setToolTipText( tooltip );
} else {
textWidget.setToolTipText( "" );
}
textWidget.addTraverseListener( lsTraverse );
textWidget.addFocusListener( lsFocusText );
} else {
Text textWidget = new Text( table, SWT.NONE );
text = textWidget;
textWidget.setText( content );
if ( lsMod != null ) {
textWidget.addModifyListener( lsMod );
}
textWidget.addModifyListener( lsUndo );
textWidget.setSelection( content.length() );
// last_carret_position = content.length();
textWidget.addKeyListener( lsKeyText );
// Make the column larger so we can still see the string we're entering...
textWidget.addModifyListener( modifyListener );
if ( selectText ) {
textWidget.selectAll();
}
if ( tooltip != null ) {
textWidget.setToolTipText( tooltip );
} else {
textWidget.setToolTipText( "" );
}
textWidget.addTraverseListener( lsTraverse );
textWidget.addFocusListener( lsFocusText );
}
props.setLook( text, Props.WIDGET_STYLE_TABLE );
int width = tablecolumn[colnr].getWidth();
int height = 30;
editor.horizontalAlignment = SWT.LEFT;
editor.grabHorizontal = true;
// Open the text editor in the correct column of the selected row.
editor.setEditor( text, row, colnr );
text.setFocus();
text.setSize( width, height );
editor.layout();
}
private void setColumnWidthBasedOnTextField( final int colnr, final boolean useVariables ) {
String str = getTextWidgetValue( colnr );
int strmax = TableView.dummyGC.textExtent( str, SWT.DRAW_TAB | SWT.DRAW_DELIMITER ).x + 20;
int colmax = tablecolumn[colnr].getWidth();
if ( strmax > colmax ) {
if ( Const.isOSX() || Const.isLinux() ) {
strmax *= 1.4;
}
tablecolumn[colnr].setWidth( strmax + 30 );
// On linux, this causes the text to select everything...
// This is because the focus is lost and re-gained. Nothing we can do
// about it now.
if ( useVariables ) {
TextVar widget = (TextVar) text;
int idx = widget.getTextWidget().getCaretPosition();
widget.selectAll();
widget.showSelection();
widget.setSelection( 0 );
widget.showSelection();
widget.setSelection( idx );
} else {
Text widget = (Text) text;
int idx = widget.getCaretPosition();
widget.selectAll();
widget.showSelection();
widget.setSelection( 0 );
widget.showSelection();
widget.setSelection( idx );
}
}
}
private String[] getComboValues( TableItem row, ColumnInfo colinfo ) {
if ( colinfo.getType() == ColumnInfo.COLUMN_TYPE_FORMAT ) {
int type = ValueMetaFactory.getIdForValueMeta( row.getText( colinfo.getFieldTypeColumn() ) );
switch ( type ) {
case ValueMetaInterface.TYPE_DATE:
return Const.getDateFormats();
case ValueMetaInterface.TYPE_INTEGER:
case ValueMetaInterface.TYPE_BIGNUMBER:
case ValueMetaInterface.TYPE_NUMBER:
return Const.getNumberFormats();
case ValueMetaInterface.TYPE_STRING:
return Const.getConversionFormats();
default:
return new String[0];
}
}
return colinfo.getComboValues();
}
private void editCombo( TableItem row, int rownr, int colnr ) {
beforeEdit = getItemText( row );
fieldChanged = false;
ColumnInfo colinfo = columns[colnr - 1];
if ( colinfo.isReadOnly() && colinfo.getSelectionAdapter() != null ) {
return;
}
if ( colinfo.getDisabledListener() != null ) {
boolean disabled = colinfo.getDisabledListener().isFieldDisabled( rownr );
if ( disabled ) {
return;
}
}
combo = new CCombo( table, colinfo.isReadOnly() ? SWT.READ_ONLY : SWT.NONE );
props.setLook( combo, Props.WIDGET_STYLE_TABLE );
combo.addTraverseListener( lsTraverse );
combo.addModifyListener( lsModCombo );
combo.addFocusListener( lsFocusCombo );
String[] opt = getComboValues( row, colinfo );
if ( colinfo.getComboValuesSelectionListener() != null ) {
opt = colinfo.getComboValuesSelectionListener().getComboValues( row, rownr, colnr );
}
combo.setItems( opt );
combo.setVisibleItemCount( opt.length );
combo.setText( row.getText( colnr ) );
if ( lsMod != null ) {
combo.addModifyListener( lsMod );
}
combo.addModifyListener( lsUndo );
combo.setToolTipText( colinfo.getToolTip() == null ? "" : colinfo.getToolTip() );
combo.setVisible( true );
combo.addKeyListener( lsKeyCombo );
if ( colinfo.getSelectionAdapter() != null ) {
combo.addSelectionListener( columns[colnr - 1].getSelectionAdapter() );
}
editor.horizontalAlignment = SWT.LEFT;
editor.layout();
// Open the text editor in the correct column of the selected row.
editor.setEditor( combo, row, colnr );
combo.setFocus();
combo.layout();
}
private void editButton( TableItem row, int rownr, int colnr ) {
beforeEdit = getItemText( row );
fieldChanged = false;
ColumnInfo colinfo = columns[colnr - 1];
if ( colinfo.isReadOnly() ) {
return;
}
if ( colinfo.getDisabledListener() != null ) {
boolean disabled = colinfo.getDisabledListener().isFieldDisabled( rownr );
if ( disabled ) {
return;
}
}
button = new Button( table, SWT.PUSH );
props.setLook( button, Props.WIDGET_STYLE_TABLE );
String buttonText = columns[colnr - 1].getButtonText();
if ( buttonText != null ) {
button.setText( buttonText );
}
button.setImage( GUIResource.getInstance().getImage( "ui/images/edittext.svg" ) );
SelectionListener selAdpt = colinfo.getSelectionAdapter();
if ( selAdpt != null ) {
button.addSelectionListener( selAdpt );
}
buttonRownr = rownr;
buttonColnr = colnr;
// button.addTraverseListener(lsTraverse);
buttonContent = row.getText( colnr );
String tooltip = columns[colnr - 1].getToolTip();
if ( tooltip != null ) {
button.setToolTipText( tooltip );
} else {
button.setToolTipText( "" );
}
button.addTraverseListener( lsTraverse ); // hop to next field
button.addTraverseListener( new TraverseListener() {
@Override
public void keyTraversed( TraverseEvent arg0 ) {
closeActiveButton();
}
} );
editor.horizontalAlignment = SWT.LEFT;
editor.verticalAlignment = SWT.TOP;
editor.grabHorizontal = false;
editor.grabVertical = false;
Point size = button.computeSize( SWT.DEFAULT, SWT.DEFAULT );
editor.minimumWidth = size.x;
editor.minimumHeight = size.y - 2;
// setRowNums();
editor.layout();
// Open the text editor in the correct column of the selected row.
editor.setEditor( button );
button.setFocus();
// if the button loses focus, destroy it...
/*
* button.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent e) { button.dispose(); } } );
*/
}
public void setRowNums() {
for ( int i = 0; i < table.getItemCount(); i++ ) {
TableItem item = table.getItem( i );
if ( item != null ) {
String num = "" + ( i + 1 );
// for(int j=num.length();j<3;j++) num="0"+num;
if ( !item.getText( 0 ).equals( num ) ) {
item.setText( 0, num );
}
}
}
}
public void optWidth( boolean header ) {
optWidth( header, 0 );
}
public void optWidth( boolean header, int nrLines ) {
for ( int c = 0; c < table.getColumnCount(); c++ ) {
TableColumn tc = table.getColumn( c );
int max = 0;
if ( header ) {
max = TableView.dummyGC.textExtent( tc.getText(), SWT.DRAW_TAB | SWT.DRAW_DELIMITER ).x;
// Check if the column has a sorted mark set. In that case, we need the
// header to be a bit wider...
//
if ( c == sortfield && sortable ) {
max += 15;
}
}
Set<String> columnStrings = new HashSet<String>();
boolean haveToGetTexts = false;
if ( c > 0 ) {
final ColumnInfo column = columns[c - 1];
if ( column != null ) {
switch ( column.getType() ) {
case ColumnInfo.COLUMN_TYPE_TEXT:
haveToGetTexts = true;
break;
case ColumnInfo.COLUMN_TYPE_CCOMBO:
case ColumnInfo.COLUMN_TYPE_FORMAT:
haveToGetTexts = true;
if ( column.getComboValues() != null ) {
for ( String comboValue : columns[c - 1].getComboValues() ) {
columnStrings.add( comboValue );
}
}
break;
case ColumnInfo.COLUMN_TYPE_BUTTON:
columnStrings.add( column.getButtonText() );
break;
default:
break;
}
}
} else {
haveToGetTexts = true;
}
if ( haveToGetTexts ) {
for ( int r = 0; r < table.getItemCount() && ( r < nrLines || nrLines <= 0 ); r++ ) {
TableItem ti = table.getItem( r );
if ( ti != null ) {
columnStrings.add( ti.getText( c ) );
}
}
}
for ( String str : columnStrings ) {
int len = TableView.dummyGC.textExtent( str == null ? "" : str, SWT.DRAW_TAB | SWT.DRAW_DELIMITER ).x;
if ( len > max ) {
max = len;
}
}
try {
int extra = 15;
if ( Const.isWindows() || Const.isLinux() ) {
extra += 15;
}
if ( tc.getWidth() != max + extra ) {
if ( c > 0 ) {
if ( columns[c - 1].getWidth() == -1 ) {
tc.setWidth( max + extra );
} else {
tc.setWidth( columns[c - 1].getWidth() );
}
}
}
} catch ( Exception e ) {
// Ignore errors
}
}
if ( table.isListening( SWT.Resize ) ) {
Event resizeEvent = new Event();
resizeEvent.widget = table;
resizeEvent.type = SWT.Resize;
resizeEvent.display = getDisplay();
resizeEvent.setBounds( table.getBounds() );
table.notifyListeners( SWT.Resize, resizeEvent );
}
unEdit();
}
/*
* Remove empty rows in the table...
*/
public void removeEmptyRows() {
removeEmptyRows( -1 );
}
private boolean isEmpty( int rownr, int colnr ) {
boolean empty = false;
TableItem item = table.getItem( rownr );
if ( item != null ) {
if ( colnr >= 0 ) {
String str = item.getText( colnr );
if ( str == null || str.length() == 0 ) {
empty = true;
}
} else {
empty = true;
for ( int j = 1; j < table.getColumnCount(); j++ ) {
String str = item.getText( j );
if ( str != null && str.length() > 0 ) {
empty = false;
}
}
}
}
return empty;
}
public void removeEmptyRows( int column ) {
// Remove "empty" table items, where item.getText(1) is empty, length==0
for ( int i = table.getItemCount() - 1; i >= 0; i-- ) {
if ( isEmpty( i, column ) ) {
table.remove( i );
}
}
if ( table.getItemCount() == 0 ) { // At least one empty row!
new TableItem( table, SWT.NONE );
}
}
private List<Integer> nonEmptyIndexes;
/**
* Count non-empty rows in the table... IMPORTANT: always call this method before calling getNonEmpty(int selnr): for
* performance reasons we cache the row indexes.
*
* @return the number of rows/table-items that are not empty
*/
public int nrNonEmpty() {
nonEmptyIndexes = new ArrayList<Integer>();
// Count only non-empty rows
for ( int i = 0; i < table.getItemCount(); i++ ) {
if ( !isEmpty( i, -1 ) ) {
nonEmptyIndexes.add( i );
}
}
return nonEmptyIndexes.size();
}
/**
* Return the row/table-item on the specified index. IMPORTANT: the indexes of the non-empty rows are populated with a
* call to nrNonEmpty(). Make sure to call that first.
*
* @param index the index of the non-empty row/table-item
* @return the requested non-empty row/table-item
*/
public TableItem getNonEmpty( int index ) {
int nonEmptyIndex = nonEmptyIndexes.get( index );
return table.getItem( nonEmptyIndex );
}
public int indexOfString( String str, int column ) {
int nrNonEmptyFields = nrNonEmpty();
for ( int i = 0; i < nrNonEmptyFields; i++ ) {
String cmp = getNonEmpty( i ).getText( column );
if ( str.equalsIgnoreCase( cmp ) ) {
return i;
}
}
return -1;
}
@Override
public ScrollBar getHorizontalBar() {
return table.getHorizontalBar();
}
@Override
public ScrollBar getVerticalBar() {
return table.getVerticalBar();
}
private void addUndo( TransAction ta ) {
while ( undo.size() > undoPosition + 1 && undo.size() > 0 ) {
int last = undo.size() - 1;
undo.remove( last );
}
undo.add( ta );
undoPosition++;
while ( undo.size() > props.getMaxUndo() ) {
undo.remove( 0 );
undoPosition--;
}
setUndoMenu();
}
private void undoAction() {
TransAction ta = previousUndo();
if ( ta == null ) {
return;
}
// Get the current cursor position
int rownr = getCurrentRownr();
setUndoMenu(); // something changed: change the menu
switch ( ta.getType() ) {
//
// NEW
//
// We created a table item: undo this...
case TransAction.TYPE_ACTION_NEW_TABLEITEM:
int[] idx = ta.getCurrentIndex();
table.remove( idx );
for ( int i = 0; i < idx.length; i++ ) {
if ( idx[i] < rownr ) {
rownr--; // shift with the rest.
}
}
// See if the table is empty, if so : undo again!!
if ( table.getItemCount() == 0 ) {
undoAction();
}
setRowNums();
break;
//
// DELETE
//
// un-Delete the rows at correct location: re-insert
case TransAction.TYPE_ACTION_DELETE_TABLEITEM:
idx = ta.getCurrentIndex();
String[][] str = (String[][]) ta.getCurrent();
for ( int i = 0; i < idx.length; i++ ) {
addItem( idx[i], str[i] );
if ( idx[i] <= rownr ) {
rownr++;
}
}
setRowNums();
break;
//
// CHANGE
//
// Change the item back to the original row-value.
case TransAction.TYPE_ACTION_CHANGE_TABLEITEM:
idx = ta.getCurrentIndex();
String[][] prev = (String[][]) ta.getPrevious();
for ( int x = 0; x < idx.length; x++ ) {
TableItem item = table.getItem( idx[x] );
for ( int i = 0; i < prev[x].length; i++ ) {
item.setText( i + 1, prev[x][i] );
}
}
break;
//
// POSITION
//
// The position of a row has changed...
case TransAction.TYPE_ACTION_POSITION_TABLEITEM:
int[] curr = ta.getCurrentIndex();
int[] prevIdx = ta.getPreviousIndex();
for ( int i = 0; i < curr.length; i++ ) {
moveRow( prevIdx[i], curr[i] );
}
setRowNums();
break;
default:
break;
}
if ( rownr >= table.getItemCount() ) {
rownr = table.getItemCount() - 1;
}
if ( rownr < 0 ) {
rownr = 0;
}
// cursor.setSelection(rownr, 0);
selectRows( rownr, rownr );
}
private void redoAction() {
TransAction ta = nextUndo();
if ( ta == null ) {
return;
}
// Get the current cursor position
int rownr = getCurrentRownr();
setUndoMenu(); // something changed: change the menu
switch ( ta.getType() ) {
//
// NEW
//
case TransAction.TYPE_ACTION_NEW_TABLEITEM:
int[] idx = ta.getCurrentIndex();
String[][] str = (String[][]) ta.getCurrent();
for ( int i = 0; i < idx.length; i++ ) {
addItem( idx[i], str[i] );
if ( idx[i] <= rownr ) {
rownr++; // Shift cursor position with the new items...
}
}
setRowNums();
break;
//
// DELETE
//
case TransAction.TYPE_ACTION_DELETE_TABLEITEM:
idx = ta.getCurrentIndex();
table.remove( idx );
for ( int i = 0; i < idx.length; i++ ) {
if ( idx[i] < rownr ) {
rownr--; // shift with the rest.
}
}
// See if the table is empty, if so : undo again!!
if ( table.getItemCount() == 0 ) {
undoAction();
}
setRowNums();
break;
//
// CHANGE
//
case TransAction.TYPE_ACTION_CHANGE_TABLEITEM:
idx = ta.getCurrentIndex();
String[][] curr = (String[][]) ta.getCurrent();
for ( int x = 0; x < idx.length; x++ ) {
TableItem item = table.getItem( idx[x] );
for ( int i = 0; i < curr[x].length; i++ ) {
item.setText( i + 1, curr[x][i] );
}
}
break;
//
// CHANGE POSITION
//
case TransAction.TYPE_ACTION_POSITION_TABLEITEM:
int[] currIdx = ta.getCurrentIndex();
int[] prev = ta.getPreviousIndex();
for ( int i = 0; i < currIdx.length; i++ ) {
moveRow( currIdx[i], prev[i] );
}
setRowNums();
break;
default:
break;
}
if ( rownr >= table.getItemCount() ) {
rownr = table.getItemCount() - 1;
}
if ( rownr < 0 ) {
rownr = 0;
}
// cursor.setSelection(rownr, 0);
selectRows( rownr, rownr );
}
private void setUndoMenu() {
TransAction prev = viewPreviousUndo();
TransAction next = viewNextUndo();
if ( miEditUndo.isDisposed() || miEditRedo.isDisposed() ) {
return;
}
if ( prev != null ) {
miEditUndo.setEnabled( true );
miEditUndo.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.Undo", prev
.toString() ) ) );
} else {
miEditUndo.setEnabled( false );
miEditUndo.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.UndoNotAvailable" ) ) );
}
if ( next != null ) {
miEditRedo.setEnabled( true );
miEditRedo.setText( OsHelper.customizeMenuitemText( BaseMessages.getString( PKG, "TableView.menu.Redo", next
.toString() ) ) );
} else {
miEditRedo.setEnabled( false );
miEditRedo.setText( OsHelper.customizeMenuitemText( BaseMessages.getString(
PKG, "TableView.menu.RedoNotAvailable" ) ) );
}
}
// get previous undo, change position
private TransAction previousUndo() {
if ( undo.isEmpty() || undoPosition < 0 ) {
return null; // No undo left!
}
TransAction retval = undo.get( undoPosition );
undoPosition--;
return retval;
}
// View previous undo, don't change position
private TransAction viewPreviousUndo() {
if ( undo.isEmpty() || undoPosition < 0 ) {
return null; // No undo left!
}
TransAction retval = undo.get( undoPosition );
return retval;
}
private TransAction nextUndo() {
int size = undo.size();
if ( size == 0 || undoPosition >= size - 1 ) {
return null; // no redo left...
}
undoPosition++;
TransAction retval = undo.get( undoPosition );
return retval;
}
private TransAction viewNextUndo() {
int size = undo.size();
if ( size == 0 || undoPosition >= size - 1 ) {
return null; // no redo left...
}
TransAction retval = undo.get( undoPosition + 1 );
return retval;
}
private void clearUndo() {
undo = new ArrayList<TransAction>();
undoPosition = -1;
}
private Point getButtonPosition() {
return new Point( buttonColnr, buttonRownr );
}
public String getButtonString() {
return buttonContent;
}
public void setButtonString( String str ) {
Point p = getButtonPosition();
TableItem item = table.getItem( p.y );
item.setText( p.x, str );
}
public void closeActiveButton() {
if ( button != null && !button.isDisposed() ) {
button.dispose();
}
}
public void unEdit() {
if ( text != null && !text.isDisposed() ) {
text.dispose();
}
if ( combo != null && !combo.isDisposed() ) {
combo.dispose();
}
}
// Filtering...
public void setFilter() {
if ( condition == null ) {
condition = new Condition();
}
RowMetaInterface f = getRowWithoutValues();
EnterConditionDialog ecd = new EnterConditionDialog( parent.getShell(), SWT.NONE, f, condition );
Condition cond = ecd.open();
if ( cond != null ) {
ArrayList<Integer> tokeep = new ArrayList<Integer>();
// Apply the condition to the TableView...
int nr = table.getItemCount();
for ( int i = nr - 1; i >= 0; i-- ) {
RowMetaAndData r = getRow( i );
boolean keep = cond.evaluate( r.getRowMeta(), r.getData() );
if ( keep ) {
tokeep.add( Integer.valueOf( i ) );
}
}
int[] sels = new int[tokeep.size()];
for ( int i = 0; i < sels.length; i++ ) {
sels[i] = ( tokeep.get( i ) ).intValue();
}
table.setSelection( sels );
}
}
public RowMetaInterface getRowWithoutValues() {
RowMetaInterface f = new RowMeta();
f.addValueMeta( new ValueMetaInteger( "#" ) );
for ( int i = 0; i < columns.length; i++ ) {
f.addValueMeta( new ValueMetaString( columns[i].getName() ) );
}
return f;
}
public RowMetaAndData getRow( int nr ) {
TableItem ti = table.getItem( nr );
RowMetaInterface rowMeta = getRowWithoutValues();
Object[] rowData = new Object[rowMeta.size()];
rowData[0] = new Long( nr );
for ( int i = 1; i < rowMeta.size(); i++ ) {
rowData[i] = ti.getText( i );
}
return new RowMetaAndData( rowMeta, rowData );
}
public int[] getSelectionIndices() {
return table.getSelectionIndices();
}
public int getSelectionIndex() {
return table.getSelectionIndex();
}
public void remove( int index ) {
table.remove( index );
if ( table.getItemCount() == 0 ) {
new TableItem( table, SWT.NONE );
}
}
public void remove( int[] index ) {
table.remove( index );
if ( table.getItemCount() == 0 ) {
new TableItem( table, SWT.NONE );
}
}
public String getItem( int rownr, int colnr ) {
TableItem item = table.getItem( rownr );
if ( item != null ) {
return item.getText( colnr );
} else {
return null;
}
}
public void add( String... string ) {
TableItem item = new TableItem( table, SWT.NONE );
for ( int i = 0; i < string.length && i + 1 < table.getColumnCount(); i++ ) {
if ( string[i] != null ) {
item.setText( i + 1, string[i] );
}
}
}
public String[] getItem( int rownr ) {
TableItem item = table.getItem( rownr );
if ( item != null ) {
return getItemText( item );
} else {
return null;
}
}
/**
* Get all the strings from a certain column as an array
*
* @param colnr The column to return
* @return the column values as a string array.
*/
public String[] getItems( int colnr ) {
String[] retval = new String[table.getItemCount()];
for ( int i = 0; i < retval.length; i++ ) {
TableItem item = table.getItem( i );
retval[i] = item.getText( colnr + 1 );
}
return retval;
}
public void removeAll() {
table.removeAll();
if ( table.getItemCount() == 0 ) {
new TableItem( table, SWT.NONE );
}
}
public int getItemCount() {
return table.getItemCount();
}
public void setText( String text, int colnr, int rownr ) {
TableItem item = table.getItem( rownr );
item.setText( colnr, text );
}
/**
* @return Returns the readonly.
*/
public boolean isReadonly() {
return readonly;
}
/**
* @param readonly The readonly to set.
*/
public void setReadonly( boolean readonly ) {
this.readonly = readonly;
}
/**
* @return the sortable
*/
public boolean isSortable() {
return sortable;
}
/**
* @param sortable the sortable to set
*/
public void setSortable( boolean sortable ) {
this.sortable = sortable;
if ( !sortable ) {
table.setSortColumn( null );
} else {
table.setSortColumn( table.getColumn( sortfield ) );
}
}
public void setFocusOnFirstEditableField() {
// Look for the first field that can be edited...
int rownr = 0;
boolean gotOne = false;
for ( int colnr = 0; colnr < columns.length && !gotOne; colnr++ ) {
if ( !columns[colnr].isReadOnly() ) {
// edit this one...
gotOne = true;
activeTableItem = table.getItem( rownr );
activeTableColumn = colnr + 1;
edit( rownr, colnr + 1 );
}
}
}
/**
* @return the getSortField
*/
public int getSortField() {
return sortfield;
}
/**
* @return the sortingDescending
*/
public boolean isSortingDescending() {
return sortingDescending;
}
/**
* @param sortingDescending the sortingDescending to set
*/
public void setSortingDescending( boolean sortingDescending ) {
this.sortingDescending = sortingDescending;
}
public Table getTable() {
return table;
}
/**
* @return the numberColumn
*/
public ColumnInfo getNumberColumn() {
return numberColumn;
}
/**
* @param numberColumn the numberColumn to set
*/
public void setNumberColumn( ColumnInfo numberColumn ) {
this.numberColumn = numberColumn;
}
public TableEditor getEditor() {
return editor;
}
public void setEditor( TableEditor editor ) {
this.editor = editor;
}
public void applyOSXChanges() {
if ( text != null && !text.isDisposed() && lsFocusText != null ) {
lsFocusText.focusLost( null );
}
}
/**
* @return the showingBlueNullValues
*/
public boolean isShowingBlueNullValues() {
return showingBlueNullValues;
}
/**
* @param showingBlueNullValues the showingBlueNullValues to set
*/
public void setShowingBlueNullValues( boolean showingBlueNullValues ) {
this.showingBlueNullValues = showingBlueNullValues;
}
/**
* @return the lsContent
*/
public ModifyListener getContentListener() {
return lsContent;
}
/**
* @param lsContent the lsContent to set
*/
public void setContentListener( ModifyListener lsContent ) {
this.lsContent = lsContent;
}
/**
* @return the showingConversionErrorsInline
*/
public boolean isShowingConversionErrorsInline() {
return showingConversionErrorsInline;
}
/**
* @param showingConversionErrorsInline the showingConversionErrorsInline to set
*/
public void setShowingConversionErrorsInline( boolean showingConversionErrorsInline ) {
this.showingConversionErrorsInline = showingConversionErrorsInline;
}
/**
* Returns copy of columns array in order to prevent unintented modifications.
*
* @return columns array
*/
public ColumnInfo[] getColumns() {
return Arrays.copyOf( columns, columns.length );
}
public TableItem getActiveTableItem() {
return activeTableItem;
}
public int getActiveTableColumn() {
return activeTableColumn;
}
}