/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 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.spoon.trans;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.Props;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.i18n.GlobalMessages;
import org.pentaho.di.trans.step.BaseStepData.StepExecutionStatus;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepStatus;
import org.pentaho.di.ui.core.dialog.ErrorDialog;
import org.pentaho.di.ui.core.gui.GUIResource;
import org.pentaho.di.ui.core.widget.ColumnInfo;
import org.pentaho.di.ui.core.widget.TableView;
import org.pentaho.di.ui.spoon.Spoon;
import org.pentaho.di.ui.spoon.XulSpoonSettingsManager;
import org.pentaho.di.ui.spoon.delegates.SpoonDelegate;
import org.pentaho.di.ui.xul.KettleXulLoader;
import org.pentaho.ui.xul.XulDomContainer;
import org.pentaho.ui.xul.XulLoader;
import org.pentaho.ui.xul.containers.XulToolbar;
import org.pentaho.ui.xul.impl.XulEventHandler;
import org.pentaho.ui.xul.swt.tags.SwtToolbarbutton;
public class TransGridDelegate extends SpoonDelegate implements XulEventHandler {
private static Class<?> PKG = Spoon.class; // for i18n purposes, needed by Translator2!!
private static final String XUL_FILE_TRANS_GRID_TOOLBAR = "ui/trans-grid-toolbar.xul";
public static final long REFRESH_TIME = 100L;
public static final long UPDATE_TIME_VIEW = 1000L;
private TransGraph transGraph;
private CTabItem transGridTab;
private TableView transGridView;
private boolean refresh_busy;
private long lastUpdateView;
private XulToolbar toolbar;
private Composite transGridComposite;
private boolean hideInactiveSteps;
private boolean showSelectedSteps;
/**
* @param spoon
* @param transGraph
*/
public TransGridDelegate( Spoon spoon, TransGraph transGraph ) {
super( spoon );
this.transGraph = transGraph;
hideInactiveSteps = false;
}
public void showGridView() {
if ( transGridTab == null || transGridTab.isDisposed() ) {
addTransGrid();
} else {
transGridTab.dispose();
transGraph.checkEmptyExtraView();
}
}
/**
* Add a grid with the execution metrics per step in a table view
*
*/
public void addTransGrid() {
// First, see if we need to add the extra view...
//
if ( transGraph.extraViewComposite == null || transGraph.extraViewComposite.isDisposed() ) {
transGraph.addExtraView();
} else {
if ( transGridTab != null && !transGridTab.isDisposed() ) {
// just set this one active and get out...
//
transGraph.extraViewTabFolder.setSelection( transGridTab );
return;
}
}
transGridTab = new CTabItem( transGraph.extraViewTabFolder, SWT.NONE );
transGridTab.setImage( GUIResource.getInstance().getImageShowGrid() );
transGridTab.setText( BaseMessages.getString( PKG, "Spoon.TransGraph.GridTab.Name" ) );
transGridComposite = new Composite( transGraph.extraViewTabFolder, SWT.NONE );
transGridComposite.setLayout( new FormLayout() );
addToolBar();
Control toolbarControl = (Control) toolbar.getManagedObject();
toolbarControl.setLayoutData( new FormData() );
FormData fd = new FormData();
fd.left = new FormAttachment( 0, 0 ); // First one in the left top corner
fd.top = new FormAttachment( 0, 0 );
fd.right = new FormAttachment( 100, 0 );
toolbarControl.setLayoutData( fd );
toolbarControl.setParent( transGridComposite );
ColumnInfo[] colinf =
new ColumnInfo[] {
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Stepname" ), ColumnInfo.COLUMN_TYPE_TEXT, false,
true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Copynr" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Read" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Written" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Input" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Output" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Updated" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Rejected" ), ColumnInfo.COLUMN_TYPE_TEXT, false,
true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Errors" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Active" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Time" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.Speed" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ),
new ColumnInfo(
BaseMessages.getString( PKG, "TransLog.Column.PriorityBufferSizes" ), ColumnInfo.COLUMN_TYPE_TEXT,
false, true ), };
colinf[1].setAllignement( SWT.RIGHT );
colinf[2].setAllignement( SWT.RIGHT );
colinf[3].setAllignement( SWT.RIGHT );
colinf[4].setAllignement( SWT.RIGHT );
colinf[5].setAllignement( SWT.RIGHT );
colinf[6].setAllignement( SWT.RIGHT );
colinf[7].setAllignement( SWT.RIGHT );
colinf[8].setAllignement( SWT.RIGHT );
colinf[9].setAllignement( SWT.LEFT );
colinf[10].setAllignement( SWT.RIGHT );
colinf[11].setAllignement( SWT.RIGHT );
colinf[12].setAllignement( SWT.RIGHT );
transGridView = new TableView( transGraph.getManagedObject(), transGridComposite, SWT.BORDER
| SWT.FULL_SELECTION | SWT.MULTI, colinf, 1,
true, // readonly!
null, // Listener
spoon.props );
FormData fdView = new FormData();
fdView.left = new FormAttachment( 0, 0 );
fdView.right = new FormAttachment( 100, 0 );
fdView.top = new FormAttachment( (Control) toolbar.getManagedObject(), 0 );
fdView.bottom = new FormAttachment( 100, 0 );
transGridView.setLayoutData( fdView );
// Add a timer to update this view every couple of seconds...
//
final Timer tim = new Timer( "TransGraph: " + transGraph.getMeta().getName() );
final AtomicBoolean busy = new AtomicBoolean( false );
TimerTask timtask = new TimerTask() {
public void run() {
if ( !spoon.getDisplay().isDisposed() ) {
spoon.getDisplay().asyncExec( new Runnable() {
public void run() {
if ( !busy.get() ) {
busy.set( true );
refreshView();
busy.set( false );
}
}
} );
}
}
};
tim.schedule( timtask, 0L, REFRESH_TIME ); // schedule to repeat a couple of times per second to get fast feedback
transGridTab.addDisposeListener( new DisposeListener() {
public void widgetDisposed( DisposeEvent disposeEvent ) {
tim.cancel();
}
} );
transGridTab.setControl( transGridComposite );
transGraph.extraViewTabFolder.setSelection( transGridTab );
}
private void addToolBar() {
try {
XulLoader loader = new KettleXulLoader();
loader.setSettingsManager( XulSpoonSettingsManager.getInstance() );
ResourceBundle bundle = GlobalMessages.getBundle( "org/pentaho/di/ui/spoon/messages/messages" );
XulDomContainer xulDomContainer = loader.loadXul( XUL_FILE_TRANS_GRID_TOOLBAR, bundle );
xulDomContainer.addEventHandler( this );
toolbar = (XulToolbar) xulDomContainer.getDocumentRoot().getElementById( "nav-toolbar" );
ToolBar swtToolBar = (ToolBar) toolbar.getManagedObject();
spoon.props.setLook( swtToolBar, Props.WIDGET_STYLE_TOOLBAR );
swtToolBar.layout( true, true );
} catch ( Throwable t ) {
log.logError( toString(), Const.getStackTracker( t ) );
new ErrorDialog( transGridComposite.getShell(),
BaseMessages.getString( PKG, "Spoon.Exception.ErrorReadingXULFile.Title" ),
BaseMessages.getString( PKG, "Spoon.Exception.ErrorReadingXULFile.Message", XUL_FILE_TRANS_GRID_TOOLBAR ),
new Exception( t ) );
}
}
public void showHideInactive() {
hideInactiveSteps = !hideInactiveSteps;
SwtToolbarbutton onlyActiveButton = (SwtToolbarbutton) toolbar.getElementById( "show-inactive" );
if ( onlyActiveButton != null ) {
onlyActiveButton.setSelected( hideInactiveSteps );
if ( hideInactiveSteps ) {
onlyActiveButton.setImage( GUIResource.getInstance().getImageHideInactive() );
} else {
onlyActiveButton.setImage( GUIResource.getInstance().getImageShowInactive() );
}
}
}
public void showHideSelected() {
showSelectedSteps = !showSelectedSteps;
SwtToolbarbutton onlySelectedButton = (SwtToolbarbutton) toolbar.getElementById( "show-selected" );
if ( onlySelectedButton != null ) {
onlySelectedButton.setSelected( showSelectedSteps );
if ( showSelectedSteps ) {
onlySelectedButton.setImage( GUIResource.getInstance().getImageShowSelected() );
} else {
onlySelectedButton.setImage( GUIResource.getInstance().getImageShowAll() );
}
}
}
private void refreshView() {
boolean insert = true;
int nrSteps = -1;
int totalSteps = -1;
if ( transGridView == null || transGridView.isDisposed() ) {
return;
}
if ( refresh_busy ) {
return;
}
List<StepMeta> selectedSteps = new ArrayList<StepMeta>();
if ( showSelectedSteps ) {
selectedSteps = transGraph.trans.getTransMeta().getSelectedSteps();
}
int topIdx = transGridView.getTable().getTopIndex();
refresh_busy = true;
Table table = transGridView.table;
long time = new Date().getTime();
long msSinceLastUpdate = time - lastUpdateView;
if ( transGraph.trans != null && !transGraph.trans.isPreparing() && msSinceLastUpdate > UPDATE_TIME_VIEW ) {
lastUpdateView = time;
nrSteps = transGraph.trans.nrSteps();
totalSteps = nrSteps;
if ( hideInactiveSteps ) {
nrSteps = transGraph.trans.nrActiveSteps();
}
StepExecutionStatus[] stepStatusLookup = transGraph.trans.getTransStepExecutionStatusLookup();
boolean[] isRunningLookup = transGraph.trans.getTransStepIsRunningLookup();
int sortColumn = transGridView.getSortField();
boolean sortDescending = transGridView.isSortingDescending();
int[] selectedItems = transGridView.getSelectionIndices();
if ( table.getItemCount() != nrSteps ) {
table.removeAll();
} else {
insert = false;
}
if ( nrSteps == 0 && table.getItemCount() == 0 ) {
new TableItem( table, SWT.NONE );
refresh_busy = false;
return;
}
int nr = 0;
for ( int i = 0; i < totalSteps; i++ ) {
StepInterface baseStep = transGraph.trans.getRunThread( i );
// See if the step is selected & in need of display
//
boolean showSelected;
if ( showSelectedSteps ) {
if ( selectedSteps.size() == 0 ) {
showSelected = true;
} else {
showSelected = false;
for ( StepMeta stepMeta : selectedSteps ) {
if ( baseStep.getStepMeta().equals( stepMeta ) ) {
showSelected = true;
break;
}
}
}
} else {
showSelected = true;
}
// when "Hide active" steps is enabled show only alive steps
// otherwise only those that have not STATUS_EMPTY
//
if ( showSelected
&& ( hideInactiveSteps && ( isRunningLookup[i]
|| stepStatusLookup[i] != StepExecutionStatus.STATUS_FINISHED ) )
|| ( !hideInactiveSteps && stepStatusLookup[i] != StepExecutionStatus.STATUS_EMPTY ) ) {
TableItem ti = null;
if ( insert ) {
ti = new TableItem( table, SWT.NONE );
} else {
ti = table.getItem( nr );
}
if ( ti == null ) {
continue;
}
String num = "" + ( i + 1 );
if ( ti.getText( 0 ).length() < 1 ) {
ti.setText( 0, num );
}
if ( ti.getText( 0 ).length() > 0 ) {
Integer tIndex = Integer.parseInt( ti.getText( 0 ) );
tIndex--;
baseStep = transGraph.trans.getRunThread( tIndex );
}
StepStatus stepStatus = new StepStatus( baseStep );
String[] fields = stepStatus.getTransLogFields();
// Anti-flicker: if nothing has changed, don't change it on the
// screen!
for ( int f = 1; f < fields.length; f++ ) {
if ( !fields[f].equalsIgnoreCase( ti.getText( f ) ) ) {
ti.setText( f, fields[f] );
}
}
// Error lines should appear in red:
if ( baseStep.getErrors() > 0 ) {
ti.setBackground( GUIResource.getInstance().getColorRed() );
} else {
if ( nr % 2 == 0 ) {
ti.setBackground( GUIResource.getInstance().getColorWhite() );
} else {
ti.setBackground( GUIResource.getInstance().getColorBlueCustomGrid() );
}
}
nr++;
}
}
// Only need to resort if the output has been sorted differently to the
// default
if ( table.getItemCount() > 0 && ( sortColumn != 0 || !sortDescending ) ) {
transGridView.sortTable( sortColumn, sortDescending );
}
// if (updateRowNumbers) { transGridView.setRowNums(); }
transGridView.optWidth( true );
if ( selectedItems != null && selectedItems.length > 0 ) {
transGridView.setSelection( selectedItems );
}
// transGridView.getTable().setTopIndex(topIdx);
if ( transGridView.getTable().getTopIndex() != topIdx ) {
transGridView.getTable().setTopIndex( topIdx );
}
} else {
// We need at least one table-item in a table!
if ( table.getItemCount() == 0 ) {
new TableItem( table, SWT.NONE );
}
}
refresh_busy = false;
}
public CTabItem getTransGridTab() {
return transGridTab;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#getData()
*/
public Object getData() {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#getName()
*/
public String getName() {
return "transgrid";
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#getXulDomContainer()
*/
public XulDomContainer getXulDomContainer() {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#setData(java.lang.Object)
*/
public void setData( Object data ) {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#setName(java.lang.String)
*/
public void setName( String name ) {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.pentaho.ui.xul.impl.XulEventHandler#setXulDomContainer(org.pentaho.ui.xul.XulDomContainer)
*/
public void setXulDomContainer( XulDomContainer xulDomContainer ) {
// TODO Auto-generated method stub
}
}