org.csstudio.trends.databrowser2.ui.AddPVDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.csstudio.trends.databrowser2.ui.AddPVDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Oak Ridge National Laboratory.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package org.csstudio.trends.databrowser2.ui;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.csstudio.autocomplete.ui.AutoCompleteTypes;
import org.csstudio.autocomplete.ui.AutoCompleteWidget;
import org.csstudio.trends.databrowser2.Activator;
import org.csstudio.trends.databrowser2.Messages;
import org.csstudio.trends.databrowser2.model.AxisConfig;
import org.csstudio.trends.databrowser2.model.Model;
import org.csstudio.trends.databrowser2.model.ModelItem;
import org.csstudio.trends.databrowser2.preferences.Preferences;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/** Dialog for creating a new PV or Formula Item: Get name, axis.
 *  For PV, also scan period.
 *
 *  @author Kay Kasemir
 *  @author Takashi Nakamoto changed AddPVDialog to update the error/warning message
 *                           dynamically as the user changes any value in this
 *                           dialog message, and to accept an existing name for
 *                           the name of newly created PV item.
 */
public class AddPVDialog extends TitleAreaDialog {
    /** Existing names */
    final private Set<String> existing_names;

    /** Value axis names */
    final private List<String> axes;

    /** Add formula, not PV? */
    final private boolean formula;

    // GUI elements
    private Text[] txt_name;
    private Text[] txt_period;
    private Button[] btn_monitor;
    private Combo[] axis;

    /** Entered names */
    private String[] name;

    /** Entered period */
    private double[] period;

    /** Selected Axis index or -1 */
    private int[] axis_index;

    private AutoCompleteWidget[] autoCompleteWidget;

    /** Initialize
     *  @param shell Shell
     *  @param count Number of names (or formulas)
     *  @param model Model to get existing names and axes
     *  @param formula Add formula, not PV?
     */
    public AddPVDialog(final Shell shell, final int count, final Model model, final boolean formula) {
        super(shell);
        this.formula = formula;
        txt_name = new Text[count];
        txt_period = new Text[count];
        btn_monitor = new Button[count];
        axis = new Combo[count];
        name = new String[count];
        period = new double[count];
        axis_index = new int[count];
        autoCompleteWidget = new AutoCompleteWidget[count];

        existing_names = new HashSet<>();
        for (ModelItem item : model.getItems())
            existing_names.add(item.getName());

        axes = new ArrayList<>();
        for (AxisConfig axis : model.getAxes())
            axes.add(axis.getName());

        setShellStyle(getShellStyle() | SWT.RESIZE);
        setHelpAvailable(false);
    }

    /** @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */
    @Override
    protected void configureShell(final Shell shell) {
        super.configureShell(shell);
        shell.setText(formula ? Messages.AddFormula : Messages.AddPV);
    }

    /** Allow resize */
    @Override
    protected boolean isResizable() {
        return true;
    }

    /** @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) */
    @Override
    protected Control createDialogArea(final Composite parent_widget) {
        final Composite parent_composite = (Composite) super.createDialogArea(parent_widget);

        // Title & Image
        setTitle(formula ? Messages.AddFormula : Messages.AddPV);
        setMessage(formula ? Messages.AddFormulaMsg : Messages.AddPVMsg);
        setTitleImage(Activator.getDefault().getImage("icons/config_image.png")); //$NON-NLS-1$

        // Scroll pane for the box
        final ScrolledComposite scroll = new ScrolledComposite(parent_composite, SWT.H_SCROLL | SWT.V_SCROLL);
        scroll.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        scroll.setExpandHorizontal(true);
        scroll.setExpandVertical(true);
        scroll.setLayout(new FillLayout());

        // Create box for widgets we're about to add
        final Composite box = new Composite(scroll, 0);
        box.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        final GridLayout layout = new GridLayout(3, false);
        box.setLayout(layout);

        final ModifyListener update_on_modify = (e) -> updateAndValidate();

        for (int i = 0; i < name.length; ++i) {
            if (i > 0) {
                Label sep = new Label(box, SWT.SEPARATOR | SWT.HORIZONTAL);
                sep.setLayoutData(new GridData(SWT.FILL, 0, true, false, layout.numColumns, 1));
            }

            // PV Name              : _____________________
            Label l = new Label(box, 0);
            l.setText(Messages.Name);
            l.setLayoutData(new GridData());

            txt_name[i] = new Text(box, SWT.BORDER);
            txt_name[i].setToolTipText(formula ? Messages.AddFormula_NameTT : Messages.AddPV_NameTT);
            txt_name[i].setLayoutData(new GridData(SWT.FILL, 0, true, false, layout.numColumns - 1, 1));
            autoCompleteWidget[i] = new AutoCompleteWidget(txt_name[i], AutoCompleteTypes.PV);

            if (!formula) {
                // Scan Period [seconds]: _____   [x] on change
                l = new Label(box, 0);
                l.setText(Messages.AddPV_Period);
                l.setLayoutData(new GridData());

                txt_period[i] = new Text(box, SWT.BORDER);
                txt_period[i].setToolTipText(Messages.AddPV_PeriodTT);
                txt_period[i].setLayoutData(new GridData(SWT.FILL, 0, true, false));

                btn_monitor[i] = new Button(box, SWT.CHECK);
                btn_monitor[i].setText(Messages.AddPV_OnChange);
                btn_monitor[i].setToolTipText(Messages.AddPV_OnChangeTT);
                btn_monitor[i].setLayoutData(new GridData());

                // Initialize to default period
                final double period = Preferences.getScanPeriod();
                if (period > 0.0)
                    txt_period[i].setText(Double.toString(period));
                else { // 'monitor'
                    txt_period[i].setText("1.0"); //$NON-NLS-1$
                    txt_period[i].setEnabled(false);
                    btn_monitor[i].setSelection(true);
                }

                // Hook listener after initial value has been set
                txt_period[i].addModifyListener(update_on_modify);

                // In 'monitor' mode, the period entry is disabled
                final int index = i;
                btn_monitor[i].addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        txt_period[index].setEnabled(!btn_monitor[index].getSelection());
                        updateAndValidate();
                    }
                });
            }

            // Value Axis:            _____
            // If there are axes to select, add related GUI
            l = new Label(box, 0);
            l.setText(Messages.AddPV_Axis);
            l.setLayoutData(new GridData());

            axis[i] = new Combo(box, SWT.READ_ONLY | SWT.DROP_DOWN | SWT.SINGLE);
            axis[i].setToolTipText(Messages.AddPV_AxisTT);
            axis[i].setLayoutData(new GridData(SWT.FILL, 0, true, false));
            // First entry is 'new axis', rest actual axis names
            axis[i].add(Messages.AddPV_NewOrEmptyAxis);
            for (String name : axes)
                axis[i].add(name);

            // Suggest multiple PVs are all placed on the same axis, the last one
            if (name.length > 1) {
                axis[i].select(axes.size());
                axis_index[i] = axes.size() - 1;
            } else {
                axis[i].select(0);
                axis_index[i] = -1;
            }

            // Empty label to fill last column
            l = new Label(box, 0);
            l.setLayoutData(new GridData());

            // Set initial text
            if (name[i] != null)
                txt_name[i].setText(name[i]);
            // and _then_ connect modify listener so it's not called for initial text
            txt_name[i].addModifyListener(update_on_modify);
        }

        scroll.setContent(box);
        scroll.setMinSize(box.computeSize(SWT.DEFAULT, SWT.DEFAULT));

        // Perform initial validation
        updateAndValidate();

        return parent_composite;
    }

    /** Save user values
     *  @see org.eclipse.jface.dialogs.Dialog#okPressed()
     */
    @Override
    protected void okPressed() {
        if (!updateAndValidate())
            return;
        for (int i = 0; i < name.length; ++i)
            autoCompleteWidget[i].getHistory().addEntry(txt_name[i].getText());
        super.okPressed();
    }

    /** Set initial name. Only effective when called before dialog is opened.
     *  @param i Index
     *  @param name Suggested name
     */
    public void setName(final int i, final String name) {
        this.name[i] = name;
    }

    /** @param i Index
     *  @return Entered PV name
     */
    public String getName(final int i) {
        return name[i];
    }

    /** @param i Index
     *  @return Entered scan period in seconds
     */
    public double getScanPeriod(final int i) {
        return period[i];
    }

    /** @param i Index
     *  @return Index of Value Axis or -1 for 'create new'
     */
    public int getAxisIndex(final int i) {
        return axis_index[i];
    }

    /** Update the internal variables according to the user input and
     *  validate them.
     *  This method also updates the message shown in this dialog.
     * @return True if all the values input by the user are valid. Otherwise, false.
     */
    private boolean updateAndValidate() {
        for (int i = 0; i < name.length; ++i) {
            // Valid name?
            name[i] = txt_name[i].getText().trim();
            if (name[i].length() <= 0) {
                setMessage(Messages.EmptyNameError, IMessageProvider.ERROR);
                return false;
            }

            // Valid scan period?
            if (!formula && !btn_monitor[i].getSelection()) {
                if (btn_monitor[i].getSelection())
                    period[i] = 0.0;
                else {
                    try {
                        period[i] = Double.parseDouble(txt_period[i].getText().trim());
                        if (period[i] < 0)
                            throw new Exception();
                    } catch (Throwable ex) {
                        setMessage(Messages.InvalidScanPeriodError, IMessageProvider.ERROR);
                        return false;
                    }
                }
            }

            // update axis_index internally
            if (axis[i] == null || axis[i].getSelectionIndex() <= 0)
                axis_index[i] = -1;
            else // entry 0 is 'no axis'
                axis_index[i] = axis[i].getSelectionIndex() - 1;

            // Now that Model accepts multiple items with the same name,
            // there is no need to prohibit from adding a new item with the
            // existing name, but this dialog just warns that the model has
            // at least one item with the given name.
            if (existing_names.contains(name[i])) {
                setMessage(NLS.bind(Messages.DuplicateItemFmt, name), IMessageProvider.WARNING);
                return true;
            }
        }
        // All OK
        setMessage(formula ? Messages.AddFormulaMsg : Messages.AddPVMsg);
        return true;
    }
}