com.cisco.yangide.ext.model.editor.dialog.AddImportDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.yangide.ext.model.editor.dialog.AddImportDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  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 com.cisco.yangide.ext.model.editor.dialog;

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

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.graphiti.ui.services.GraphitiUi;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;

import com.cisco.yangide.core.YangCorePlugin;
import com.cisco.yangide.core.YangModelException;
import com.cisco.yangide.core.dom.SimpleNode;
import com.cisco.yangide.core.indexing.ElementIndexInfo;
import com.cisco.yangide.core.indexing.ElementIndexType;
import com.cisco.yangide.core.model.YangModelManager;
import com.cisco.yangide.ext.model.Import;
import com.cisco.yangide.ext.model.ModelFactory;
import com.cisco.yangide.ext.model.ModelPackage;
import com.cisco.yangide.ext.model.Module;
import com.cisco.yangide.ext.model.Node;
import com.cisco.yangide.ext.model.editor.Activator;
import com.cisco.yangide.ext.model.editor.util.Strings;
import com.cisco.yangide.ext.model.editor.util.YangDiagramImageProvider;
import com.cisco.yangide.ext.model.editor.util.YangModelUtil;

/**
 * This class is a dialog in which user can choose a module to import and its prefix. <br>
 * The existing modules are shown in a list, while the prefix is given by a text box. The first
 * module in the list is chosen by default. When user changes selection in the list, the dialog
 * automatically sets the prefix field to the value defined in the selected module. Value of prefix
 * is examined against the empty value and prefixes already present in the edited module. <br>
 * The resulting {@link Import} object may be obtained from {@link #getResultImport()} if dialog was
 * closed with OK button.
 * 
 * @author Kirill Karmakulov
 * @date 09 Oct 2014
 */
public class AddImportDialog extends ElementListSelectionDialog {

    private Text prefix;
    private ModifyListener prefixModifyListener;

    // Prefixes that are already used by the edited module
    private final Set<String> importPrefixes;

    // Keeps track of parent's Status
    private IStatus fLastStatus;

    private Import result;

    /**
     * Creates a new {@link AddImportDialog}
     * 
     * @param parent the parent shell
     * @param module the edited {@link Module}
     * @param file file to get an {@link IProject} from; the existing modules are taken from this
     * project
     */
    public AddImportDialog(Shell parent, Module module, IFile file) {
        super(parent, new ModuleLabelProvider());
        setAllowDuplicates(false);
        List<Import> imports = getImports(module);
        importPrefixes = getImportData(imports, ModelPackage.Literals.IMPORT__PREFIX);
        setElements(getModuleList(module, file, imports));
        setTitle("Select imported module");
        setImage(GraphitiUi.getImageService().getImageForId(YangDiagramImageProvider.DIAGRAM_TYPE_PROVIDER_ID,
                YangDiagramImageProvider.IMG_IMPORT_PROPOSAL));
    }

    /**
     * Creates an area and a text field to enter prefix of the imported module into
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite content = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(content);
        GridLayoutFactory.fillDefaults().numColumns(1).applyTo(content);
        super.createDialogArea(content);
        createPrefixArea(content);
        return content;
    }

    private void createPrefixArea(Composite content) {
        Composite appendix = new Composite(content, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
        layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
        layout.numColumns = 2;
        appendix.setLayout(layout);
        appendix.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        CLabel label = new CLabel(appendix, SWT.NONE);
        label.setText("Prefix");
        prefix = new Text(appendix, SWT.BORDER);
        prefixModifyListener = new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent e) {
                updateStatus(getOverallStatus());
            }
        };
        prefix.addModifyListener(prefixModifyListener);
        prefix.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    }

    /**
     * If prefix field contains an invalid value, returns an error {@link IStatus}. Otherwise
     * returns parent's status.
     * 
     * @return an {@link IStatus} object
     */
    private IStatus getOverallStatus() {
        String value = prefix.getText();
        IStatus status;
        if (value.isEmpty()) {
            status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                    String.format("Empty prefix is not allowed", value));
        } else if (importPrefixes.contains(value)) {
            status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                    String.format("Prefix \"%s\" is already used", value), null);
        } else
            status = fLastStatus;
        return status;
    }

    /**
     * Saves parent's status internally for use by {@link #getOverallStatus()}.
     */
    @Override
    protected void updateStatus(IStatus status) {
        if (!Activator.PLUGIN_ID.equals(status.getPlugin()))
            // The Status wasn't generated by this class
            fLastStatus = status;
        super.updateStatus(status);
    }

    /**
     * Updates prefix field from the module selected by user. Then updates status of the window if
     * prefix is invalid.
     */
    @Override
    protected void handleSelectionChanged() {
        setDefaultPrefix();
        super.handleSelectionChanged();
        IStatus status = getOverallStatus();
        if (status.getSeverity() != IStatus.OK)
            updateStatus(status);
    }

    /**
     * Updates prefix field from the module selected by user. If the prefix is invalid, fails the
     * default selection and update status of the window. Otherwise behaves just lake parent.
     */
    @Override
    protected void handleDefaultSelected() {
        setDefaultPrefix();
        IStatus status = getOverallStatus();
        if (status.getSeverity() == IStatus.OK)
            super.handleDefaultSelected();
    }

    private void setDefaultPrefix() {
        String defaultPrefix = Strings.EMPTY_STRING;
        Object[] selectedElements = getSelectedElements();
        if (selectedElements.length > 0) // it's a single selection list dialog
        {
            ElementIndexInfo info = (ElementIndexInfo) selectedElements[0];
            try {
                com.cisco.yangide.core.dom.Module importedModule = YangCorePlugin.createYangFile(info.getPath())
                        .getModule();
                SimpleNode<String> prefixNode = importedModule.getPrefix();
                if (prefixNode != null)
                    defaultPrefix = prefixNode.getValue();
            } catch (YangModelException ex) {
                Activator.log(ex, "Yang source file could not be loaded.");
            }
        }
        // There's no need in checking the default prefix, since this is done by hand in
        // handleSelectionChanged() and handleDefaultSelected()
        prefix.removeModifyListener(prefixModifyListener);
        prefix.setText(defaultPrefix);
        prefix.addModifyListener(prefixModifyListener);
    }

    /**
     * Creates the resulting {@link Import} object returned by {@link #getResultImport()}
     */
    @Override
    protected void computeResult() {
        super.computeResult();
        ElementIndexInfo choosen = (ElementIndexInfo) getFirstResult();
        result = ModelFactory.eINSTANCE.createImport();
        result.setPrefix(prefix.getText());
        result.setRevisionDate(choosen.getRevision());
        result.setModule(choosen.getModule());
    }

    public Import getResultImport() {
        return result;
    }

    /**
     * Returns a list of {@link Import} objects defined by the given {@code module}
     */
    private static List<Import> getImports(Module module) {
        List<Import> result = new ArrayList<Import>();
        for (Node _import : YangModelUtil.filter(module.getChildren(), ModelPackage.Literals.IMPORT))
            result.add((Import) _import);
        return result;
    }

    /**
     * Iterates over {@code imports}, and from each object gets a value of the field defined by
     * {@code feature}. The values are put in the resulting {@link Set}.
     * 
     * @param imports source of objects
     * @param feature field of object
     * @return a {@link Set}
     */
    @SuppressWarnings("unchecked")
    private static <T> Set<T> getImportData(List<Import> imports, EStructuralFeature feature) {
        Set<T> result = new HashSet<T>(imports.size());
        for (Import _import : imports)
            result.add((T) ((Import) _import).eGet(feature));
        return result;
    }

    /**
     * Builds a list of modules that the current module can import. <br>
     * Retrieves yang modules that exist in the current project. Then filters out the {@code module}
     * itself and the modules that are already imported. <br>
     * Current project is determined from to the given {@code file}
     * 
     * @param file a file from the current project
     * @param imports a collection of imports of the module
     * @return List of modules that
     */
    private static ElementIndexInfo[] getModuleList(Module module, IFile file, List<Import> imports) {
        ElementIndexInfo[] allModules = YangModelManager.search(null, null, null, ElementIndexType.MODULE,
                null == file ? null : file.getProject(), null);
        List<ElementIndexInfo> result = new ArrayList<ElementIndexInfo>(allModules.length - 1);

        Set<String> importSet = getImportData(imports, ModelPackage.Literals.IMPORT__MODULE);
        String name = module.getName();
        for (ElementIndexInfo info : allModules) {
            String moduleName = info.getModule();
            if (Objects.equals(name, moduleName))
                continue;
            if (importSet.contains(moduleName))
                continue;
            result.add(info);
        }
        return result.toArray(new ElementIndexInfo[result.size()]);
    }

    /**
     * Label provider for {@link Module}
     */
    private static final class ModuleLabelProvider extends LabelProvider {
        public String getText(Object element) {
            if (element instanceof ElementIndexInfo) {
                return ((ElementIndexInfo) element).getName() + " {" + ((ElementIndexInfo) element).getRevision()
                        + "}";
            }
            return null;
        }

        @Override
        public Image getImage(Object element) {
            return GraphitiUi.getImageService().getImageForId(YangDiagramImageProvider.DIAGRAM_TYPE_PROVIDER_ID,
                    YangDiagramImageProvider.IMG_MODULE_PROPOSAL);
        }
    }

}