io.sarl.eclipse.launching.dialog.SARLMainLaunchConfigurationTab.java Source code

Java tutorial

Introduction

Here is the source code for io.sarl.eclipse.launching.dialog.SARLMainLaunchConfigurationTab.java

Source

/*
 * $Id$
 *
 * SARL is an general-purpose agent programming language.
 * More details on http://www.sarl.io
 *
 * Copyright (C) 2014-2017 the original authors or authors.
 *
 * 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 io.sarl.eclipse.launching.dialog;

import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;

import javax.inject.Inject;

import com.google.common.base.Strings;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.actions.ControlAccessibleListener;
import org.eclipse.jdt.internal.debug.ui.launcher.AbstractJavaMainTab;
import org.eclipse.jdt.internal.debug.ui.launcher.DebugTypeSelectionDialog;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;

import io.sarl.eclipse.SARLEclipseConfig;
import io.sarl.eclipse.SARLEclipsePlugin;
import io.sarl.eclipse.launching.config.ILaunchConfigurationAccessor;
import io.sarl.eclipse.launching.config.ILaunchConfigurationConfigurator;
import io.sarl.eclipse.launching.config.RootContextIdentifierType;
import io.sarl.eclipse.util.Utilities;

/**
 * The main launch configuration tab.
 *
 * <p>This configuration tab enables to enter the name of the agent to launch,
 * the launching parameters, and the SRE.
 *
 * @author $Author: sgalland$
 * @version $FullVersion$
 * @mavengroupid $GroupId$
 * @mavenartifactid $ArtifactId$
 */
public class SARLMainLaunchConfigurationTab extends AbstractJavaMainTab {

    private volatile SoftReference<Image> image;

    private volatile String lastAgentNameError;

    private Text agentNameTextField;

    private Button agentNameSearchButton;

    private Button showLogoOptionButton;

    private Button showLogInfoButton;

    private Button offlineButton;

    private Button runInEclipseButton;

    private Button enableAssertionsInDebugModeButton;

    private Button enableAssertionsInRunModeButton;

    private Button defaultContextIdentifierButton;

    private Button randomContextIdentifierButton;

    private Button bootContextIdentifierButton;

    private final WidgetListener defaultListener = new WidgetListener();

    @Inject
    private ILaunchConfigurationConfigurator configurator;

    @Inject
    private ILaunchConfigurationAccessor accessor;

    /** Construct a main configuration tab for SARL project.
     */
    public SARLMainLaunchConfigurationTab() {
        //
    }

    @Override
    public Image getImage() {
        Image img = (this.image == null) ? null : this.image.get();
        if (img == null) {
            img = SARLEclipsePlugin.getDefault().getImage(SARLEclipseConfig.SARL_LOGO_IMAGE);
            this.image = new SoftReference<>(img);
        }
        return img;
    }

    @Override
    public String getId() {
        return "io.sarl.eclipse.debug.ui.sarlMainTab"; //$NON-NLS-1$
    }

    @Override
    public String getName() {
        return Messages.MainLaunchConfigurationTab_7;
    }

    @Override
    public void createControl(Composite parent) {
        final Composite comp = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH);
        ((GridLayout) comp.getLayout()).verticalSpacing = 0;
        createProjectEditor(comp);
        createVerticalSpacer(comp, 1);
        createAgentNameEditor(comp, Messages.MainLaunchConfigurationTab_0);
        createVerticalSpacer(comp, 1);
        createContextIdentifierTypeEditor(comp, Messages.MainLaunchConfigurationTab_9);
        createVerticalSpacer(comp, 1);
        createLaunchOptionEditor(comp, Messages.MainLaunchConfigurationTab_10);
        setControl(comp);
    }

    /**
     * Creates the widgets for specifying a agent name.
     *
     * @param parent - the parent composite.
     * @param text - the label of the group.
     */
    protected void createAgentNameEditor(Composite parent, String text) {
        final Group group = SWTFactory.createGroup(parent, text, 2, 1, GridData.FILL_HORIZONTAL);
        this.agentNameTextField = SWTFactory.createSingleText(group, 1);
        this.agentNameTextField.addModifyListener(new ModifyListener() {
            @SuppressWarnings("synthetic-access")
            @Override
            public void modifyText(ModifyEvent event) {
                SARLMainLaunchConfigurationTab.this.lastAgentNameError = null;
                updateLaunchConfigurationDialog();
            }
        });
        ControlAccessibleListener.addListener(this.agentNameTextField, group.getText());
        this.agentNameSearchButton = createPushButton(group, Messages.MainLaunchConfigurationTab_1, null);
        this.agentNameSearchButton.addSelectionListener(new SelectionListener() {
            @Override
            public void widgetDefaultSelected(SelectionEvent event) {
                //
            }

            @Override
            public void widgetSelected(SelectionEvent event) {
                handleAgentNameSearchButtonSelected();
            }
        });
    }

    /**
     * Creates the widgets for configuring the context identifier.
     *
     * @param parent - the parent composite.
     * @param text - the label of the group.
     */
    protected void createContextIdentifierTypeEditor(Composite parent, String text) {
        final Group group = SWTFactory.createGroup(parent, text, 1, 1, GridData.FILL_HORIZONTAL);
        this.defaultContextIdentifierButton = createRadioButton(group, Messages.MainLaunchConfigurationTab_11);
        this.defaultContextIdentifierButton.addSelectionListener(this.defaultListener);
        this.randomContextIdentifierButton = createRadioButton(group, Messages.MainLaunchConfigurationTab_12);
        this.randomContextIdentifierButton.addSelectionListener(this.defaultListener);
        this.bootContextIdentifierButton = createRadioButton(group, Messages.MainLaunchConfigurationTab_13);
        this.bootContextIdentifierButton.addSelectionListener(this.defaultListener);
    }

    /** Replies the type of context identifier selected by the user.
     *
     * @return the type of context identifier.
     */
    protected RootContextIdentifierType getSelectedContextIdentifierType() {
        if (this.randomContextIdentifierButton.getSelection()) {
            return RootContextIdentifierType.RANDOM_CONTEXT_ID;
        }
        if (this.bootContextIdentifierButton.getSelection()) {
            return RootContextIdentifierType.BOOT_AGENT_CONTEXT_ID;
        }
        return RootContextIdentifierType.DEFAULT_CONTEXT_ID;
    }

    /**
     * Creates the widgets for configuring the launch options.
     *
     * @param parent - the parent composite.
     * @param text - the label of the group.
     */
    protected void createLaunchOptionEditor(Composite parent, String text) {
        final Group group = SWTFactory.createGroup(parent, text, 1, 1, GridData.FILL_HORIZONTAL);
        this.showLogoOptionButton = createCheckButton(group, Messages.MainLaunchConfigurationTab_14);
        this.showLogoOptionButton.addSelectionListener(this.defaultListener);
        this.showLogInfoButton = createCheckButton(group, Messages.MainLaunchConfigurationTab_15);
        this.showLogInfoButton.addSelectionListener(this.defaultListener);
        this.offlineButton = createCheckButton(group, Messages.MainLaunchConfigurationTab_16);
        this.offlineButton.addSelectionListener(this.defaultListener);
        this.enableAssertionsInRunModeButton = createCheckButton(group, Messages.SARLMainLaunchConfigurationTab_2);
        this.enableAssertionsInRunModeButton.addSelectionListener(this.defaultListener);
        this.enableAssertionsInDebugModeButton = createCheckButton(group,
                Messages.SARLMainLaunchConfigurationTab_1);
        this.enableAssertionsInDebugModeButton.addSelectionListener(this.defaultListener);
        this.runInEclipseButton = createCheckButton(group, Messages.SARLMainLaunchConfigurationTab_0);
        this.runInEclipseButton.addSelectionListener(this.defaultListener);
    }

    @Override
    public void initializeFrom(ILaunchConfiguration config) {
        super.initializeFrom(config);
        updateAgentNameFromConfig(config);
        updateContextIdentifierTypeFromConfig(config);
        updateLaunchOptionsFromConfig(config);
    }

    /**
     * Loads the context identifier type from the launch configuration's preference store.
     *
     * @param config - the config to load the agent name from
     */
    protected void updateContextIdentifierTypeFromConfig(ILaunchConfiguration config) {
        final RootContextIdentifierType type = this.accessor.getDefaultContextIdentifier(config);
        assert type != null;
        switch (type) {
        case RANDOM_CONTEXT_ID:
            this.randomContextIdentifierButton.setSelection(true);
            break;
        case BOOT_AGENT_CONTEXT_ID:
            this.bootContextIdentifierButton.setSelection(true);
            break;
        case DEFAULT_CONTEXT_ID:
        default:
            this.defaultContextIdentifierButton.setSelection(true);
            break;
        }
    }

    /**
     * Loads the launch options from the launch configuration's preference store.
     *
     * @param config - the config to load the agent name from
     */
    protected void updateLaunchOptionsFromConfig(ILaunchConfiguration config) {
        final boolean showLogo = this.accessor.getShowLogoFlag(config);
        final boolean showLogInfo = this.accessor.getShowLogInfoFlag(config);
        final boolean offline = this.accessor.getOfflineFlag(config);
        final boolean runInEclipse = this.accessor.isEmbeddedSRE(config);
        final boolean enableAssertionsRun = this.accessor.isAssertionEnabledInRunMode(config);
        final boolean enableAssertionsDebug = this.accessor.isAssertionEnabledInDebugMode(config);
        this.showLogoOptionButton.setSelection(showLogo);
        this.showLogInfoButton.setSelection(showLogInfo);
        this.offlineButton.setSelection(offline);
        this.enableAssertionsInRunModeButton.setSelection(enableAssertionsRun);
        this.enableAssertionsInDebugModeButton.setSelection(enableAssertionsDebug);
        this.runInEclipseButton.setSelection(runInEclipse);
    }

    /**
     * Loads the agent name from the launch configuration's preference store.
     *
     * @param config - the config to load the agent name from
     */
    protected void updateAgentNameFromConfig(ILaunchConfiguration config) {
        final String agentName = this.accessor.getAgent(config);
        this.agentNameTextField.setText(Strings.nullToEmpty(agentName));
    }

    @Override
    public boolean isValid(ILaunchConfiguration config) {
        setErrorMessage(null);
        setMessage(null);
        return isValidProjectName() && isValidAgentName() && isValidContextIdentifierType()
                && isValidLaunchOptions();
    }

    /** Replies if the context identfiier type is valid.
     *
     * @return the validity state.
     */
    @SuppressWarnings("static-method")
    protected boolean isValidContextIdentifierType() {
        return true;
    }

    /** Replies if the launch options are valid.
     *
     * @return the validity state.
     */
    @SuppressWarnings("static-method")
    protected boolean isValidLaunchOptions() {
        return true;
    }

    /** Replies if the agent name is valid.
     *
     * @return the validity state.
     */
    protected boolean isValidAgentName() {
        if (this.lastAgentNameError != null) {
            final boolean isValid = Strings.isNullOrEmpty(this.lastAgentNameError);
            if (!isValid) {
                setErrorMessage(this.lastAgentNameError);
            }
            return isValid;
        }
        final String name = this.agentNameTextField.getText();
        if (Strings.isNullOrEmpty(name)) {
            this.lastAgentNameError = Messages.MainLaunchConfigurationTab_2;
            setErrorMessage(this.lastAgentNameError);
            return false;
        }
        if (!isAgentNameDefined(name)) {
            this.lastAgentNameError = MessageFormat.format(Messages.MainLaunchConfigurationTab_8, name);
            setErrorMessage(this.lastAgentNameError);
            return false;
        }
        this.lastAgentNameError = Utilities.EMPTY_STRING;
        return true;
    }

    /** Replies if the project name is valid.
     *
     * <p>Copied from JDT.
     *
     * @return the validity state.
     */
    protected boolean isValidProjectName() {
        final String name = this.fProjText.getText();
        if (Strings.isNullOrEmpty(name)) {
            setErrorMessage(Messages.MainLaunchConfigurationTab_3);
            return false;
        }
        final IWorkspace workspace = ResourcesPlugin.getWorkspace();
        final IStatus status = workspace.validateName(name, IResource.PROJECT);
        if (status.isOK()) {
            final IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
            if (!project.exists()) {
                setErrorMessage(MessageFormat.format(Messages.MainLaunchConfigurationTab_4, name));
                return false;
            }
            if (!project.isOpen()) {
                setErrorMessage(MessageFormat.format(Messages.MainLaunchConfigurationTab_5, name));
                return false;
            }
        } else {
            setErrorMessage(MessageFormat.format(Messages.MainLaunchConfigurationTab_6, status.getMessage()));
            return false;
        }
        return true;
    }

    @Override
    public void performApply(ILaunchConfigurationWorkingCopy config) {
        this.configurator.setProjectName(config, Strings.emptyToNull(this.fProjText.getText().trim()));
        this.configurator.setAgent(config, Strings.emptyToNull(this.agentNameTextField.getText().trim()));
        this.configurator.setDefaultContextIdentifier(config, getSelectedContextIdentifierType());
        this.configurator.setLaunchingFlags(config, this.showLogoOptionButton.getSelection(),
                this.showLogInfoButton.getSelection(), this.offlineButton.getSelection());
        this.configurator.setAssertionEnabledInRunMode(config, this.enableAssertionsInRunModeButton.getSelection());
        this.configurator.setAssertionEnabledInDebugMode(config,
                this.enableAssertionsInDebugModeButton.getSelection());
        this.configurator.setEmbeddedSRE(config, this.runInEclipseButton.getSelection());
        mapResources(config);
    }

    @Override
    public void setDefaults(ILaunchConfigurationWorkingCopy config) {
        final IJavaElement javaElement = getContext();
        if (javaElement != null) {
            initializeJavaProject(javaElement, config);
        } else {
            config.removeAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME);
        }
        initializeAgentName(javaElement, config);
        initializeContextIdentifierType(config);
        initializeLaunchOptions(config);
    }

    /**
     * Reset the given configuration with the context identifier type.
     *
     * @param config - the config to set with the context identifier type.
     */
    protected void initializeContextIdentifierType(ILaunchConfigurationWorkingCopy config) {
        this.configurator.setDefaultContextIdentifier(config, null);
    }

    /**
     * Reset the given configuration with the launch options.
     *
     * @param config - the config to set with the launch options.
     */
    protected void initializeLaunchOptions(ILaunchConfigurationWorkingCopy config) {
        this.configurator.setLaunchingFlags(config, null, null, null);
    }

    private String extractNameFromJavaElement(final IJavaElement javaElement) {
        String name = null;
        if (javaElement != null) {
            final String[] nameRef = new String[1];
            try {
                getLaunchConfigurationDialog().run(true, true, new IRunnableWithProgress() {
                    @SuppressWarnings("synthetic-access")
                    @Override
                    public void run(IProgressMonitor pm) throws InvocationTargetException {
                        try {
                            final IJavaProject javaProject = javaElement.getJavaProject();
                            final IType agentType = javaProject.findType("io.sarl.lang.core.Agent"); //$NON-NLS-1$
                            final IType[] types = agentType.newTypeHierarchy(pm).getAllSubtypes(agentType);
                            if (types != null && types.length > 0) {
                                nameRef[0] = types[0].getFullyQualifiedName();
                            }
                        } catch (JavaModelException e) {
                            setErrorMessage(e.getLocalizedMessage());
                            JDIDebugUIPlugin.log(e);
                        }
                    }
                });
            } catch (Exception e) {
                setErrorMessage(e.getLocalizedMessage());
                JDIDebugUIPlugin.log(e);
            }
            name = nameRef[0];
        }
        return Strings.nullToEmpty(name);
    }

    /**
     * Reset the given configuration with the agent name attributes associated
     * to the given element.
     *
     * @param javaElement - the element from which information may be retrieved.
     * @param config - the config to set with the agent name.
     */
    protected void initializeAgentName(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config) {
        String name = extractNameFromJavaElement(javaElement);

        // Set the attribute
        this.configurator.setAgent(config, name);

        // Rename the launch configuration
        if (name.length() > 0) {
            final int index = name.lastIndexOf('.');
            if (index > 0) {
                name = name.substring(index + 1);
            }
            name = getLaunchConfigurationDialog().generateName(name);
            config.rename(name);
        }
    }

    private IType[] searchAgentNames() {
        final IType[][] res = new IType[1][];
        res[0] = new IType[0];
        final String projectName = this.fProjText.getText();
        final IStatus status = ResourcesPlugin.getWorkspace().validateName(projectName, IResource.PROJECT);
        if (status.isOK()) {
            try {
                getLaunchConfigurationDialog().run(true, true, new IRunnableWithProgress() {
                    @SuppressWarnings("synthetic-access")
                    @Override
                    public void run(IProgressMonitor pm) throws InvocationTargetException {
                        try {
                            final IProject project = ResourcesPlugin.getWorkspace().getRoot()
                                    .getProject(projectName);
                            final IJavaProject javaProject = JavaCore.create(project);
                            final IType agentType = javaProject.findType("io.sarl.lang.core.Agent"); //$NON-NLS-1$
                            res[0] = agentType.newTypeHierarchy(pm).getAllSubtypes(agentType);
                        } catch (JavaModelException e) {
                            setErrorMessage(e.getLocalizedMessage());
                            JDIDebugUIPlugin.log(e);
                        }
                    }
                });
            } catch (Exception e) {
                setErrorMessage(e.getLocalizedMessage());
                JDIDebugUIPlugin.log(e);
            }
        }
        return res[0];
    }

    private boolean isAgentNameDefined(final String agentName) {
        final String projectName = this.fProjText.getText();
        final IStatus status = ResourcesPlugin.getWorkspace().validateName(projectName, IResource.PROJECT);
        if (status.isOK()) {
            try {
                final boolean[] res = new boolean[1];
                getLaunchConfigurationDialog().run(true, true, new IRunnableWithProgress() {
                    @SuppressWarnings("synthetic-access")
                    @Override
                    public void run(IProgressMonitor pm) throws InvocationTargetException {
                        try {
                            final IProject project = ResourcesPlugin.getWorkspace().getRoot()
                                    .getProject(projectName);
                            final IJavaProject javaProject = JavaCore.create(project);
                            final IType agentType = javaProject.findType("io.sarl.lang.core.Agent"); //$NON-NLS-1$
                            if (agentType != null) {
                                final IType type = javaProject.findType(agentName);
                                if (type != null) {
                                    res[0] = type.newSupertypeHierarchy(pm).contains(agentType);
                                }
                            }
                        } catch (JavaModelException e) {
                            setErrorMessage(e.getLocalizedMessage());
                            JDIDebugUIPlugin.log(e);
                        }
                    }
                });
                return res[0];
            } catch (Exception exception) {
                //
            }
        }
        return false;
    }

    /** Invoked when the search button for the agent agent was clocked.
     */
    protected void handleAgentNameSearchButtonSelected() {
        final IType[] types = searchAgentNames();
        // Ask to the user
        final DebugTypeSelectionDialog mmsd = new DebugTypeSelectionDialog(getShell(), types, ""); //$NON-NLS-1$
        if (mmsd.open() == Window.CANCEL) {
            return;
        }
        final IType type = (IType) mmsd.getFirstResult();
        if (type != null) {
            this.agentNameTextField.setText(type.getFullyQualifiedName());
            this.fProjText.setText(type.getJavaProject().getElementName());
        }
    }

    /** Listener of events in internal components for refreshing the tab.
     *
     * @author $Author: sgalland$
     * @version $FullVersion$
     * @mavengroupid $GroupId$
     * @mavenartifactid $ArtifactId$
     */
    private class WidgetListener implements SelectionListener {

        WidgetListener() {
            //
        }

        @Override
        public void widgetDefaultSelected(SelectionEvent event) {
            //
        }

        @SuppressWarnings("synthetic-access")
        @Override
        public void widgetSelected(SelectionEvent event) {
            updateLaunchConfigurationDialog();
        }

    }

}