/*! ****************************************************************************** * * 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.dataset.spoon.dialog; import org.apache.commons.lang.StringUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; 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.Combo; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Dialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.pentaho.di.core.Const; import org.pentaho.di.core.database.Database; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.LogChannel; import org.pentaho.di.core.logging.LoggingObject; 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.util.StringUtil; import org.pentaho.di.core.variables.Variables; import org.pentaho.di.dataset.DataSet; import org.pentaho.di.dataset.DataSetField; import org.pentaho.di.dataset.DataSetGroup; import org.pentaho.di.dataset.DataSetGroupType; import org.pentaho.di.dataset.spoon.DataSetHelper; import org.pentaho.di.dataset.util.DataSetConst; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.dialog.PreviewRowsDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.core.gui.WindowProperty; import org.pentaho.di.ui.core.widget.ColumnInfo; import org.pentaho.di.ui.core.widget.TableView; import org.pentaho.di.ui.trans.step.BaseStepDialog; import org.pentaho.di.ui.trans.step.TableItemInsertListener; import org.pentaho.metastore.api.IMetaStore; import org.pentaho.metastore.api.exceptions.MetaStoreException; import org.pentaho.metastore.persist.MetaStoreFactory; import org.pentaho.metastore.util.PentahoDefaults; import java.util.Collections; import java.util.List; public class DataSetDialog extends Dialog { private static Class<?> PKG = DataSetDialog.class; // for i18n purposes, needed by Translator2!! private DataSet dataSet; private List<DataSetGroup> groups; private Shell shell; private Text wName; private Text wDescription; private Text wTableName; private Combo wDataSetGroup; private TableView wFieldMapping; private Button wOK; private Button wGetMetadata; private Button wCreateTable; private Button wEditData; private Button wViewData; private Button wCancel; private Button wNewGroup; private PropsUI props; private int middle; private int margin; private boolean ok; private IMetaStore metaStore; private Button wEditGroup; private List<DatabaseMeta> databases; public DataSetDialog( Shell parent, IMetaStore metaStore, DataSet dataSet, List<DataSetGroup> groups, List<DatabaseMeta> databases ) { super( parent, SWT.NONE ); this.metaStore = metaStore; this.dataSet = dataSet; this.groups = groups; this.databases = databases; props = PropsUI.getInstance(); ok = false; } public boolean open() { Shell parent = getParent(); shell = new Shell( parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN ); props.setLook( shell ); shell.setImage( GUIResource.getInstance().getImageTable() ); middle = props.getMiddlePct(); margin = Const.MARGIN; FormLayout formLayout = new FormLayout(); formLayout.marginWidth = Const.FORM_MARGIN; formLayout.marginHeight = Const.FORM_MARGIN; shell.setText( BaseMessages.getString( PKG, "DataSetDialog.Shell.Title" ) ); shell.setLayout( formLayout ); // The name of the group... // Label wlName = new Label( shell, SWT.RIGHT ); props.setLook( wlName ); wlName.setText( BaseMessages.getString( PKG, "DataSetDialog.Name.Label" ) ); FormData fdlName = new FormData(); fdlName.top = new FormAttachment( 0, 0 ); fdlName.left = new FormAttachment( 0, 0 ); fdlName.right = new FormAttachment( middle, -margin ); wlName.setLayoutData( fdlName ); wName = new Text( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER ); props.setLook( wName ); FormData fdName = new FormData(); fdName.top = new FormAttachment( 0, 0 ); fdName.left = new FormAttachment( middle, 0 ); fdName.right = new FormAttachment( 100, 0 ); wName.setLayoutData( fdName ); Control lastControl = wName; // The description of the group... // Label wlDescription = new Label( shell, SWT.RIGHT ); props.setLook( wlDescription ); wlDescription.setText( BaseMessages.getString( PKG, "DataSetDialog.Description.Label" ) ); FormData fdlDescription = new FormData(); fdlDescription.top = new FormAttachment( lastControl, margin ); fdlDescription.left = new FormAttachment( 0, 0 ); fdlDescription.right = new FormAttachment( middle, -margin ); wlDescription.setLayoutData( fdlDescription ); wDescription = new Text( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER ); props.setLook( wDescription ); FormData fdDescription = new FormData(); fdDescription.top = new FormAttachment( lastControl, margin ); fdDescription.left = new FormAttachment( middle, 0 ); fdDescription.right = new FormAttachment( 100, 0 ); wDescription.setLayoutData( fdDescription ); lastControl = wDescription; // The table storing the set... // Label wlTableName = new Label( shell, SWT.RIGHT ); props.setLook( wlTableName ); wlTableName.setText( BaseMessages.getString( PKG, "DataSetDialog.TableName.Label" ) ); FormData fdlTableName = new FormData(); fdlTableName.top = new FormAttachment( lastControl, margin ); fdlTableName.left = new FormAttachment( 0, 0 ); fdlTableName.right = new FormAttachment( middle, -margin ); wlTableName.setLayoutData( fdlTableName ); wTableName = new Text( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER ); props.setLook( wTableName ); FormData fdTableName = new FormData(); fdTableName.top = new FormAttachment( lastControl, margin ); fdTableName.left = new FormAttachment( middle, 0 ); fdTableName.right = new FormAttachment( 100, 0 ); wTableName.setLayoutData( fdTableName ); lastControl = wTableName; // The data set group... // Label wlGroup = new Label( shell, SWT.RIGHT ); props.setLook( wlGroup ); wlGroup.setText( BaseMessages.getString( PKG, "DataSetDialog.Group.Label" ) ); FormData fdlDatabase = new FormData(); fdlDatabase.top = new FormAttachment( lastControl, margin ); fdlDatabase.left = new FormAttachment( 0, 0 ); fdlDatabase.right = new FormAttachment( middle, -margin ); wlGroup.setLayoutData( fdlDatabase ); wNewGroup = new Button( shell, SWT.PUSH ); props.setLook( wNewGroup ); wNewGroup.setText( BaseMessages.getString( PKG, "DataSetDialog.NewGroup.Label" ) ); FormData fdlNewGroup = new FormData(); fdlNewGroup.top = new FormAttachment( lastControl, margin ); fdlNewGroup.right = new FormAttachment( 100, -margin ); wNewGroup.setLayoutData( fdlNewGroup ); wNewGroup.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent arg0 ) { addDataSetGroup(); } } ); wEditGroup = new Button( shell, SWT.PUSH ); props.setLook( wEditGroup ); wEditGroup.setText( BaseMessages.getString( PKG, "DataSetDialog.EditGroup.Label" ) ); FormData fdlEditGroup = new FormData(); fdlEditGroup.top = new FormAttachment( lastControl, margin ); fdlEditGroup.right = new FormAttachment( wNewGroup, -margin ); wEditGroup.setLayoutData( fdlEditGroup ); wEditGroup.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent arg0 ) { editDataSetGroup(); } } ); wDataSetGroup = new Combo( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER ); FormData fdDatabase = new FormData(); fdDatabase.top = new FormAttachment( lastControl, margin ); fdDatabase.left = new FormAttachment( middle, 0 ); fdDatabase.right = new FormAttachment( wEditGroup, -margin ); wDataSetGroup.setLayoutData( fdDatabase ); lastControl = wDataSetGroup; // The field mapping from the input to the data set... // Label wlFieldMapping = new Label( shell, SWT.NONE ); wlFieldMapping.setText( BaseMessages.getString( PKG, "DataSetDialog.FieldMapping.Label" ) ); props.setLook( wlFieldMapping ); FormData fdlUpIns = new FormData(); fdlUpIns.left = new FormAttachment( 0, 0 ); fdlUpIns.top = new FormAttachment( lastControl, margin * 2 ); wlFieldMapping.setLayoutData( fdlUpIns ); lastControl = wlFieldMapping; // Buttons at the bottom... // wOK = new Button( shell, SWT.PUSH ); wOK.setText( BaseMessages.getString( PKG, "System.Button.OK" ) ); wGetMetadata = new Button( shell, SWT.PUSH ); wGetMetadata.setText( BaseMessages.getString( PKG, "DataSetDialog.GetMetadata.Button" ) ); wCreateTable = new Button( shell, SWT.PUSH ); wCreateTable.setText( BaseMessages.getString( PKG, "DataSetDialog.CreateTable.Button" ) ); wEditData = new Button( shell, SWT.PUSH ); wEditData.setText( BaseMessages.getString( PKG, "DataSetDialog.EditData.Button" ) ); wViewData = new Button( shell, SWT.PUSH ); wViewData.setText( BaseMessages.getString( PKG, "DataSetDialog.ViewData.Button" ) ); wCancel = new Button( shell, SWT.PUSH ); wCancel.setText( BaseMessages.getString( PKG, "System.Button.Cancel" ) ); Button[] buttons = new Button[] { wOK, wGetMetadata, wCreateTable, wEditData, wViewData, wCancel }; BaseStepDialog.positionBottomButtons( shell, buttons, margin, null ); // the field mapping grid in between // ColumnInfo[] columns = new ColumnInfo[] { new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.FieldName" ), ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] { "" }, false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.ColumnName" ), ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] { "" }, false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.FieldType" ), ColumnInfo.COLUMN_TYPE_CCOMBO, ValueMetaFactory.getAllValueMetaNames(), false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.FieldFormat" ), ColumnInfo.COLUMN_TYPE_TEXT, true, false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.FieldLength" ), ColumnInfo.COLUMN_TYPE_TEXT, true, false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.FieldPrecision" ), ColumnInfo.COLUMN_TYPE_TEXT, true, false ), new ColumnInfo( BaseMessages.getString( PKG, "DataSetDialog.ColumnInfo.Comment" ), ColumnInfo.COLUMN_TYPE_TEXT, false, false ), }; wFieldMapping = new TableView( new Variables(), shell, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL, columns, dataSet.getFields().size(), null, props ); FormData fdFieldMapping = new FormData(); fdFieldMapping.left = new FormAttachment( 0, 0 ); fdFieldMapping.top = new FormAttachment( lastControl, margin ); fdFieldMapping.right = new FormAttachment( 100, 0 ); fdFieldMapping.bottom = new FormAttachment( wOK, -2 * margin ); wFieldMapping.setLayoutData( fdFieldMapping ); // Add listeners wOK.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { ok(); } } ); wGetMetadata.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { getMetadataFromTable(); } } ); wCreateTable.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { createTable(); } } ); wEditData.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { editData(); } } ); wViewData.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { viewData(); } } ); wCancel.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { cancel(); } } ); SelectionAdapter selAdapter = new SelectionAdapter() { public void widgetDefaultSelected( SelectionEvent e ) { ok(); } }; wName.addSelectionListener( selAdapter ); wDescription.addSelectionListener( selAdapter ); wTableName.addSelectionListener( selAdapter ); // Detect X or ALT-F4 or something that kills this window... shell.addShellListener( new ShellAdapter() { public void shellClosed( ShellEvent e ) { cancel(); } } ); getData(); BaseStepDialog.setSize( shell ); shell.open(); Display display = parent.getDisplay(); while ( !shell.isDisposed() ) { if ( !display.readAndDispatch() ) { display.sleep(); } } return ok; } protected void addDataSetGroup() { try { DataSetHelper.getInstance().addDataSetGroup(); refreshGroups( metaStore ); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error creating new data set group", e ); } } protected void editDataSetGroup() { String groupName = wDataSetGroup.getText(); if ( StringUtils.isEmpty( groupName ) ) { return; } try { DataSetHelper.getInstance().editDataSetGroup( groupName ); refreshGroups( metaStore ); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error editing data set group", e ); } } private void refreshGroups( IMetaStore metaStore ) throws MetaStoreException { MetaStoreFactory<DataSetGroup> factory = new MetaStoreFactory<DataSetGroup>( DataSetGroup.class, metaStore, PentahoDefaults.NAMESPACE ); factory.addNameList( DataSetConst.DATABASE_LIST_KEY, databases ); groups = factory.getElements(); List<String> names = factory.getElementNames(); Collections.sort( names ); wDataSetGroup.setItems( names.toArray( new String[ names.size() ] ) ); } /** * Look at the metadata specified here and create the table accordingly... */ protected void getMetadataFromTable() { try { verifySettings(); DataSet set = new DataSet(); getInfo( set ); DataSetGroup group = set.getGroup(); if ( group.getType() != DataSetGroupType.Database ) { return; } group.verifySettings(); String schemaTable = group.getDatabaseMeta().getQuotedSchemaTableCombination( group.getSchemaName(), wTableName.getText() ); Database database = null; try { database = new Database( new LoggingObject( "DataSetDialog" ), group.getDatabaseMeta() ); database.connect(); if ( database.checkTableExists( schemaTable ) ) { RowMetaInterface rowMeta = database.getTableFields( schemaTable ); BaseStepDialog.getFieldsFromPrevious( rowMeta, wFieldMapping, 2, new int[] { 1, 2 }, new int[] { 3 }, 4, 5, new TableItemInsertListener() { public boolean tableItemInserted( TableItem tableItem, ValueMetaInterface v ) { tableItem.setText( 4, v.getLength() < 0 ? "" : Integer.toString( v.getLength() ) ); tableItem.setText( 5, v.getPrecision() < 0 ? "" : Integer.toString( v.getPrecision() ) ); return true; } } ); } else { throw new KettleException( BaseMessages.getString( PKG, "DataSetDialog.Error.TableDoesNotExist", schemaTable ) ); } } finally { if ( database != null ) { database.disconnect(); } } } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error retrieving metadata from dataset table", e ); } } private void verifySettings() throws KettleException { DataSetGroup group = DataSetConst.findDataSetGroup( groups, wDataSetGroup.getText() ); if ( group == null ) { throw new KettleException( BaseMessages.getString( PKG, "DataSetDialog.Error.NoGroupSpecified" ) ); } if ( StringUtil.isEmpty( wTableName.getText() ) ) { throw new KettleException( BaseMessages.getString( PKG, "DataSetDialog.Error.NoTableSpecified" ) ); } group.verifySettings(); } /** * Look at the metadata specified here and create the table accordingly... * - Create a table for the Database Group type * - Create a metadata file for the CSV group type */ protected void createTable() { try { verifySettings(); DataSet set = new DataSet(); getInfo( set ); DataSetGroup group = set.getGroup(); String tableName = wTableName.getText(); // Calculate the row metadata of the table // RowMetaInterface rowMeta = new RowMeta(); int nrFields = wFieldMapping.nrNonEmpty(); for ( int i = 0; i < nrFields; i++ ) { TableItem item = wFieldMapping.getNonEmpty( i ); int colnr = 2; String columnName = item.getText( colnr++ ); if ( StringUtil.isEmpty( columnName ) ) { throw new KettleException( BaseMessages.getString( PKG, "DataSetDialog.Error.NoColumnName", Integer.toString( i ) ) ); } int fieldType = ValueMetaFactory.getIdForValueMeta( item.getText( colnr++ ) ); if ( fieldType == ValueMetaInterface.TYPE_NONE ) { throw new KettleException( BaseMessages.getString( PKG, "DataSetDialog.Error.NoDataType", Integer.toString( i ) ) ); } int length = Const.toInt( item.getText( colnr++ ), -1 ); int precision = Const.toInt( item.getText( colnr++ ), -1 ); ValueMetaInterface valueMeta = ValueMetaFactory.createValueMeta( columnName, fieldType, length, precision ); rowMeta.addValueMeta( valueMeta ); } group.createTable( tableName, rowMeta ); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error retrieving metadata from dataset table", e ); } } protected void editData() { // If the row count is too high, we don't want to load it into memory... // Too high simply means: above the preview size... // int previewSize = props.getDefaultPreviewSize(); try { verifySettings(); DataSet set = new DataSet(); getInfo( set ); DataSetGroup group = set.getGroup(); // get rows from the data set... // List<Object[]> rows = set.getAllRows( LogChannel.UI ); RowMetaInterface fieldsRowMeta = set.getSetRowMeta( false ); RowMetaInterface columnsRowMeta = set.getSetRowMeta( true ); EditRowsDialog editRowsDialog = new EditRowsDialog( shell, SWT.NONE, BaseMessages.getString( PKG, "DataSetDialog.EditRows.Title" ), BaseMessages.getString( PKG, "DataSetDialog.EditRows.Message", set.getName() ), fieldsRowMeta, rows ); List<Object[]> newList = editRowsDialog.open(); if ( newList != null ) { // Write the rows back to the data set // group.writeDataSetData( set.getTableName(), columnsRowMeta, newList ); } } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error previewing data from dataset table", e ); } } protected void viewData() { try { DataSet set = new DataSet(); getInfo( set ); verifySettings(); List<Object[]> setRows = set.getAllRows( LogChannel.UI ); RowMetaInterface setRowMeta = set.getSetRowMeta( false ); PreviewRowsDialog previewRowsDialog = new PreviewRowsDialog( shell, new Variables(), SWT.NONE, set.getName(), setRowMeta, setRows ); previewRowsDialog.open(); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error previewing data from dataset table", e ); } } public void dispose() { props.setScreen( new WindowProperty( shell ) ); shell.dispose(); } public void getData() { for ( DataSetGroup group : groups ) { wDataSetGroup.add( group.getName() ); } wName.setText( Const.NVL( dataSet.getName(), "" ) ); wDescription.setText( Const.NVL( dataSet.getDescription(), "" ) ); wDataSetGroup.setText( Const.NVL( dataSet.getGroup() == null ? null : dataSet.getGroup().getName(), "" ) ); wTableName.setText( Const.NVL( dataSet.getTableName(), "" ) ); for ( int i = 0; i < dataSet.getFields().size(); i++ ) { DataSetField field = dataSet.getFields().get( i ); int colnr = 1; wFieldMapping.setText( Const.NVL( field.getFieldName(), "" ), colnr++, i ); wFieldMapping.setText( Const.NVL( field.getColumnName(), "" ), colnr++, i ); wFieldMapping.setText( ValueMetaFactory.getValueMetaName( field.getType() ), colnr++, i ); wFieldMapping.setText( Const.NVL( field.getFormat(), ""), colnr++, i ); wFieldMapping.setText( field.getLength() >= 0 ? Integer.toString( field.getLength() ) : "", colnr++, i ); wFieldMapping.setText( field.getPrecision() >= 0 ? Integer.toString( field.getPrecision() ) : "", colnr++, i ); wFieldMapping.setText( Const.NVL( field.getComment(), "" ), colnr++, i ); } wName.setFocus(); } private void cancel() { ok = false; dispose(); } /** * @param set The data set to load the dialog information into */ public void getInfo( DataSet set ) { set.setName( wName.getText() ); set.setDescription( wDescription.getText() ); set.setGroup( DataSetConst.findDataSetGroup( groups, wDataSetGroup.getText() ) ); set.setTableName( wTableName.getText() ); set.getFields().clear(); int nrFields = wFieldMapping.nrNonEmpty(); for ( int i = 0; i < nrFields; i++ ) { TableItem item = wFieldMapping.getNonEmpty( i ); int colnr = 1; String fieldName = item.getText( colnr++ ); String columnName = item.getText( colnr++ ); int type = ValueMetaFactory.getIdForValueMeta( item.getText( colnr++ ) ); String format = item.getText( colnr++ ); int length = Const.toInt( item.getText( colnr++ ), -1 ); int precision = Const.toInt( item.getText( colnr++ ), -1 ); String comment = item.getText( colnr++ ); DataSetField field = new DataSetField( fieldName, columnName, type, length, precision, comment, format ); set.getFields().add( field ); } } public void ok() { try { verifySettings(); } catch ( Exception e ) { new ErrorDialog( shell, "Error", BaseMessages.getString( PKG, "DataSetDialog.Error.ValidationError" ), e ); } getInfo( dataSet ); ok = true; dispose(); } public IMetaStore getMetaStore() { return metaStore; } public void setMetaStore( IMetaStore metaStore ) { this.metaStore = metaStore; } }