/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 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.job.entry;
import com.google.common.annotations.VisibleForTesting;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.logging.LoggingObjectType;
import org.pentaho.di.core.logging.SimpleLoggingObject;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.job.entry.JobEntryInterface;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.RepositoryElementMetaInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.database.dialog.DatabaseDialog;
import org.pentaho.di.ui.core.database.wizard.CreateDatabaseWizard;
import org.pentaho.di.ui.util.DialogUtils;
import org.pentaho.metastore.api.IMetaStore;
/**
* The JobEntryDialog class is responsible for constructing and opening the settings dialog for the job entry. Whenever
* the user opens the job entry settings in Spoon, it will instantiate the dialog class passing in the JobEntryInterface
* object and call the
*
* <pre>
* open()
* </pre>
*
* method on the dialog. SWT is the native windowing environment of Spoon, and it is typically the framework used for
* implementing job entry dialogs.
*/
public class JobEntryDialog extends Dialog {
/** The package name, used for internationalization. */
private static Class<?> PKG = StepInterface.class; // for i18n purposes, needed by Translator2!!
/** The loggingObject for the dialog */
public static final LoggingObjectInterface loggingObject = new SimpleLoggingObject(
"Job entry dialog", LoggingObjectType.JOBENTRYDIALOG, null );
/** A reference to the job entry interface */
protected JobEntryInterface jobEntryInt;
/** The repository */
protected Repository rep;
/** the MetaStore */
protected IMetaStore metaStore;
/** The job metadata object. */
protected JobMeta jobMeta;
/** A reference to the shell object */
protected Shell shell;
/** A reference to the properties user interface */
protected PropsUI props;
/** A reference to the parent shell */
protected Shell parent;
/** A reference to a database dialog */
protected DatabaseDialog databaseDialog;
/**
* Instantiates a new job entry dialog.
*
* @param parent
* the parent shell
* @param jobEntry
* the job entry interface
* @param rep
* the repository
* @param jobMeta
* the job metadata object
*/
public JobEntryDialog( Shell parent, JobEntryInterface jobEntry, Repository rep, JobMeta jobMeta ) {
super( parent, SWT.NONE );
props = PropsUI.getInstance();
this.jobEntryInt = jobEntry;
this.rep = rep;
this.jobMeta = jobMeta;
this.shell = parent;
}
/**
* Gets the database dialog.
*
* @return the database dialog
*/
private DatabaseDialog getDatabaseDialog() {
if ( databaseDialog != null ) {
return databaseDialog;
}
databaseDialog = new DatabaseDialog( shell );
return databaseDialog;
}
/**
* Adds the connection line for the given parent and previous control, and returns a combo box UI component
*
* @param parent
* the parent composite object
* @param previous
* the previous control
* @param middle
* the middle
* @param margin
* the margin
* @return the combo box UI component
*/
public CCombo addConnectionLine( Composite parent, Control previous, int middle, int margin ) {
return addConnectionLine( parent, previous, middle, margin, new Label( parent, SWT.RIGHT ), new Button(
parent, SWT.PUSH ), new Button( parent, SWT.PUSH ), new Button( parent, SWT.PUSH ) );
}
/**
* Adds the connection line for the given parent and previous control, and returns a combo box UI component
*
* @param parent
* the parent composite object
* @param previous
* the previous control
* @param middle
* the middle
* @param margin
* the margin
* @param wlConnection
* the connection label
* @param wbnConnection
* the "new connection" button
* @param wbeConnection
* the "edit connection" button
* @return the combo box UI component
*/
public CCombo addConnectionLine( Composite parent, Control previous, int middle, int margin, final Label wlConnection,
final Button wbwConnection, final Button wbnConnection, final Button wbeConnection ) {
final CCombo wConnection;
final FormData fdlConnection, fdbConnection, fdeConnection, fdConnection, fdbwConnection;
wConnection = new CCombo( parent, SWT.BORDER | SWT.READ_ONLY );
props.setLook( wConnection );
addDatabases( wConnection );
wlConnection.setText( BaseMessages.getString( PKG, "BaseStepDialog.Connection.Label" ) );
props.setLook( wlConnection );
fdlConnection = new FormData();
fdlConnection.left = new FormAttachment( 0, 0 );
fdlConnection.right = new FormAttachment( middle, -margin );
if ( previous != null ) {
fdlConnection.top = new FormAttachment( previous, margin );
} else {
fdlConnection.top = new FormAttachment( 0, 0 );
}
wlConnection.setLayoutData( fdlConnection );
//
// Wizard button
//
wbwConnection.setText( BaseMessages.getString( PKG, "BaseStepDialog.WizardConnectionButton.Label" ) );
wbwConnection.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
CreateDatabaseWizard cdw = new CreateDatabaseWizard();
DatabaseMeta newDBInfo = cdw.createAndRunDatabaseWizard( shell, props, jobMeta.getDatabases() );
if ( newDBInfo != null ) {
jobMeta.addDatabase( newDBInfo );
reinitConnectionDropDown( wConnection, newDBInfo.getName() );
}
}
} );
fdbwConnection = new FormData();
fdbwConnection.right = new FormAttachment( 100, 0 );
if ( previous != null ) {
fdbwConnection.top = new FormAttachment( previous, margin );
} else {
fdbwConnection.top = new FormAttachment( 0, 0 );
}
wbwConnection.setLayoutData( fdbwConnection );
//
// NEW button
//
wbnConnection.setText( BaseMessages.getString( PKG, "BaseStepDialog.NewConnectionButton.Label" ) );
wbnConnection.addSelectionListener( new AddConnectionListener( wConnection ) );
fdbConnection = new FormData();
fdbConnection.right = new FormAttachment( wbwConnection, -margin );
if ( previous != null ) {
fdbConnection.top = new FormAttachment( previous, margin );
} else {
fdbConnection.top = new FormAttachment( 0, 0 );
}
wbnConnection.setLayoutData( fdbConnection );
//
// Edit button
//
wbeConnection.setText( BaseMessages.getString( PKG, "BaseStepDialog.EditConnectionButton.Label" ) );
wbeConnection.addSelectionListener( new EditConnectionListener( wConnection ) );
fdeConnection = new FormData();
fdeConnection.right = new FormAttachment( wbnConnection, -margin );
if ( previous != null ) {
fdeConnection.top = new FormAttachment( previous, margin );
} else {
fdeConnection.top = new FormAttachment( 0, 0 );
}
wbeConnection.setLayoutData( fdeConnection );
//
// what's left of the line: combo box
//
fdConnection = new FormData();
fdConnection.left = new FormAttachment( middle, 0 );
if ( previous != null ) {
fdConnection.top = new FormAttachment( previous, margin );
} else {
fdConnection.top = new FormAttachment( 0, 0 );
}
fdConnection.right = new FormAttachment( wbeConnection, -margin );
wConnection.setLayoutData( fdConnection );
return wConnection;
}
@VisibleForTesting
String showDbDialogUnlessCancelledOrValid( DatabaseMeta changing, DatabaseMeta origin ) {
changing.shareVariablesWith( jobMeta );
DatabaseDialog cid = getDatabaseDialog();
cid.setDatabaseMeta( changing );
cid.setModalDialog( true );
String name = null;
boolean repeat = true;
while ( repeat ) {
name = cid.open();
if ( name == null ) {
// Cancel was pressed
repeat = false;
} else {
name = name.trim();
DatabaseMeta same = jobMeta.findDatabase( name );
if ( same == null || same == origin ) {
// OK was pressed and input is valid
repeat = false;
} else {
showDbExistsDialog( changing );
}
}
}
return name;
}
@VisibleForTesting
void showDbExistsDialog( DatabaseMeta changing ) {
DatabaseDialog.showDatabaseExistsDialog( shell, changing );
}
private void reinitConnectionDropDown( CCombo dropDown, String selected ) {
dropDown.removeAll();
addDatabases( dropDown );
selectDatabase( dropDown, selected );
}
/**
* Adds the databases from the job metadata to the combo box.
*
* @param wConnection
* the w connection
*/
public void addDatabases( CCombo wConnection ) {
for ( int i = 0; i < jobMeta.nrDatabases(); i++ ) {
DatabaseMeta ci = jobMeta.getDatabase( i );
wConnection.add( ci.getName() );
}
}
/**
* Selects a database from the combo box
*
* @param wConnection
* the combo box list of connections
* @param name
* the name
*/
public void selectDatabase( CCombo wConnection, String name ) {
int idx = wConnection.indexOf( name );
if ( idx >= 0 ) {
wConnection.select( idx );
}
}
public IMetaStore getMetaStore() {
return metaStore;
}
public void setMetaStore( IMetaStore metaStore ) {
this.metaStore = metaStore;
}
protected String getPathOf( RepositoryElementMetaInterface object ) {
return DialogUtils.getPathOf( object );
}
@VisibleForTesting
class AddConnectionListener extends SelectionAdapter {
private final CCombo wConnection;
public AddConnectionListener( CCombo wConnection ) {
this.wConnection = wConnection;
}
@Override
public void widgetSelected( SelectionEvent e ) {
DatabaseMeta databaseMeta = new DatabaseMeta();
String connectionName = showDbDialogUnlessCancelledOrValid( databaseMeta, null );
if ( connectionName != null ) {
jobMeta.addDatabase( databaseMeta );
reinitConnectionDropDown( wConnection, databaseMeta.getName() );
}
}
}
@VisibleForTesting
class EditConnectionListener extends SelectionAdapter {
private final CCombo wConnection;
public EditConnectionListener( CCombo wConnection ) {
this.wConnection = wConnection;
}
public void widgetSelected( SelectionEvent e ) {
DatabaseMeta databaseMeta = jobMeta.findDatabase( wConnection.getText() );
if ( databaseMeta != null ) {
// cloning to avoid spoiling data on cancel or incorrect input
DatabaseMeta clone = (DatabaseMeta) databaseMeta.clone();
String connectionName = showDbDialogUnlessCancelledOrValid( clone, databaseMeta );
if ( connectionName != null ) {
// need to replace the old connection with a new one
jobMeta.removeDatabase( jobMeta.indexOfDatabase( databaseMeta ) );
jobMeta.addDatabase( clone );
reinitConnectionDropDown( wConnection, connectionName );
}
}
}
}
}