tern.eclipse.ide.ui.controls.TernModulesBlock.java Source code

Java tutorial

Introduction

Here is the source code for tern.eclipse.ide.ui.controls.TernModulesBlock.java

Source

/**
 *  Copyright (c) 2013-2016 Angelo ZERR.
 *  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
 *
 *  Contributors:
 *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
 */
package tern.eclipse.ide.ui.controls;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;

import tern.eclipse.ide.core.IIDETernProject;
import tern.eclipse.ide.core.TernCorePlugin;
import tern.eclipse.ide.internal.ui.TernUIMessages;
import tern.eclipse.ide.internal.ui.Trace;
import tern.eclipse.ide.internal.ui.controls.DependenciesPanel;
import tern.eclipse.ide.internal.ui.controls.DetailsPanel;
import tern.eclipse.ide.internal.ui.controls.OptionsPanel;
import tern.eclipse.ide.internal.ui.viewers.TernModuleVersionEditingSupport;
import tern.eclipse.ide.ui.TernUIPlugin;
import tern.eclipse.ide.ui.viewers.TernModuleLabelProvider;
import tern.metadata.TernModuleMetadata;
import tern.repository.ITernRepository;
import tern.server.ITernModule;
import tern.server.ITernModuleConfigurable;
import tern.utils.StringUtils;
import tern.utils.TernModuleHelper;

/**
 * Block to select Tern plugins + JSON Type Definitions.
 * 
 */
public class TernModulesBlock extends AbstractTableBlock {

    private static final IElementComparer TERN_MODULES_COMPARER = new IElementComparer() {

        @Override
        public boolean equals(Object a, Object b) {
            return a.equals(b);
        }

        @Override
        public int hashCode(Object element) {
            return element.hashCode();
        }
    };

    private final String tableLabel;
    private final IProject project;

    private final Map<String, ITernModule> ternModules = new HashMap<String, ITernModule>();
    private CheckboxTableViewer tableViewer;
    private DetailsPanel detailsPanel;
    private DependenciesPanel dependenciesPanel;
    private OptionsPanel optionsPanel;
    private TabItem optionsTabItem;
    private TabFolder tabFolder;
    private TabItem detailsTabItem;
    private Button selectDependenciesCheckbox;

    private Collection<ITernModule> checkedModules;
    private boolean checkUpdating;

    public TernModulesBlock(IProject project, String tableLabel) {
        this.project = project;
        this.tableLabel = tableLabel;
    }

    public Control createControl(Composite ancestor) {

        Composite parent = new Composite(ancestor, SWT.NULL);
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        parent.setLayout(layout);
        Font font = ancestor.getFont();
        parent.setFont(font);

        GridData data;
        if (tableLabel != null) {
            Composite header = new Composite(parent, SWT.NONE);
            data = new GridData();
            data.horizontalSpan = 2;
            header.setLayoutData(data);
            header.setLayout(new GridLayout(2, false));

            // Create description
            Label tableLabel = new Label(header, SWT.NONE);
            tableLabel.setText(this.tableLabel);
            tableLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            tableLabel.setFont(font);
            // Create dependencies checkbox
            selectDependenciesCheckbox = new Button(header, SWT.CHECK);
            selectDependenciesCheckbox.setSelection(true);
        }

        SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL | SWT.SMOOTH);
        data = new GridData(SWT.FILL, SWT.FILL, true, true);
        sashForm.setLayoutData(data);

        createModulesMaster(sashForm);
        createModulesDetails(sashForm);

        Dialog.applyDialogFont(parent);
        return parent;
    }

    /**
     * Create table of tern modules.
     * 
     * @param ancestor
     */
    private void createModulesMaster(Composite ancestor) {
        Composite parent = new Composite(ancestor, SWT.NULL);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        parent.setLayout(layout);
        Font font = ancestor.getFont();
        parent.setFont(font);

        Table table = new Table(parent, SWT.CHECK | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);

        GridData data = new GridData(GridData.FILL_BOTH);
        data.widthHint = 350;
        data.heightHint = 400;
        table.setLayoutData(data);
        table.setFont(parent.getFont());

        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        tableViewer = new CheckboxTableViewer(table);

        // create name column
        TableViewerColumn nameColumn = new TableViewerColumn(tableViewer, SWT.NONE);
        nameColumn.getColumn().setWidth(180);
        nameColumn.getColumn().setResizable(true);
        nameColumn.getColumn().setText(TernUIMessages.TernModulesBlock_moduleName);
        nameColumn.getColumn().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                sortByName();
            }
        });

        // create version column
        TableViewerColumn versionColumn = new TableViewerColumn(tableViewer, SWT.NONE);
        versionColumn.getColumn().setWidth(100);
        versionColumn.getColumn().setResizable(true);
        versionColumn.getColumn().setText(TernUIMessages.TernModulesBlock_moduleVersion);
        final TernModuleVersionEditingSupport versionEditiongSupport = new TernModuleVersionEditingSupport(
                tableViewer);
        versionColumn.setEditingSupport(versionEditiongSupport);

        tableViewer.setComparer(TERN_MODULES_COMPARER);
        tableViewer.setLabelProvider(TernModuleLabelProvider.getInstance());
        tableViewer.setContentProvider(ArrayContentProvider.getInstance());

        // when a module is checked and dependencies checkbox is checked, tern
        // module dependencies must be selected too
        addCheckStateListener(new ICheckStateListener() {

            @Override
            public void checkStateChanged(CheckStateChangedEvent e) {
                if (checkUpdating) {
                    return;
                }
                try {
                    checkUpdating = true;
                    ITernModule module = ((ITernModule) e.getElement());
                    // update checked modules list
                    updateCheckedModules(module, e.getChecked());
                    if (e.getChecked() && isSelectDependencies()) {
                        TernModuleMetadata metadata = module.getMetadata();
                        if (metadata != null) {
                            ITernModule dependencyModule = null;
                            // loop for each dependencies and check it if needed
                            for (String moduleName : metadata.getDependencies(module.getVersion())) {
                                dependencyModule = ternModules.get(moduleName);
                                if (dependencyModule != null) {
                                    // update module selection
                                    if (!tableViewer.getChecked(dependencyModule)) {
                                        tableViewer.setChecked(dependencyModule, true);
                                    }
                                    // update checked modules list
                                    updateCheckedModules(dependencyModule, true);
                                    if (dependencyModule instanceof ITernModuleConfigurable) {
                                        ITernModuleConfigurable configurable = (ITernModuleConfigurable) dependencyModule;
                                        if (configurable.hasVersion()) {
                                            // update version
                                            String version = configurable.getModule(moduleName).getVersion();
                                            versionEditiongSupport.setValue(dependencyModule, version);
                                        }
                                    }
                                }
                            }
                        }
                    }
                } finally {
                    checkUpdating = false;
                }
            }
        });

        // when a module is selected, details, dependencies, options tabs must
        // be
        // refreshed.
        addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent e) {
                if (!e.getSelection().isEmpty()) {
                    ITernModule module = (ITernModule) ((IStructuredSelection) e.getSelection()).getFirstElement();
                    refreshModule(module);
                } else {
                    refreshModule(null);
                }
            }
        });
        restoreColumnSettings();
    }

    private void createModulesDetails(Composite parent) {

        // Create tab folder.
        tabFolder = new TabFolder(parent, SWT.NONE);
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        data.heightHint = 80;
        tabFolder.setLayoutData(data);

        // create details tab
        this.detailsPanel = new DetailsPanel(tabFolder, project);
        detailsTabItem = new TabItem(tabFolder, SWT.NULL);
        detailsTabItem.setControl(this.detailsPanel);
        detailsTabItem.setText(TernUIMessages.TernModulesBlock_detailsTabLabel);

        // create dependencies tab
        this.dependenciesPanel = new DependenciesPanel(tabFolder, project);
        TabItem dependenciesTabItem = new TabItem(tabFolder, SWT.NULL);
        dependenciesTabItem.setControl(this.dependenciesPanel);
        dependenciesTabItem.setText(TernUIMessages.TernModulesBlock_dependenciesTabLabel);

        // create options panel.
        this.optionsPanel = new OptionsPanel(tabFolder, project);
    }

    /**
     * Refresh tab items with the given module information
     * 
     * @param module
     */
    private void refreshModule(ITernModule module) {
        if (TernModuleHelper.hasOptions(module)) {
            // module has options, create options tab if needed
            if (optionsTabItem == null) {
                this.optionsTabItem = new TabItem(tabFolder, SWT.NULL);
                optionsTabItem.setControl(this.optionsPanel);
                optionsTabItem.setText(TernUIMessages.TernModulesBlock_optionsTabLabel);
            }
            optionsPanel.refresh(module);

        } else {
            // module has no options, don't display options tab
            if (optionsTabItem != null) {
                optionsTabItem.dispose();
            }
            optionsTabItem = null;
        }

        detailsPanel.refresh(module);
        dependenciesPanel.refresh(module);
        // select the details tab.
        tabFolder.setSelection(detailsTabItem);
    }

    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        tableViewer.addSelectionChangedListener(listener);
    }

    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        tableViewer.removeSelectionChangedListener(listener);
    }

    public void addCheckStateListener(ICheckStateListener listener) {
        tableViewer.addCheckStateListener(listener);
    }

    public void removeCheckStateListener(ICheckStateListener listener) {
        tableViewer.removeCheckStateListener(listener);
    }

    /**
     * Sorts by name.
     */
    private void sortByName() {
        tableViewer.setSorter(new ViewerSorter() {
            @Override
            public int compare(Viewer viewer, Object e1, Object e2) {
                if ((e1 instanceof ITernModule) && (e2 instanceof ITernModule)) {
                    ITernModule left = (ITernModule) e1;
                    ITernModule right = (ITernModule) e2;
                    return getNameOrLabel(left).compareToIgnoreCase(getNameOrLabel(right));
                }
                return super.compare(viewer, e1, e2);
            }

            private String getNameOrLabel(ITernModule module) {
                TernModuleMetadata metadata = module.getMetadata();
                if (metadata == null) {
                    return module.getName();
                }
                return StringUtils.isEmpty(metadata.getLabel()) ? module.getName() : metadata.getLabel();
            }

            @Override
            public boolean isSorterProperty(Object element, String property) {
                return true;
            }
        });
    }

    public void setTernModules(ITernModule[] modules) {
        ternModules.clear();
        for (ITernModule module : modules) {
            if (module instanceof ITernModuleConfigurable) {
                ITernModuleConfigurable configurable = (ITernModuleConfigurable) module;
                if (!configurable.hasVersion()) {
                    ternModules.put(module.getName(), module);
                } else {
                    Collection<ITernModule> mods = configurable.getModules();
                    for (ITernModule mod : mods) {
                        ternModules.put(mod.getName(), module);
                    }
                }
            } else {
                ternModules.put(module.getName(), module);
            }
        }
        tableViewer.setInput(modules);
    }

    public Collection<ITernModule> getCheckedModules() {
        if (checkedModules != null) {
            return checkedModules;
        }
        return Collections.emptyList();
    }

    public void setCheckedModules(Collection<ITernModule> checkedModules) {
        this.checkedModules = checkedModules;
        tableViewer.setCheckedElements(checkedModules.toArray());
    }

    public void setCheckedModule(ITernModule module, boolean selected) {
        updateCheckedModules(module, selected);
        tableViewer.setChecked(module, selected);
    }

    private void updateCheckedModules(ITernModule module, boolean checked) {
        if (checked) {
            if (!checkedModules.contains(module)) {
                checkedModules.add(module);
            }
        } else {
            checkedModules.remove(module);
        }
    }

    @Override
    protected void setSortColumn(int column) {
        switch (column) {
        case 1:
            sortByName();
            break;
        }
        super.setSortColumn(column);
    }

    @Override
    protected Table getTable() {
        return tableViewer.getTable();
    }

    @Override
    protected IDialogSettings getDialogSettings() {
        return TernUIPlugin.getDefault().getDialogSettings();
    }

    @Override
    protected String getQualifier() {
        return TernUIPlugin.PLUGIN_ID + ".modules.";
    }

    /**
     * Load plugins from tern project.
     * 
     * @param moduleNames
     * @param repository
     */
    public void loadModules() {
        try {

            // load modules from the given tern project
            IIDETernProject ternProject = getTernProject();
            if (ternProject != null) {

                // Add list of tern modules from the repository and local
                List<ITernModule> allModules = ternProject.getAllModules();
                // Group by type
                allModules = TernModuleHelper.groupByType(allModules);

                // checked modules
                List<ITernModule> checkedModules = TernCorePlugin.getTernRepositoryManager()
                        .getCheckedModules(ternProject, allModules);
                refresh(allModules, checkedModules);
                /*
                 * if (checkedModules.size() > 0) { ITernModule firstModule =
                 * checkedModules.get(0); tableViewer.setSelection(new
                 * StructuredSelection( firstModule)); }
                 */
            }

        } catch (Throwable e) {
            Trace.trace(Trace.SEVERE, "Error while loading plugins.", e);
        }
    }

    /**
     * Load modules from the given tern repository and check the modules with
     * the given checked module names.
     * 
     * @param repository
     *            tern repository which hosts tern modules.
     * @param checkedModuleNames
     *            module names to check.
     */
    public void loadModules(ITernRepository repository, String[] checkedModuleNames) {
        try {
            // load modules from the given repository
            List<ITernModule> allModules = new ArrayList<ITernModule>(Arrays.asList(repository.getModules()));
            // Group by type
            List<ITernModule> groupedModules = TernModuleHelper.groupByType(allModules);
            // checked modules
            List<ITernModule> checkedModules = TernCorePlugin.getTernRepositoryManager()
                    .getCheckedModules(checkedModuleNames, allModules, groupedModules);
            refresh(groupedModules, checkedModules);
        } catch (Throwable e) {
            Trace.trace(Trace.SEVERE, "Error while loading plugins.", e);
        }
    }

    public void refresh(Collection<ITernModule> allModules, Collection<ITernModule> checkedModules) {
        this.setTernModules(allModules.toArray(ITernModule.EMPTY_MODULE));
        this.setCheckedModules(checkedModules);
    }

    /**
     * Returns true if tern modules dependencies must be select when a tern
     * module is selected and false otherwise.
     * 
     * @return true if tern modules dependencies must be select when a tern
     *         module is selected and false otherwise.
     */
    private boolean isSelectDependencies() {
        return selectDependenciesCheckbox != null && selectDependenciesCheckbox.getSelection();
    }

    /**
     * Returns the tern project and null otherwise.
     * 
     * @return the tern project and null otherwise.
     * 
     * @throws CoreException
     */
    public IIDETernProject getTernProject() throws CoreException {
        return project != null ? TernCorePlugin.getTernProject(project) : null;
    }

    /**
     * Returns the eclipse project and null otherwise.
     * 
     * @return the eclipse project and null otherwise.
     */
    public IProject getProject() {
        return project;
    }

    public void setEnabled(boolean enabled) {
        getTable().setEnabled(enabled);
    }

    public boolean isCheckUpdating() {
        return checkUpdating;
    }

}