Java tutorial
/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Hitachi Vantara : 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; } }