/*! ******************************************************************************
*
* 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.core.widget;
import org.eclipse.jface.window.DefaultToolTip;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
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.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.gui.GUIResource;
import java.util.Arrays;
import java.util.Comparator;
public class ControlSpaceKeyAdapter extends KeyAdapter {
private static Class<?> PKG = ControlSpaceKeyAdapter.class; // for i18n purposes, needed by Translator2!!
private static final PropsUI props = PropsUI.getInstance();
private GetCaretPositionInterface getCaretPositionInterface;
private InsertTextInterface insertTextInterface;
private VariableSpace variables;
private Control control;
/**
* @param space
* @param control
* a Text or CCombo box object
*/
public ControlSpaceKeyAdapter( final VariableSpace space, final Control control ) {
this( space, control, null, null );
}
/**
*
* @param space
* @param control
* a Text or CCombo box object
* @param getCaretPositionInterface
* @param insertTextInterface
*/
public ControlSpaceKeyAdapter( VariableSpace space, final Control control,
final GetCaretPositionInterface getCaretPositionInterface, final InsertTextInterface insertTextInterface ) {
this.variables = space;
this.control = control;
this.getCaretPositionInterface = getCaretPositionInterface;
this.insertTextInterface = insertTextInterface;
}
/**
* PDI-1284 in chinese window, Ctrl-SPACE is reversed by system for input chinese character. use Ctrl-ALT-SPACE
* instead.
*
* @param e
* @return
*/
private boolean isHotKey( KeyEvent e ) {
if ( System.getProperty( "user.language" ).equals( "zh" ) ) {
return e.character == ' ' && ( ( e.stateMask & SWT.CONTROL ) != 0 ) && ( ( e.stateMask & SWT.ALT ) != 0 );
} else if ( System.getProperty( "os.name" ).startsWith( "Mac OS X" ) ) {
return e.character == ' ' && ( ( e.stateMask & SWT.MOD1 ) != 0 ) && ( ( e.stateMask & SWT.ALT ) == 0 );
} else {
return e.character == ' ' && ( ( e.stateMask & SWT.CONTROL ) != 0 ) && ( ( e.stateMask & SWT.ALT ) == 0 );
}
}
public void keyPressed( KeyEvent e ) {
// CTRL-<SPACE> --> Insert a variable
if ( isHotKey( e ) ) {
e.doit = false;
// textField.setData(TRUE) indicates we have transitioned from the textbox to list mode...
// This will be set to false when the list selection has been processed
// and the list is being disposed of.
control.setData( Boolean.TRUE );
final int position;
if ( getCaretPositionInterface != null ) {
position = getCaretPositionInterface.getCaretPosition();
} else {
position = -1;
}
// Drop down a list of variables...
//
Rectangle bounds = control.getBounds();
Point location = GUIResource.calculateControlPosition( control );
final Shell shell = new Shell( control.getShell(), SWT.NONE );
shell.setSize( bounds.width > 300 ? bounds.width : 300, 200 );
shell.setLocation( location.x, location.y + bounds.height );
shell.setLayout( new FillLayout() );
final List list = new List( shell, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL );
props.setLook( list );
list.setItems( getVariableNames( variables ) );
final DefaultToolTip toolTip = new DefaultToolTip( list, ToolTip.RECREATE, true );
toolTip.setImage( GUIResource.getInstance().getImageVariable() );
toolTip.setHideOnMouseDown( true );
toolTip.setRespectMonitorBounds( true );
toolTip.setRespectDisplayBounds( true );
toolTip.setPopupDelay( 350 );
list.addSelectionListener( new SelectionAdapter() {
// Enter or double-click: picks the variable
//
public synchronized void widgetDefaultSelected( SelectionEvent e ) {
applyChanges( shell, list, control, position, insertTextInterface );
}
// Select a variable name: display the value in a tool tip
//
public void widgetSelected( SelectionEvent event ) {
if ( list.getSelectionCount() <= 0 ) {
return;
}
String name = list.getSelection()[0];
String value = variables.getVariable( name );
Rectangle shellBounds = shell.getBounds();
String message = BaseMessages.getString( PKG, "TextVar.VariableValue.Message", name, value );
if ( name.startsWith( Const.INTERNAL_VARIABLE_PREFIX ) ) {
message += BaseMessages.getString( PKG, "TextVar.InternalVariable.Message" );
}
toolTip.setText( message );
toolTip.hide();
toolTip.show( new Point( shellBounds.width, 0 ) );
}
} );
list.addKeyListener( new KeyAdapter() {
public synchronized void keyPressed( KeyEvent e ) {
if ( e.keyCode == SWT.CR && ( ( e.keyCode & SWT.CONTROL ) == 0 ) && ( ( e.keyCode & SWT.SHIFT ) == 0 ) ) {
applyChanges( shell, list, control, position, insertTextInterface );
}
}
} );
list.addFocusListener( new FocusAdapter() {
public void focusLost( FocusEvent event ) {
shell.dispose();
if ( !control.isDisposed() ) {
control.setData( Boolean.FALSE );
}
}
} );
shell.open();
}
}
private static final void applyChanges( Shell shell, List list, Control control, int position,
InsertTextInterface insertTextInterface ) {
String selection =
list.getSelection()[0].contains( Const.getDeprecatedPrefix() )
? list.getSelection()[0].replace( Const.getDeprecatedPrefix(), "" )
: list.getSelection()[0];
String extra = "${" + selection + "}";
if ( insertTextInterface != null ) {
insertTextInterface.insertText( extra, position );
} else {
if ( control.isDisposed() ) {
return;
}
if ( list.getSelectionCount() <= 0 ) {
return;
}
if ( control instanceof Text ) {
( (Text) control ).insert( extra );
} else if ( control instanceof CCombo ) {
CCombo combo = (CCombo) control;
combo.setText( extra ); // We can't know the location of the cursor yet. All we can do is overwrite.
} else if ( control instanceof StyledTextComp ) {
( (StyledTextComp) control ).insert( extra );
} else if ( control instanceof StyledText ) {
( (StyledText) control ).insert( extra );
}
}
if ( !shell.isDisposed() ) {
shell.dispose();
}
if ( !control.isDisposed() ) {
control.setData( Boolean.FALSE );
}
}
public static final String[] getVariableNames( VariableSpace space ) {
String[] variableNames = space.listVariables();
for ( int i = 0; i < variableNames.length; i++ ) {
for ( int j = 0; j < Const.DEPRECATED_VARIABLES.length; j++ ) {
if ( variableNames[i].equals( Const.DEPRECATED_VARIABLES[j] ) ) {
variableNames[i] = variableNames[i] + Const.getDeprecatedPrefix();
break;
}
}
}
Arrays.sort( variableNames, new Comparator<String>() {
public int compare( String var1, String var2 ) {
if ( var1.endsWith( Const.getDeprecatedPrefix() ) && var2.endsWith( Const.getDeprecatedPrefix() ) ) {
return 0;
}
if ( var1.endsWith( Const.getDeprecatedPrefix() ) && !var2.endsWith( Const.getDeprecatedPrefix() ) ) {
return 1;
}
if ( !var1.endsWith( Const.getDeprecatedPrefix() ) && var2.endsWith( Const.getDeprecatedPrefix() ) ) {
return -1;
}
return var1.compareTo( var2 );
}
} );
return variableNames;
}
public void setVariables( VariableSpace vars ) {
variables = vars;
}
}