/*! ******************************************************************************
*
* 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.core.dialog;
import java.util.Hashtable;
import java.util.StringTokenizer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
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.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
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.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
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.pentaho.di.core.Const;
import org.pentaho.di.i18n.BaseMessages;
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.trans.step.BaseStepDialog;
/**
* This dialogs allows you to select a number of items from a list of strings.
*
* @author Matt
* @since 21-10-2004
*/
public class EnterListDialog extends Dialog {
private static Class<?> PKG = EnterListDialog.class; // for i18n purposes, needed by Translator2!!
private PropsUI props;
private String[] input;
private String[] retval;
private Hashtable<Integer, String> selection;
private Shell shell;
private List wListSource, wListDest;
private Label wlListSource, wlListDest;
private Button wOK;
private Button wCancel;
private Button wAddOne, wAddAll, wRemoveAll, wRemoveOne;
private boolean opened;
public EnterListDialog( Shell parent, int style, String[] input ) {
super( parent, style );
this.props = PropsUI.getInstance();
this.input = input;
this.retval = null;
selection = new Hashtable<Integer, String>();
opened = false;
}
public String[] open() {
Shell parent = getParent();
shell = new Shell( parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN );
props.setLook( shell );
shell.setImage( GUIResource.getInstance().getImageTransGraph() );
shell.setText( BaseMessages.getString( PKG, "EnterListDialog.Title" ) );
shell.setLayout( new FormLayout() );
int margin = Const.MARGIN;
// //////////////////////////////////////////////////
// Top & Bottom regions.
// //////////////////////////////////////////////////
Composite top = new Composite( shell, SWT.NONE );
FormLayout topLayout = new FormLayout();
topLayout.marginHeight = margin;
topLayout.marginWidth = margin;
top.setLayout( topLayout );
FormData fdTop = new FormData();
fdTop.left = new FormAttachment( 0, 0 );
fdTop.top = new FormAttachment( 0, 0 );
fdTop.right = new FormAttachment( 100, 0 );
fdTop.bottom = new FormAttachment( 100, -50 );
top.setLayoutData( fdTop );
props.setLook( top );
Composite bottom = new Composite( shell, SWT.NONE );
bottom.setLayout( new FormLayout() );
FormData fdBottom = new FormData();
fdBottom.left = new FormAttachment( 0, 0 );
fdBottom.top = new FormAttachment( top, 0 );
fdBottom.right = new FormAttachment( 100, 0 );
fdBottom.bottom = new FormAttachment( 100, 0 );
bottom.setLayoutData( fdBottom );
props.setLook( bottom );
// //////////////////////////////////////////////////
// Sashform
// //////////////////////////////////////////////////
SashForm sashform = new SashForm( top, SWT.HORIZONTAL );
sashform.setLayout( new FormLayout() );
FormData fdSashform = new FormData();
fdSashform.left = new FormAttachment( 0, 0 );
fdSashform.top = new FormAttachment( 0, 0 );
fdSashform.right = new FormAttachment( 100, 0 );
fdSashform.bottom = new FormAttachment( 100, 0 );
sashform.setLayoutData( fdSashform );
// ////////////////////////
// / LEFT
// ////////////////////////
Composite leftsplit = new Composite( sashform, SWT.NONE );
leftsplit.setLayout( new FormLayout() );
FormData fdLeftsplit = new FormData();
fdLeftsplit.left = new FormAttachment( 0, 0 );
fdLeftsplit.top = new FormAttachment( 0, 0 );
fdLeftsplit.right = new FormAttachment( 100, 0 );
fdLeftsplit.bottom = new FormAttachment( 100, 0 );
leftsplit.setLayoutData( fdLeftsplit );
props.setLook( leftsplit );
// Source list to the left...
wlListSource = new Label( leftsplit, SWT.NONE );
wlListSource.setText( BaseMessages.getString( PKG, "EnterListDialog.AvailableItems.Label" ) );
props.setLook( wlListSource );
FormData fdlListSource = new FormData();
fdlListSource.left = new FormAttachment( 0, 0 );
fdlListSource.top = new FormAttachment( 0, 0 );
wlListSource.setLayoutData( fdlListSource );
wListSource = new List( leftsplit, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL );
props.setLook( wListSource );
FormData fdListSource = new FormData();
fdListSource.left = new FormAttachment( 0, 0 );
fdListSource.top = new FormAttachment( wlListSource, 0 );
fdListSource.right = new FormAttachment( 100, 0 );
fdListSource.bottom = new FormAttachment( 100, 0 );
wListSource.setLayoutData( fdListSource );
// /////////////////////////
// MIDDLE
// /////////////////////////
Composite compmiddle = new Composite( sashform, SWT.NONE );
compmiddle.setLayout( new FormLayout() );
FormData fdCompMiddle = new FormData();
fdCompMiddle.left = new FormAttachment( 0, 0 );
fdCompMiddle.top = new FormAttachment( 0, 0 );
fdCompMiddle.right = new FormAttachment( 100, 0 );
fdCompMiddle.bottom = new FormAttachment( 100, 0 );
compmiddle.setLayoutData( fdCompMiddle );
props.setLook( compmiddle );
Composite gButtonGroup = new Composite( compmiddle, SWT.NONE );
GridLayout gridLayout = new GridLayout( 1, false );
gButtonGroup.setLayout( gridLayout );
wAddOne = new Button( gButtonGroup, SWT.PUSH );
wAddOne.setText( " > " );
wAddOne.setToolTipText( BaseMessages.getString( PKG, "EnterListDialog.AddOne.Tooltip" ) );
wAddAll = new Button( gButtonGroup, SWT.PUSH );
wAddAll.setText( " >> " );
wAddAll.setToolTipText( BaseMessages.getString( PKG, "EnterListDialog.AddAll.Tooltip" ) );
wRemoveOne = new Button( gButtonGroup, SWT.PUSH );
wRemoveOne.setText( " < " );
wRemoveOne.setToolTipText( BaseMessages.getString( PKG, "EnterListDialog.RemoveOne.Tooltip" ) );
wRemoveAll = new Button( gButtonGroup, SWT.PUSH );
wRemoveAll.setText( " << " );
wRemoveAll.setToolTipText( BaseMessages.getString( PKG, "EnterListDialog.RemoveAll.Tooltip" ) );
GridData gdAddOne = new GridData( GridData.FILL_BOTH );
wAddOne.setLayoutData( gdAddOne );
GridData gdAddAll = new GridData( GridData.FILL_BOTH );
wAddAll.setLayoutData( gdAddAll );
GridData gdRemoveAll = new GridData( GridData.FILL_BOTH );
wRemoveAll.setLayoutData( gdRemoveAll );
GridData gdRemoveOne = new GridData( GridData.FILL_BOTH );
wRemoveOne.setLayoutData( gdRemoveOne );
FormData fdButtonGroup = new FormData();
wAddAll.pack(); // get a size
fdButtonGroup.left = new FormAttachment( 50, -( wAddAll.getSize().x / 2 ) - 5 );
fdButtonGroup.top = new FormAttachment( 30, 0 );
gButtonGroup.setBackground( shell.getBackground() ); // the default looks ugly
gButtonGroup.setLayoutData( fdButtonGroup );
// ///////////////////////////////
// RIGHT
// ///////////////////////////////
Composite rightsplit = new Composite( sashform, SWT.NONE );
rightsplit.setLayout( new FormLayout() );
FormData fdRightsplit = new FormData();
fdRightsplit.left = new FormAttachment( 0, 0 );
fdRightsplit.top = new FormAttachment( 0, 0 );
fdRightsplit.right = new FormAttachment( 100, 0 );
fdRightsplit.bottom = new FormAttachment( 100, 0 );
rightsplit.setLayoutData( fdRightsplit );
props.setLook( rightsplit );
wlListDest = new Label( rightsplit, SWT.NONE );
wlListDest.setText( BaseMessages.getString( PKG, "EnterListDialog.Selection.Label" ) );
props.setLook( wlListDest );
FormData fdlListDest = new FormData();
fdlListDest.left = new FormAttachment( 0, 0 );
fdlListDest.top = new FormAttachment( 0, 0 );
wlListDest.setLayoutData( fdlListDest );
wListDest = new List( rightsplit, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL );
props.setLook( wListDest );
FormData fdListDest = new FormData();
fdListDest.left = new FormAttachment( 0, 0 );
fdListDest.top = new FormAttachment( wlListDest, 0 );
fdListDest.right = new FormAttachment( 100, 0 );
fdListDest.bottom = new FormAttachment( 100, 0 );
wListDest.setLayoutData( fdListDest );
sashform.setWeights( new int[] { 40, 16, 40 } );
// //////////////////////////////////////////////////////////////
// THE BOTTOM BUTTONS...
// //////////////////////////////////////////////////////////////
wOK = new Button( bottom, SWT.PUSH );
wOK.setText( BaseMessages.getString( PKG, "System.Button.OK" ) );
wCancel = new Button( bottom, SWT.PUSH );
wCancel.setText( BaseMessages.getString( PKG, "System.Button.Cancel" ) );
FormData fdOK = new FormData();
FormData fdCancel = new FormData();
fdOK.left = new FormAttachment( 35, 0 );
fdOK.bottom = new FormAttachment( 100, 0 );
wOK.setLayoutData( fdOK );
fdCancel.left = new FormAttachment( wOK, 10 );
fdCancel.bottom = new FormAttachment( 100, 0 );
wCancel.setLayoutData( fdCancel );
// Add listeners
wCancel.addListener( SWT.Selection, new Listener() {
public void handleEvent( Event e ) {
dispose();
}
} );
// Add listeners
wOK.addListener( SWT.Selection, new Listener() {
public void handleEvent( Event e ) {
handleOK();
}
} );
// Drag & Drop for steps
Transfer[] ttypes = new Transfer[] { TextTransfer.getInstance() };
DragSource ddSource = new DragSource( wListSource, DND.DROP_MOVE | DND.DROP_COPY );
ddSource.setTransfer( ttypes );
ddSource.addDragListener( new DragSourceListener() {
public void dragStart( DragSourceEvent event ) {
}
public void dragSetData( DragSourceEvent event ) {
String[] ti = wListSource.getSelection();
String data = new String();
for ( int i = 0; i < ti.length; i++ ) {
data += ti[i] + Const.CR;
}
event.data = data;
}
public void dragFinished( DragSourceEvent event ) {
}
} );
DropTarget ddTarget = new DropTarget( wListDest, DND.DROP_MOVE | DND.DROP_COPY );
ddTarget.setTransfer( ttypes );
ddTarget.addDropListener( new DropTargetListener() {
public void dragEnter( DropTargetEvent event ) {
}
public void dragLeave( DropTargetEvent event ) {
}
public void dragOperationChanged( DropTargetEvent event ) {
}
public void dragOver( DropTargetEvent event ) {
}
public void drop( DropTargetEvent event ) {
if ( event.data == null ) { // no data to copy, indicate failure in event.detail
event.detail = DND.DROP_NONE;
return;
}
StringTokenizer strtok = new StringTokenizer( (String) event.data, Const.CR );
while ( strtok.hasMoreTokens() ) {
String source = strtok.nextToken();
addToDestination( source );
}
}
public void dropAccept( DropTargetEvent event ) {
}
} );
wListSource.addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e ) {
if ( e.character == SWT.CR ) {
addToSelection( wListSource.getSelection() );
}
}
} );
wListDest.addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e ) {
if ( e.character == SWT.CR ) {
delFromSelection( wListDest.getSelection() );
}
}
} );
// Double click adds to destination.
wListSource.addSelectionListener( new SelectionAdapter() {
public void widgetDefaultSelected( SelectionEvent e ) {
addToSelection( wListSource.getSelection() );
}
} );
// Double click adds to source
wListDest.addSelectionListener( new SelectionAdapter() {
public void widgetDefaultSelected( SelectionEvent e ) {
delFromSelection( wListDest.getSelection() );
}
} );
wAddOne.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
addToSelection( wListSource.getSelection() );
}
} );
wRemoveOne.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
delFromSelection( wListDest.getSelection() );
}
} );
wAddAll.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
addToSelection( wListSource.getItems() );
}
} );
wRemoveAll.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
delFromSelection( wListDest.getItems() );
}
} );
opened = true;
getData();
BaseStepDialog.setSize( shell );
shell.open();
Display display = parent.getDisplay();
while ( !shell.isDisposed() ) {
if ( !display.readAndDispatch() ) {
display.sleep();
}
}
return retval;
}
public void getData() {
if ( !opened ) {
return;
}
wListSource.removeAll();
wListDest.removeAll();
for ( int i = 0; i < input.length; i++ ) {
Integer idx = Integer.valueOf( i );
String str = selection.get( idx );
if ( str == null ) {
// Not selected: show in source!
wListSource.add( input[i] );
} else {
// Selected, show in destination!
wListDest.add( input[i] );
}
}
}
public void addToSelection( String[] string ) {
for ( int i = 0; i < string.length; i++ ) {
addToDestination( string[i] );
}
}
public void delFromSelection( String[] string ) {
for ( int i = 0; i < string.length; i++ ) {
delFromDestination( string[i] );
}
}
public void addToDestination( String string ) {
int idxInput = Const.indexOfString( string, input );
selection.put( Integer.valueOf( idxInput ), string );
getData();
}
public void delFromDestination( String string ) {
int idxInput = Const.indexOfString( string, input );
selection.remove( Integer.valueOf( idxInput ) );
getData();
}
public void dispose() {
WindowProperty winprop = new WindowProperty( shell );
props.setScreen( winprop );
shell.dispose();
}
public void handleOK() {
retval = wListDest.getItems();
dispose();
}
}