org.pentaho.di.ui.trans.steps.multimerge.MultiMergeJoinDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.ui.trans.steps.multimerge.MultiMergeJoinDialog.java

Source

/*! ******************************************************************************
 *
 * 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.trans.steps.multimerge;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepDialogInterface;
import org.pentaho.di.trans.step.StepIOMetaInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.errorhandling.Stream;
import org.pentaho.di.trans.step.errorhandling.StreamIcon;
import org.pentaho.di.trans.step.errorhandling.StreamInterface;
import org.pentaho.di.trans.step.errorhandling.StreamInterface.StreamType;
import org.pentaho.di.trans.steps.multimerge.MultiMergeJoinMeta;
import org.pentaho.di.ui.core.gui.GUIResource;
import org.pentaho.di.ui.core.widget.ColumnInfo;
import org.pentaho.di.ui.core.widget.TableView;
import org.pentaho.di.ui.trans.step.BaseStepDialog;

public class MultiMergeJoinDialog extends BaseStepDialog implements StepDialogInterface {
    private static Class<?> PKG = MultiMergeJoinMeta.class; // for i18n purposes, needed by Translator2!!

    public static final String STRING_SORT_WARNING_PARAMETER = "MultiMergeJoinSortWarning";

    private CCombo[] wInputStepArray;
    private CCombo joinTypeCombo;
    private Text[] keyValTextBox;

    private Map<String, Integer> inputFields;
    private RowMetaInterface prev;
    private ColumnInfo[] ciKeys;

    private static final int margin = Const.MARGIN;

    private MultiMergeJoinMeta joinMeta;

    public MultiMergeJoinDialog(Shell parent, Object in, TransMeta tr, String sname) {
        super(parent, (BaseStepMeta) in, tr, sname);
        joinMeta = (MultiMergeJoinMeta) in;

        String[] inputStepNames = getInputStepNames();
        wInputStepArray = new CCombo[inputStepNames.length];
        keyValTextBox = new Text[inputStepNames.length];
    }

    private String[] getInputStepNames() {
        String[] inputStepNames = joinMeta.getInputSteps();
        ArrayList<String> nameList = new ArrayList<String>();
        if (inputStepNames != null) {
            Collections.addAll(nameList, inputStepNames);
        }

        String[] prevStepNames = transMeta.getPrevStepNames(stepname);
        if (prevStepNames != null) {
            String prevStepName;
            for (int i = 0; i < prevStepNames.length; i++) {
                prevStepName = prevStepNames[i];
                if (nameList.contains(prevStepName)) {
                    continue;
                }
                nameList.add(prevStepName);
            }
        }

        return nameList.toArray(new String[nameList.size()]);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.pentaho.di.trans.step.StepDialogInterface#open()
     */
    public String open() {
        Shell parent = getParent();
        Display display = parent.getDisplay();

        shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN | SWT.MAX);
        props.setLook(shell);
        setShellImage(shell, joinMeta);

        final ModifyListener lsMod = new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                joinMeta.setChanged();
            }
        };
        backupChanged = joinMeta.hasChanged();

        FormLayout formLayout = new FormLayout();
        formLayout.marginWidth = Const.FORM_MARGIN;
        formLayout.marginHeight = Const.FORM_MARGIN;

        shell.setLayout(formLayout);
        shell.setText(BaseMessages.getString(PKG, "MultiMergeJoinDialog.Shell.Label"));

        // int middle = props.getMiddlePct();

        wlStepname = new Label(shell, SWT.LEFT);
        wlStepname.setText(BaseMessages.getString(PKG, "MultiMergeJoinDialog.Stepname.Label"));
        props.setLook(wlStepname);
        fdlStepname = new FormData();
        fdlStepname.left = new FormAttachment(0, 0);
        fdlStepname.right = new FormAttachment(15, -margin);
        fdlStepname.top = new FormAttachment(0, margin);
        wlStepname.setLayoutData(fdlStepname);
        wStepname = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
        wStepname.setText(stepname);
        props.setLook(wStepname);
        wStepname.addModifyListener(lsMod);
        fdStepname = new FormData();
        fdStepname.left = new FormAttachment(15, 0);
        fdStepname.top = new FormAttachment(0, margin);
        fdStepname.right = new FormAttachment(35, 0);
        wStepname.setLayoutData(fdStepname);

        // create widgets for input stream and join key selections
        createInputStreamWidgets(lsMod);

        // create widgets for Join type
        createJoinTypeWidget(lsMod);

        // Some buttons
        wOK = new Button(shell, SWT.PUSH);
        wOK.setText(BaseMessages.getString(PKG, "System.Button.OK"));
        wCancel = new Button(shell, SWT.PUSH);
        wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel"));

        setButtonPositions(new Button[] { wOK, wCancel }, margin, null);

        // Add listeners
        lsCancel = new Listener() {
            public void handleEvent(Event e) {
                cancel();
            }
        };
        lsOK = new Listener() {
            public void handleEvent(Event e) {
                ok();
            }
        };

        wCancel.addListener(SWT.Selection, lsCancel);
        wOK.addListener(SWT.Selection, lsOK);

        /*
         * lsDef=new SelectionAdapter() { public void widgetDefaultSelected(SelectionEvent e) { ok(); } };
         *
         * wStepname.addSelectionListener( lsDef );
         */

        // Detect X or ALT-F4 or something that kills this window...
        shell.addShellListener(new ShellAdapter() {
            public void shellClosed(ShellEvent e) {
                cancel();
            }
        });

        // Set the shell size, based upon previous time...
        setSize();

        // get the data
        getData();
        joinMeta.setChanged(backupChanged);

        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        return stepname;
    }

    /**
     * Create widgets for join type selection
     *
     * @param lsMod
     */
    private void createJoinTypeWidget(final ModifyListener lsMod) {
        Label joinTypeLabel = new Label(shell, SWT.LEFT);
        joinTypeLabel.setText(BaseMessages.getString(PKG, "MultiMergeJoinDialog.Type.Label"));
        props.setLook(joinTypeLabel);
        FormData fdlType = new FormData();
        fdlType.left = new FormAttachment(0, 0);
        fdlType.right = new FormAttachment(15, -margin);
        if (wInputStepArray.length > 0) {
            fdlType.top = new FormAttachment(wInputStepArray[wInputStepArray.length - 1], margin);
        } else {
            fdlType.top = new FormAttachment(wStepname, margin);
        }
        joinTypeLabel.setLayoutData(fdlType);
        joinTypeCombo = new CCombo(shell, SWT.BORDER);
        props.setLook(joinTypeCombo);

        joinTypeCombo.setItems(MultiMergeJoinMeta.join_types);

        joinTypeCombo.addModifyListener(lsMod);
        FormData fdType = new FormData();
        if (wInputStepArray.length > 0) {
            fdType.top = new FormAttachment(wInputStepArray[wInputStepArray.length - 1], margin);
        } else {
            fdType.top = new FormAttachment(wStepname, margin);
        }
        fdType.left = new FormAttachment(15, 0);
        fdType.right = new FormAttachment(35, 0);
        joinTypeCombo.setLayoutData(fdType);
    }

    /**
     * create widgets for input stream and join keys
     *
     * @param lsMod
     */
    private void createInputStreamWidgets(final ModifyListener lsMod) {
        // Get the previous steps ...
        String[] inputSteps = getInputStepNames();
        for (int index = 0; index < inputSteps.length; index++) {
            Label wlStep;
            FormData fdlStep, fdStep1;

            wlStep = new Label(shell, SWT.LEFT);
            // wlStep1.setText(+i+".Label"));
            wlStep.setText(BaseMessages.getString(PKG, "MultiMergeJoinMeta.InputStep") + (index + 1));
            props.setLook(wlStep);
            fdlStep = new FormData();
            fdlStep.left = new FormAttachment(0, 0);
            fdlStep.right = new FormAttachment(15, -margin);
            if (index == 0) {
                fdlStep.top = new FormAttachment(wStepname, margin);
            } else {
                fdlStep.top = new FormAttachment(wInputStepArray[index - 1], margin);
            }

            wlStep.setLayoutData(fdlStep);
            wInputStepArray[index] = new CCombo(shell, SWT.BORDER);
            props.setLook(wInputStepArray[index]);

            wInputStepArray[index].setItems(inputSteps);

            wInputStepArray[index].addModifyListener(lsMod);
            fdStep1 = new FormData();
            fdStep1.left = new FormAttachment(15, 0);
            if (index == 0) {
                fdStep1.top = new FormAttachment(wStepname, margin);
            } else {
                fdStep1.top = new FormAttachment(wInputStepArray[index - 1], margin);
            }

            fdStep1.right = new FormAttachment(35, 0);
            wInputStepArray[index].setLayoutData(fdStep1);

            Label keyLabel = new Label(shell, SWT.LEFT);
            keyLabel.setText(BaseMessages.getString(PKG, "MultiMergeJoinMeta.JoinKeys"));
            props.setLook(keyLabel);
            FormData keyStep = new FormData();
            keyStep.left = new FormAttachment(35, margin + 5);
            keyStep.right = new FormAttachment(45, -margin);
            if (index == 0) {
                keyStep.top = new FormAttachment(wStepname, margin);
            } else {
                keyStep.top = new FormAttachment(wInputStepArray[index - 1], margin);
            }
            keyLabel.setLayoutData(keyStep);

            keyValTextBox[index] = new Text(shell, SWT.READ_ONLY | SWT.SINGLE | SWT.LEFT | SWT.BORDER);
            props.setLook(keyValTextBox[index]);
            keyValTextBox[index].setText("");
            keyValTextBox[index].addModifyListener(lsMod);
            FormData keyData = new FormData();
            keyData.left = new FormAttachment(45, margin + 5);
            keyData.right = new FormAttachment(65, -margin);
            if (index == 0) {
                keyData.top = new FormAttachment(wStepname, margin);
            } else {
                keyData.top = new FormAttachment(wInputStepArray[index - 1], margin);
            }
            keyValTextBox[index].setLayoutData(keyData);

            Button button = new Button(shell, SWT.PUSH);
            button.setText(BaseMessages.getString(PKG, "MultiMergeJoinMeta.SelectKeys"));
            // add listener
            button.addListener(SWT.Selection,
                    new ConfigureKeyButtonListener(this, keyValTextBox[index], index, lsMod));
            FormData buttonData = new FormData();
            buttonData.left = new FormAttachment(65, margin);
            buttonData.right = new FormAttachment(80, -margin);
            if (index == 0) {
                buttonData.top = new FormAttachment(wStepname, margin);
            } else {
                buttonData.top = new FormAttachment(wInputStepArray[index - 1], margin);
            }
            button.setLayoutData(buttonData);
        }
    }

    /**
     * "Configure join key" shell
     *
     * @param keyValTextBox
     * @param lsMod
     */
    private void configureKeys(final Text keyValTextBox, final int inputStreamIndex, ModifyListener lsMod) {
        inputFields = new HashMap<String, Integer>();

        final Shell subShell = new Shell(shell, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN | SWT.MAX);
        final FormLayout formLayout = new FormLayout();
        formLayout.marginWidth = 5;
        formLayout.marginHeight = 5;
        subShell.setLayout(formLayout);
        subShell.setSize(200, 150);
        subShell.setText(BaseMessages.getString(PKG, "MultiMergeJoinMeta.JoinKeys"));
        subShell.setImage(GUIResource.getInstance().getImageTransGraph());
        Label wlKeys = new Label(subShell, SWT.NONE);
        wlKeys.setText(BaseMessages.getString(PKG, "MultiMergeJoinDialog.Keys"));
        FormData fdlKeys = new FormData();
        fdlKeys.left = new FormAttachment(0, 0);
        fdlKeys.right = new FormAttachment(50, -margin);
        fdlKeys.top = new FormAttachment(0, margin);
        wlKeys.setLayoutData(fdlKeys);

        String[] keys = keyValTextBox.getText().split(",");
        int nrKeyRows = (keys != null ? keys.length : 1);

        ciKeys = new ColumnInfo[] {
                new ColumnInfo(BaseMessages.getString(PKG, "MultiMergeJoinDialog.ColumnInfo.KeyField"),
                        ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] { "" }, false), };

        final TableView wKeys = new TableView(transMeta, subShell,
                SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL, ciKeys, nrKeyRows, lsMod,
                props);

        FormData fdKeys = new FormData();
        fdKeys.top = new FormAttachment(wlKeys, margin);
        fdKeys.left = new FormAttachment(0, 0);
        fdKeys.bottom = new FormAttachment(100, -70);
        fdKeys.right = new FormAttachment(100, -margin);
        wKeys.setLayoutData(fdKeys);

        //
        // Search the fields in the background

        final Runnable runnable = new Runnable() {
            public void run() {
                try {
                    CCombo wInputStep = wInputStepArray[inputStreamIndex];
                    String stepName = wInputStep.getText();
                    StepMeta stepMeta = transMeta.findStep(stepName);
                    if (stepMeta != null) {
                        prev = transMeta.getStepFields(stepMeta);
                        if (prev != null) {
                            // Remember these fields...
                            for (int i = 0; i < prev.size(); i++) {
                                inputFields.put(prev.getValueMeta(i).getName(), Integer.valueOf(i));
                            }
                            setComboBoxes();
                        }
                    }
                } catch (KettleException e) {
                    logError(BaseMessages.getString(PKG, "System.Dialog.GetFieldsFailed.Message"));
                }
            }
        };
        Display.getDefault().asyncExec(runnable);

        Button getKeyButton = new Button(subShell, SWT.PUSH);
        getKeyButton.setText(BaseMessages.getString(PKG, "MultiMergeJoinDialog.KeyFields.Button"));
        FormData fdbKeys = new FormData();
        fdbKeys.top = new FormAttachment(wKeys, margin);
        fdbKeys.left = new FormAttachment(0, 0);
        fdbKeys.right = new FormAttachment(100, -margin);
        getKeyButton.setLayoutData(fdbKeys);
        getKeyButton.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent e) {
                BaseStepDialog.getFieldsFromPrevious(prev, wKeys, 1, new int[] { 1 }, new int[] {}, -1, -1, null);
            }
        });
        // Some buttons
        Button okButton = new Button(subShell, SWT.PUSH);
        okButton.setText(BaseMessages.getString(PKG, "System.Button.OK"));

        setButtonPositions(new Button[] { okButton }, margin, getKeyButton);

        okButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                int nrKeys = wKeys.nrNonEmpty();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < nrKeys; i++) {
                    TableItem item = wKeys.getNonEmpty(i);
                    sb.append(item.getText(1));
                    if (nrKeys > 1 && i != nrKeys - 1) {
                        sb.append(",");
                    }
                }
                keyValTextBox.setText(sb.toString());
                subShell.close();
            }
        });

        /*
         * SelectionAdapter lsDef=new SelectionAdapter() { public void widgetDefaultSelected(SelectionEvent e) { ok(); } };
         *
         * wStepname.addSelectionListener( lsDef );
         */

        // Detect X or ALT-F4 or something that kills this window...
        subShell.addShellListener(new ShellAdapter() {
            public void shellClosed(ShellEvent e) {

            }
        });

        for (int i = 0; i < keys.length; i++) {
            TableItem item = wKeys.table.getItem(i);
            if (keys[i] != null) {
                item.setText(1, keys[i]);
            }
        }

        subShell.pack();
        subShell.open();

    }

    protected void setComboBoxes() {
        // Something was changed in the row.
        //
        final Map<String, Integer> fields = new HashMap<String, Integer>();

        // Add the currentMeta fields...
        fields.putAll(inputFields);

        Set<String> keySet = fields.keySet();
        List<String> entries = new ArrayList<String>(keySet);

        String[] fieldNames = entries.toArray(new String[entries.size()]);

        Const.sortStrings(fieldNames);
        ciKeys[0].setComboValues(fieldNames);
    }

    /**
     * Copy information from the meta-data input to the dialog fields.
     */
    public void getData() {
        String[] inputStepNames = joinMeta.getInputSteps();
        if (inputStepNames != null) {
            String inputStepName;
            String[] keyFields = joinMeta.getKeyFields();
            String keyField;
            for (int i = 0; i < inputStepNames.length; i++) {
                inputStepName = Const.NVL(inputStepNames[i], "");
                wInputStepArray[i].setText(inputStepName);

                keyField = Const.NVL(i < keyFields.length ? keyFields[i] : null, "");
                keyValTextBox[i].setText(keyField);
            }

            String joinType = joinMeta.getJoinType();
            if (joinType != null && joinType.length() > 0) {
                joinTypeCombo.setText(joinType);
            } else {
                joinTypeCombo.setText(MultiMergeJoinMeta.join_types[0]);
            }
        }
        wStepname.selectAll();
        wStepname.setFocus();
    }

    private void cancel() {
        stepname = null;
        joinMeta.setChanged(backupChanged);
        dispose();
    }

    /**
     * Get the meta data
     *
     * @param meta
     */
    private void getMeta(MultiMergeJoinMeta meta) {
        StepIOMetaInterface stepIOMeta = meta.getStepIOMeta();
        List<StreamInterface> infoStreams = stepIOMeta.getInfoStreams();
        StreamInterface stream;
        String streamDescription;
        ArrayList<String> inputStepNameList = new ArrayList<String>();
        ArrayList<String> keyList = new ArrayList<String>();
        CCombo wInputStep;
        String inputStepName;
        for (int i = 0; i < wInputStepArray.length; i++) {
            wInputStep = wInputStepArray[i];
            inputStepName = wInputStep.getText();

            if (Utils.isEmpty(inputStepName)) {
                continue;
            }

            inputStepNameList.add(inputStepName);
            keyList.add(keyValTextBox[i].getText());

            if (infoStreams.size() < inputStepNameList.size()) {
                streamDescription = BaseMessages.getString(PKG, "MultiMergeJoin.InfoStream.Description");
                stream = new Stream(StreamType.INFO, null, streamDescription, StreamIcon.INFO, null);
                stepIOMeta.addStream(stream);
            }
        }

        int inputStepCount = inputStepNameList.size();
        meta.allocateInputSteps(inputStepCount);
        meta.allocateKeys(inputStepCount);

        String[] inputSteps = meta.getInputSteps();
        String[] keyFields = meta.getKeyFields();
        infoStreams = stepIOMeta.getInfoStreams();
        for (int i = 0; i < inputStepCount; i++) {
            inputStepName = inputStepNameList.get(i);
            inputSteps[i] = inputStepName;
            stream = infoStreams.get(i);
            stream.setStepMeta(transMeta.findStep(inputStepName));
            keyFields[i] = keyList.get(i);
        }

        meta.setJoinType(joinTypeCombo.getText());
    }

    private void ok() {
        if (Utils.isEmpty(wStepname.getText())) {
            return;
        }
        getMeta(joinMeta);
        // Show a warning (optional)
        if ("Y".equalsIgnoreCase(props.getCustomParameter(STRING_SORT_WARNING_PARAMETER, "Y"))) {
            MessageDialogWithToggle md = new MessageDialogWithToggle(shell,
                    BaseMessages.getString(PKG, "MultiMergeJoinDialog.InputNeedSort.DialogTitle"), null,
                    BaseMessages.getString(PKG, "MultiMergeJoinDialog.InputNeedSort.DialogMessage", Const.CR)
                            + Const.CR,
                    MessageDialog.WARNING,
                    new String[] { BaseMessages.getString(PKG, "MultiMergeJoinDialog.InputNeedSort.Option1") }, 0,
                    BaseMessages.getString(PKG, "MultiMergeJoinDialog.InputNeedSort.Option2"),
                    "N".equalsIgnoreCase(props.getCustomParameter(STRING_SORT_WARNING_PARAMETER, "Y")));
            MessageDialogWithToggle.setDefaultImage(GUIResource.getInstance().getImageSpoon());
            md.open();
            props.setCustomParameter(STRING_SORT_WARNING_PARAMETER, md.getToggleState() ? "N" : "Y");
            props.saveProps();
        }
        stepname = wStepname.getText(); // return value
        dispose();
    }

    /**
     * Listener for Configure Keys button
     *
     * @author A71481
     *
     */
    private static class ConfigureKeyButtonListener implements Listener {
        MultiMergeJoinDialog dialog;
        Text textBox;
        int inputStreamIndex;
        ModifyListener listener;

        public ConfigureKeyButtonListener(MultiMergeJoinDialog dialog, Text textBox, int streamIndex,
                ModifyListener lsMod) {
            this.dialog = dialog;
            this.textBox = textBox;
            this.listener = lsMod;
            this.inputStreamIndex = streamIndex;
        }

        @Override
        public void handleEvent(Event event) {
            dialog.configureKeys(textBox, inputStreamIndex, listener);
        }

    }

}