/*! ******************************************************************************
*
* 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.dialog;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
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.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.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.Props;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.HasDatabasesInterface;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.gui.GUIResource;
import org.pentaho.di.ui.core.gui.WindowProperty;
import org.pentaho.di.ui.core.widget.TextVar;
import org.pentaho.di.ui.spoon.Spoon;
import org.pentaho.di.ui.spoon.delegates.SpoonDBDelegate;
import org.pentaho.di.ui.trans.step.BaseStepDialog;
import org.pentaho.di.ui.util.HelpUtils;
/**
* Allows the user to make a selection from a list of values.
*
* @author Matt
* @since 19-06-2003
*/
public class EnterSelectionDialog extends Dialog {
private static Class<?> PKG = EnterSelectionDialog.class; // for i18n purposes, needed by Translator2!!
private Label wlSelection;
private List wSelection;
private FormData fdlSelection, fdSelection;
private TextVar wConstantValue;
private Button wbUseConstant;
private Button wOK, wCancel;
private Listener lsOK, lsCancel;
private Shell shell;
public Shell getShell() {
return shell;
}
private SelectionAdapter lsDef;
private String[] choices;
private String selection;
private int selectionNr;
private String shellText;
private String lineText;
private PropsUI props;
private String constant;
private VariableSpace variableSpace;
private boolean viewOnly, modal;
private int[] selectedNrs;
private boolean multi;
private int[] indices;
private boolean fixed;
private boolean quickSearch;
private ToolItem goSearch, wfilter, addConnection;
private ToolItem wbRegex;
private String filterString = null;
private Pattern pattern = null;
private Text searchText = null;
private HasDatabasesInterface databasesInterface;
/**
* @deprecated Use CT without <i>props</i> parameter
*/
@Deprecated
public EnterSelectionDialog( Shell parent, PropsUI props, String[] choices, String shellText, String lineText ) {
this( parent, choices, shellText, lineText );
this.props = props;
}
/**
* Create a new dialog allow someone to pick one value out of a list of values
*
* @param parent
* the parent shell.
* @param choices
* The available list of options
* @param shellText
* The shell text
* @param message
* the message to display as extra information about the possible choices
*/
public EnterSelectionDialog( Shell parent, String[] choices, String shellText, String message ) {
super( parent, SWT.NONE );
this.choices = choices;
this.shellText = shellText;
this.lineText = message;
props = PropsUI.getInstance();
selection = null;
viewOnly = false;
modal = true;
selectedNrs = new int[] {};
multi = false;
fixed = false;
quickSearch = true;
}
public EnterSelectionDialog( Shell parent, String[] choices, String shellText, String message,
HasDatabasesInterface databasesInterface ) {
this( parent, choices, shellText, message );
this.databasesInterface = databasesInterface;
}
public EnterSelectionDialog( Shell parent, String[] choices, String shellText, String message, String constant,
VariableSpace variableSpace ) {
this( parent, choices, shellText, message );
this.constant = constant;
this.variableSpace = variableSpace;
}
public void setViewOnly() {
viewOnly = true;
}
public void setAvoidQuickSearch() {
quickSearch = false;
}
public void clearModal() {
modal = false;
}
public String open( int nr ) {
selectedNrs = new int[] { nr };
return open();
}
public String open() {
Shell parent = getParent();
Display display = parent.getDisplay();
shell =
new Shell( parent, SWT.DIALOG_TRIM
| ( modal ? SWT.APPLICATION_MODAL | SWT.SHEET : SWT.NONE ) | SWT.RESIZE | SWT.MIN | SWT.MAX );
props.setLook( shell );
FormLayout formLayout = new FormLayout();
formLayout.marginWidth = 15;
formLayout.marginHeight = 15;
shell.setLayout( formLayout );
shell.setText( shellText );
shell.setImage( GUIResource.getInstance().getImageSpoon() );
int margin = Const.MARGIN;
if ( quickSearch ) {
ToolBar treeTb = new ToolBar( shell, SWT.HORIZONTAL | SWT.FLAT );
props.setLook( treeTb );
wfilter = new ToolItem( treeTb, SWT.SEPARATOR );
searchText = new Text( treeTb, SWT.SEARCH | SWT.CANCEL );
props.setLook( searchText );
searchText.setToolTipText( BaseMessages.getString( PKG, "EnterSelectionDialog.FilterString.ToolTip" ) );
wfilter.setControl( searchText );
wfilter.setWidth( 120 );
wbRegex = new ToolItem( treeTb, SWT.CHECK );
wbRegex.setImage( GUIResource.getInstance().getImageRegexSmall() );
wbRegex.setToolTipText( BaseMessages.getString( PKG, "EnterSelectionDialog.useRegEx.Tooltip" ) );
goSearch = new ToolItem( treeTb, SWT.PUSH );
goSearch.setImage( GUIResource.getInstance().getImageSearchSmall() );
goSearch.setToolTipText( BaseMessages.getString( PKG, "EnterSelectionDialog.refresh.Label" ) );
goSearch.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent event ) {
updateFilter();
}
} );
if ( this.databasesInterface != null ) {
addConnection = new ToolItem( treeTb, SWT.PUSH );
addConnection.setImage( GUIResource.getInstance().getImageAdd() );
addConnection.setToolTipText( BaseMessages.getString( PKG, "Add.Datasource.Label" ) );
addConnection.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent event ) {
addDataSource();
}
} );
}
FormData fd = new FormData();
fd.right = new FormAttachment( 100 );
fd.top = new FormAttachment( 0, 0 );
treeTb.setLayoutData( fd );
Label wlFilter = new Label( shell, SWT.RIGHT );
props.setLook( wlFilter );
wlFilter.setText( BaseMessages.getString( PKG, "EnterSelectionDialog.FilterString.Label" ) );
FormData fdlFilter = new FormData();
fdlFilter.top = new FormAttachment( 0, 5 );
fdlFilter.right = new FormAttachment( treeTb, -5 );
wlFilter.setLayoutData( fdlFilter );
searchText.addSelectionListener( new SelectionAdapter() {
public void widgetDefaultSelected( SelectionEvent e ) {
updateFilter();
}
} );
// From step line
wlSelection = new Label( shell, SWT.NONE );
wlSelection.setText( lineText );
props.setLook( wlSelection );
fdlSelection = new FormData();
fdlSelection.left = new FormAttachment( 0, 0 );
fdlSelection.top = new FormAttachment( treeTb, 10 );
wlSelection.setLayoutData( fdlSelection );
} else {
// From step line
wlSelection = new Label( shell, SWT.NONE );
wlSelection.setText( lineText );
props.setLook( wlSelection );
fdlSelection = new FormData();
fdlSelection.left = new FormAttachment( 0, 0 );
wlSelection.setLayoutData( fdlSelection );
}
int options = SWT.LEFT | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL;
if ( multi ) {
options |= SWT.MULTI;
} else {
options |= SWT.SINGLE;
}
wSelection = new List( shell, options );
for ( int i = 0; i < choices.length; i++ ) {
wSelection.add( choices[i] );
}
if ( selectedNrs != null ) {
wSelection.select( selectedNrs );
wSelection.showSelection();
}
if ( fixed ) {
props.setLook( wSelection, Props.WIDGET_STYLE_FIXED );
} else {
props.setLook( wSelection );
}
// Some buttons
wOK = new Button( shell, SWT.PUSH );
if ( viewOnly ) {
wOK.setText( BaseMessages.getString( PKG, "System.Button.Close" ) );
} else {
wOK.setText( BaseMessages.getString( PKG, "System.Button.OK" ) );
}
lsOK = new Listener() {
public void handleEvent( Event e ) {
ok();
}
};
wOK.addListener( SWT.Selection, lsOK );
Button[] buttons = new Button[] { wOK };
if ( !viewOnly ) {
wCancel = new Button( shell, SWT.PUSH );
wCancel.setText( BaseMessages.getString( PKG, "System.Button.Cancel" ) );
lsCancel = new Listener() {
public void handleEvent( Event e ) {
cancel();
}
};
wCancel.addListener( SWT.Selection, lsCancel );
buttons = new Button[] { wOK, wCancel };
}
BaseStepDialog.positionBottomRightButtons( shell, buttons, margin, null );
Control nextControl = wOK;
if ( constant != null ) {
wConstantValue = new TextVar( variableSpace, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER );
if ( !Utils.isEmpty( constant ) ) {
wConstantValue.setText( constant );
}
props.setLook( wConstantValue );
FormData fdConstantValue = new FormData();
fdConstantValue.left = new FormAttachment( 0, 0 );
fdConstantValue.bottom = new FormAttachment( wOK, -10 );
fdConstantValue.right = new FormAttachment( 100, 0 );
wConstantValue.setLayoutData( fdConstantValue );
wbUseConstant = new Button( shell, SWT.CHECK );
props.setLook( wbUseConstant );
wbUseConstant.setText( BaseMessages.getString( PKG, "EnterSelectionDialog.UseConstant.Label" ) );
wbUseConstant.setSelection( !Utils.isEmpty( constant ) );
nextControl = wbUseConstant;
FormData fdUseConstant = new FormData();
fdUseConstant.left = new FormAttachment( 0, 0 );
fdUseConstant.bottom = new FormAttachment( wConstantValue, -5 );
wbUseConstant.setLayoutData( fdUseConstant );
wbUseConstant.addSelectionListener( new SelectionAdapter() {
@Override public void widgetSelected( SelectionEvent selectionEvent ) {
super.widgetSelected( selectionEvent );
setActive();
}
} );
setActive();
}
fdSelection = new FormData();
fdSelection.left = new FormAttachment( 0, 0 );
fdSelection.right = new FormAttachment( 100, 0 );
fdSelection.top = new FormAttachment( wlSelection, 5 );
fdSelection.bottom = new FormAttachment( nextControl, -10 );
wSelection.setLayoutData( fdSelection );
// Add listeners
lsDef = new SelectionAdapter() {
public void widgetDefaultSelected( SelectionEvent e ) {
ok();
}
};
wSelection.addSelectionListener( lsDef );
wSelection.addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e ) {
if ( e.character == SWT.CR ) {
ok();
}
}
} );
// 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 );
wOK.setFocus();
shell.open();
while ( !shell.isDisposed() ) {
if ( !display.readAndDispatch() ) {
display.sleep();
}
}
return selection;
}
private void setActive() {
wSelection.setEnabled( !wbUseConstant.getSelection() );
wConstantValue.setEnabled( wbUseConstant.getSelection() );
}
public String openRepoDialog() {
Shell parent = getParent();
Display display = parent.getDisplay();
shell =
new Shell( parent, SWT.DIALOG_TRIM | ( modal ? SWT.APPLICATION_MODAL | SWT.SHEET : SWT.NONE ) | SWT.MIN
| SWT.MAX );
props.setLook( shell );
FormLayout formLayout = new FormLayout();
formLayout.marginWidth = Const.FORM_MARGIN;
formLayout.marginHeight = Const.FORM_MARGIN;
shell.setLayout( formLayout );
shell.setText( shellText );
shell.setImage( GUIResource.getInstance().getImageSpoon() );
wlSelection = new Label( shell, SWT.NONE );
wlSelection.setText( lineText );
props.setLook( wlSelection );
fdlSelection = new FormData();
fdlSelection.left = new FormAttachment( 0, 10 );
fdlSelection.top = new FormAttachment( 0, 10 );
wlSelection.setLayoutData( fdlSelection );
int options = SWT.LEFT | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL;
wSelection = new List( shell, options );
String pentRepo = "";
boolean found = false;
for ( int i = 0; i < choices.length; i++ ) {
if ( choices[i] != null && choices[i].startsWith( BaseMessages.getString( PKG,
"EnterSelectionDialog.PentahoRepo" ) ) ) {
pentRepo = choices[i];
found = true;
} else {
wSelection.add( choices[i] );
}
}
if ( found ) {
wSelection.add( pentRepo, 0 );
wSelection.select( 0 );
}
int width = ( Const.isOSX() ? 75 : 70 );
Label separator = new Label( shell, SWT.SEPARATOR | SWT.HORIZONTAL );
FormData fd_separator = new FormData();
fd_separator.top = new FormAttachment( wSelection, 35 );
fd_separator.right = new FormAttachment( 100, -10 );
fd_separator.left = new FormAttachment( 0, 10 );
separator.setLayoutData( fd_separator );
Button btnHelp = new Button( shell, SWT.PUSH );
btnHelp.setImage( GUIResource.getInstance().getImageHelpWeb() );
FormData fd_btnHelp = new FormData();
fd_btnHelp.top = new FormAttachment( separator, 12 );
fd_btnHelp.left = new FormAttachment( 0, 10 );
fd_btnHelp.bottom = new FormAttachment( 100, -10 );
fd_btnHelp.width = ( Const.isOSX() ? 85 : 75 );
btnHelp.setLayoutData( fd_btnHelp );
btnHelp.setText( BaseMessages.getString( PKG, "System.Button.Help" ) );
btnHelp.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent arg0 ) {
HelpUtils.openHelpDialog( shell,
BaseMessages.getString( PKG, "EnterSelectionDialog.Help.Title" ),
Const.getDocUrl( BaseMessages.getString( PKG, "EnterSelectionDialog.Help" ) ),
BaseMessages.getString( PKG, "EnterSelectionDialog.Help.Header" ) );
}
} );
wCancel = new Button( shell, SWT.PUSH );
FormData fd_wCancel = new FormData();
fd_wCancel.top = new FormAttachment( separator, 12 );
fd_wCancel.right = new FormAttachment( 100, -10 );
fd_wCancel.bottom = new FormAttachment( 100, -10 );
fd_wCancel.width = width;
wCancel.setLayoutData( fd_wCancel );
wCancel.setText( BaseMessages.getString( PKG, "System.Button.Cancel" ).trim() );
lsCancel = new Listener() {
public void handleEvent( Event e ) {
cancel();
}
};
wCancel.addListener( SWT.Selection, lsCancel );
wOK = new Button( shell, SWT.PUSH );
wOK.setText( BaseMessages.getString( PKG, "System.Button.OK" ) );
FormData fd_wOK = new FormData();
fd_wOK.top = new FormAttachment( separator, 12 );
fd_wOK.right = new FormAttachment( wCancel, -5 );
fd_wOK.bottom = new FormAttachment( 100, -10 );
fd_wOK.width = width;
wOK.setLayoutData( fd_wOK );
lsOK = new Listener() {
public void handleEvent( Event e ) {
ok();
}
};
wOK.addListener( SWT.Selection, lsOK );
fdSelection = new FormData();
fdSelection.left = new FormAttachment( 0, 10 );
fdSelection.right = new FormAttachment( 100, -10 );
fdSelection.top = new FormAttachment( wlSelection, 10 );
fdSelection.bottom = new FormAttachment( separator, -12 );
wSelection.setLayoutData( fdSelection );
lsDef = new SelectionAdapter() {
public void widgetDefaultSelected( SelectionEvent e ) {
ok();
}
};
wSelection.addSelectionListener( lsDef );
wSelection.addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e ) {
if ( e.character == SWT.CR ) {
ok();
}
}
} );
// 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 );
wOK.setFocus();
shell.pack();
shell.open();
while ( !shell.isDisposed() ) {
if ( !display.readAndDispatch() ) {
display.sleep();
}
}
return selection;
}
public void dispose() {
props.setScreen( new WindowProperty( shell ) );
shell.dispose();
}
public void getData() {
}
private void cancel() {
selection = null;
dispose();
}
private void ok() {
if ( constant != null && wbUseConstant.getSelection() ) {
selection = wConstantValue.getText();
} else if ( wSelection.getSelectionCount() > 0 ) {
selection = wSelection.getSelection()[0];
selectionNr = wSelection.getSelectionIndices()[0];
if ( quickSearch ) {
for ( int i = 0; i < choices.length; i++ ) {
if ( choices[i].equals( selection ) ) {
selectionNr = i;
}
}
}
// We need to handle the indices properly. If a filter is applied, the wSelection will differ from choices
// So we have to get the current index from choices and store it in the indices
String[] selections = wSelection.getSelection();
boolean found = false;
indices = new int[selections.length];
for ( int i = 0; i < selections.length; i++ ) {
found = false;
for ( int j = 0; j < choices.length; j++ ) {
if ( selections[i].equals( choices[j] ) ) {
indices[i] = j;
found = true;
break;
}
}
}
if ( !found ) {
indices = wSelection.getSelectionIndices();
}
} else {
selection = null;
selectionNr = -1;
indices = new int[0];
}
dispose();
}
public int getSelectionNr( String str ) {
for ( int i = 0; i < choices.length; i++ ) {
if ( choices[i].equalsIgnoreCase( str ) ) {
return i;
}
}
return -1;
}
public int getSelectionNr() {
return selectionNr;
}
public boolean isMulti() {
return multi;
}
public void setMulti( boolean multi ) {
this.multi = multi;
}
public int[] getSelectionIndeces() {
return indices;
}
/**
* @return the fixed
*/
public boolean isFixed() {
return fixed;
}
/**
* @param fixed
* the fixed to set
*/
public void setFixed( boolean fixed ) {
this.fixed = fixed;
}
/**
* @return the selectedNrs
*/
public int[] getSelectedNrs() {
return selectedNrs;
}
/**
* @param selectedNrs
* the selectedNrs to set
*/
public void setSelectedNrs( int[] selectedNrs ) {
this.selectedNrs = selectedNrs;
}
protected void updateFilter() {
pattern = null;
filterString = null;
if ( searchText != null && !searchText.isDisposed() && !Utils.isEmpty( searchText.getText() ) ) {
if ( wbRegex.getSelection() ) {
pattern = Pattern.compile( searchText.getText() );
} else {
filterString = searchText.getText().toUpperCase();
}
}
refresh();
}
protected void addDataSource() {
Spoon theSpoon = Spoon.getInstance();
SpoonDBDelegate theDelegate = new SpoonDBDelegate( theSpoon );
theDelegate.newConnection( this.databasesInterface );
ArrayList<DatabaseMeta> theDatabases = new ArrayList<DatabaseMeta>();
theDatabases.addAll( this.databasesInterface.getDatabases() );
String[] theNames = new String[theDatabases.size()];
for ( int i = 0; i < theDatabases.size(); i++ ) {
theNames[i] = theDatabases.get( i ).getName();
}
this.choices = theNames;
refresh();
}
private void refresh() {
wSelection.removeAll();
for ( int i = 0; i < choices.length; i++ ) {
if ( quickSearch ) {
if ( wbRegex.getSelection() ) {
// use regex
if ( pattern != null ) {
Matcher matcher = pattern.matcher( choices[i] );
if ( matcher.matches() ) {
wSelection.add( choices[i] );
}
} else {
wSelection.add( choices[i] );
}
} else {
if ( filterString != null ) {
if ( choices[i].toUpperCase().contains( filterString ) ) {
wSelection.add( choices[i] );
}
} else {
wSelection.add( choices[i] );
}
}
} else {
wSelection.add( choices[i] );
}
}
wSelection.redraw();
/*
* selectedNrs = new int[] {}; if (selectedNrs!=null){ wSelection.select(selectedNrs); wSelection.showSelection(); }
*/
}
}