org.robotframework.red.jface.preferences.ComboBoxFieldEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.robotframework.red.jface.preferences.ComboBoxFieldEditor.java

Source

/*
 * Copyright 2015 Nokia Solutions and Networks
 * Licensed under the Apache License, Version 2.0,
 * see license.txt file for details.
 */
package org.robotframework.red.jface.preferences;

import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;

/**
 * Custom combo field editor capable of showing line between label and combo
 * (similarly like field editors on Java -> Compiler -> Error/Warnings
 * preference page.
 * 
 * @{author Michal Anglart
 */
public class ComboBoxFieldEditor extends FieldEditor {

    private final int labelIndent;

    private Combo combo;

    private final String tooltip;

    private String value;

    private final String[][] entryNamesAndValues;

    public ComboBoxFieldEditor(final String name, final String labelText, final String tooltip,
            final String[][] entryNamesAndValues, final Composite parent) {
        this(name, labelText, tooltip, 0, entryNamesAndValues, parent);
    }

    /**
     * Create the combo box field editor.
     * 
     * @param name
     *            the name of the preference this field editor works on
     * @param labelText
     *            the label text of the field editor
     * @param entryNamesAndValues
     *            the names (labels) and underlying values to populate the combo
     *            widget. These should be arranged as: { {name1, value1},
     *            {name2, value2}, ...}
     * @param parent
     *            the parent composite
     * @param labelIndent
     */
    public ComboBoxFieldEditor(final String name, final String labelText, final String tooltip,
            final int labelIndent, final String[][] entryNamesAndValues, final Composite parent) {
        init(name, labelText);
        Assert.isTrue(checkArray(entryNamesAndValues));
        this.tooltip = tooltip;
        this.entryNamesAndValues = entryNamesAndValues;
        this.labelIndent = labelIndent;
        createControl(parent);
    }

    /**
     * Checks whether given <code>String[][]</code> is of "type"
     * <code>String[][2]</code>.
     *
     * @return <code>true</code> if it is ok, and <code>false</code> otherwise
     */
    private boolean checkArray(final String[][] table) {
        if (table == null) {
            return false;
        }
        for (int i = 0; i < table.length; i++) {
            final String[] array = table[i];
            if (array == null || array.length != 2) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected void adjustForNumColumns(final int numColumns) {
        if (numColumns > 1) {
            final Label label = getLabelControl();
            int left = numColumns;
            if (label != null) {
                label.setToolTipText(tooltip);
                final GridData labelGridData = (GridData) label.getLayoutData();
                labelGridData.horizontalSpan = 1;
                labelGridData.grabExcessHorizontalSpace = true;
                labelGridData.horizontalIndent = labelIndent;
                left = left - 1;
            }
            ((GridData) combo.getLayoutData()).horizontalSpan = left;
        } else {
            final Label label = getLabelControl();
            if (label != null) {
                label.setToolTipText(tooltip);
                final GridData labelGridData = (GridData) label.getLayoutData();
                labelGridData.horizontalSpan = 1;
                labelGridData.horizontalIndent = labelIndent;
            }
            ((GridData) combo.getLayoutData()).horizontalSpan = 1;
        }
        combo.setToolTipText(tooltip);
    }

    @Override
    protected void doFillIntoGrid(final Composite parent, final int numColumns) {
        final int comboSpan = numColumns <= 1 ? 1 : numColumns - 1;

        final Label label = getLabelControl(parent);
        GridDataFactory.swtDefaults().applyTo(label);

        final Combo comboBox = getComboBoxControl(parent);
        GridDataFactory.swtDefaults().span(comboSpan, 1).align(GridData.FILL, GridData.CENTER).applyTo(comboBox);

        installLineLinkingCapability(parent, label, comboBox);
    }

    private void installLineLinkingCapability(final Composite parent, final Label label, final Combo comboBox) {
        final AtomicBoolean shouldShowLine = new AtomicBoolean(false);
        final MouseTrackAdapter controlsMouseListener = new MouseTrackAdapter() {
            @Override
            public void mouseEnter(final MouseEvent e) {
                shouldShowLine.set(true);
                parent.redraw();
            }

            @Override
            public void mouseExit(final MouseEvent e) {
                shouldShowLine.set(false);
                parent.redraw();
            }
        };
        label.addMouseTrackListener(controlsMouseListener);
        comboBox.addMouseTrackListener(controlsMouseListener);

        parent.addPaintListener(new PaintListener() {

            @Override
            public void paintControl(final PaintEvent e) {
                if (!shouldShowLine.get()) {
                    return;
                }
                final Display display = parent.getDisplay();
                final Point labelSize = label.getSize();
                final Point labelRightEndCenter = new Point(labelSize.x, labelSize.y / 2);
                final Point fromPoint = display.map(label, parent, labelRightEndCenter);

                final Point toPoint = display.map(comboBox, parent, 0, 0);

                final Color oldForground = e.gc.getForeground();
                e.gc.setForeground(display.getSystemColor(SWT.COLOR_DARK_GRAY));
                e.gc.drawLine(fromPoint.x + 5, fromPoint.y, toPoint.x - 5, fromPoint.y);
                e.gc.drawLine(toPoint.x - 8, fromPoint.y - 3, toPoint.x - 5, fromPoint.y);
                e.gc.drawLine(toPoint.x - 8, fromPoint.y + 3, toPoint.x - 5, fromPoint.y);
                e.gc.setForeground(oldForground);
            }
        });
    }

    @Override
    protected void doLoad() {
        updateComboForValue(getPreferenceStore().getString(getPreferenceName()));
    }

    @Override
    protected void doLoadDefault() {
        updateComboForValue(getPreferenceStore().getDefaultString(getPreferenceName()));
    }

    @Override
    protected void doStore() {
        if (value == null) {
            getPreferenceStore().setToDefault(getPreferenceName());
            return;
        }
        getPreferenceStore().setValue(getPreferenceName(), value);
    }

    @Override
    public int getNumberOfControls() {
        return 2;
    }

    private Combo getComboBoxControl(final Composite parent) {
        if (combo == null) {
            combo = new Combo(parent, SWT.READ_ONLY);
            for (int i = 0; i < entryNamesAndValues.length; i++) {
                combo.add(entryNamesAndValues[i][0], i);
            }
            combo.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent evt) {
                    final String oldValue = value;
                    final String name = combo.getText();
                    value = getValueForName(name);
                    setPresentsDefaultValue(false);
                    fireValueChanged(VALUE, oldValue, value);
                }
            });
        }
        combo.setEnabled(entryNamesAndValues.length > 1);
        return combo;
    }

    private String getValueForName(final String name) {
        for (int i = 0; i < entryNamesAndValues.length; i++) {
            final String[] entry = entryNamesAndValues[i];
            if (name.equals(entry[0])) {
                return entry[1];
            }
        }
        return entryNamesAndValues[0][0];
    }

    private void updateComboForValue(final String value) {
        this.value = value;
        for (int i = 0; i < entryNamesAndValues.length; i++) {
            if (value.equals(entryNamesAndValues[i][1])) {
                combo.setText(entryNamesAndValues[i][0]);
                return;
            }
        }
        if (entryNamesAndValues.length > 0) {
            this.value = entryNamesAndValues[0][1];
            combo.setText(entryNamesAndValues[0][0]);
        }
    }

    @Override
    public void setEnabled(final boolean enabled, final Composite parent) {
        super.setEnabled(enabled, parent);
        getComboBoxControl(parent).setEnabled(enabled);
    }
}