bndtools.editor.components.ComponentListPart.java Source code

Java tutorial

Introduction

Here is the source code for bndtools.editor.components.ComponentListPart.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Neil Bartlett.
 * 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:
 *     Neil Bartlett - initial API and implementation
 *******************************************************************************/
package bndtools.editor.components;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
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.ui.JavaUI;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Table;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.IMessageManager;
import org.eclipse.ui.forms.SectionPart;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.part.ResourceTransfer;

import aQute.lib.osgi.Constants;
import aQute.libg.header.Attrs;
import bndtools.Plugin;
import bndtools.editor.model.BndEditModel;
import bndtools.model.clauses.ExportedPackage;
import bndtools.model.clauses.ServiceComponent;
import bndtools.utils.PathUtils;

public class ComponentListPart extends SectionPart implements PropertyChangeListener {

    private static final String XML_SUFFIX = ".xml"; //$NON-NLS-1$
    private List<String> componentNames;
    private Map<String, ServiceComponent> componentMap;

    private IManagedForm managedForm;
    private Table table;
    private TableViewer viewer;
    private BndEditModel model;

    public ComponentListPart(Composite parent, FormToolkit toolkit, int style) {
        super(parent, toolkit, style);
        createSection(getSection(), toolkit);
    }

    void createSection(Section section, FormToolkit toolkit) {
        section.setText(Messages.ComponentListPart_listSectionTitle);

        Composite composite = toolkit.createComposite(section);
        section.setClient(composite);

        table = toolkit.createTable(composite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);

        viewer = new TableViewer(table);
        viewer.setUseHashlookup(true);
        viewer.setContentProvider(new ArrayContentProvider());
        viewer.setLabelProvider(new ServiceComponentLabelProvider());

        final Button btnAdd = toolkit.createButton(composite, Messages.ComponentListPart_addButton, SWT.PUSH);
        final Button btnRemove = toolkit.createButton(composite, Messages.ComponentListPart_RemoveButton, SWT.PUSH);

        toolkit.paintBordersFor(section);

        // Listeners
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                ArrayList<ServiceComponent> selectedComponents = new ArrayList<ServiceComponent>(selection.size());

                @SuppressWarnings("rawtypes")
                Iterator iterator = selection.iterator();
                while (iterator.hasNext()) {
                    String name = (String) iterator.next();
                    ServiceComponent component = componentMap.get(name);
                    if (component != null)
                        selectedComponents.add(component);
                }

                managedForm.fireSelectionChanged(ComponentListPart.this,
                        new StructuredSelection(selectedComponents));
                btnRemove.setEnabled(!selection.isEmpty());
            }
        });
        viewer.addOpenListener(new IOpenListener() {
            public void open(OpenEvent event) {
                String name = (String) ((IStructuredSelection) event.getSelection()).getFirstElement();
                if (name != null) {
                    doOpenComponent(name);
                }
            }
        });
        viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, new Transfer[] { ResourceTransfer.getInstance() },
                new ComponentListDropAdapter(viewer));
        btnAdd.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    doAdd();
                } catch (Exception x) {
                    Plugin.logError("Error adding component", x);
                }
            }
        });
        btnRemove.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                doRemove();
            }
        });

        // Layout
        GridData gd;
        section.setLayoutData(new GridData(GridData.FILL_BOTH));
        composite.setLayout(new GridLayout(2, false));
        gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 3);
        gd.widthHint = 250;
        table.setLayoutData(gd);
        btnAdd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
        btnRemove.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
    }

    void doAdd() throws Exception {
        String name;
        ServiceComponent component;
        int i = 0;
        while (true) {
            if (i == 0)
                name = ""; //$NON-NLS-1$
            else
                name = String.format("%d", i); //$NON-NLS-1$
            if (!componentMap.containsKey(name)) {
                component = new ServiceComponent(name, new Attrs());
                componentMap.put(name, component);
                componentNames.add(name);
                break;
            }
            if (i > 100)
                throw new Exception("Unable to find a free component name after 100 tries!");
        }
        viewer.add(name);
        viewer.setSelection(new StructuredSelection(name), true);
        checkComponentPackagesIncluded();
        markDirty();
    }

    void doRemove() {
        Iterator<?> iter = ((IStructuredSelection) viewer.getSelection()).iterator();
        while (iter.hasNext()) {
            Object item = iter.next();
            componentMap.remove(item);
            componentNames.remove(item);
            viewer.remove(item);
        }
        checkComponentPackagesIncluded();
        markDirty();
    }

    void doOpenComponent(String componentName) {
        ServiceComponent component = componentMap.get(componentName);
        if (component == null)
            return;

        if (component.isPath()) {
            IFormPage page = (IFormPage) getManagedForm().getContainer();
            IResource resource = ResourceUtil.getResource(page.getEditorInput());
            IProject project = resource.getProject();
            IResource member = project.findMember(component.getName());
            if (member != null && member.getType() == IResource.FILE) {
                try {
                    IDE.openEditor(page.getEditorSite().getPage(), (IFile) member);
                } catch (PartInitException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } else if (!component.getName().endsWith("*")) { //$NON-NLS-1$
            try {
                IType type = getJavaProject().findType(component.getName());
                if (type != null) {
                    JavaUI.openInEditor(type, true, true);
                }
            } catch (JavaModelException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (PartInitException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    void checkComponentPackagesIncluded() {
        IMessageManager msgs = getManagedForm().getMessageManager();
        msgs.setDecorationPosition(SWT.TOP | SWT.RIGHT);
        msgs.removeMessages();

        int index = 0;

        if (componentMap != null) {
            for (Entry<String, ServiceComponent> entry : componentMap.entrySet()) {
                ServiceComponent component = entry.getValue();
                if (component.getName().length() > 0 && !component.isPath()) {
                    String classOrWildcard = entry.getKey();
                    if (classOrWildcard != null && classOrWildcard.length() > 0) {
                        int dotIndex = classOrWildcard.lastIndexOf('.');
                        if (dotIndex == -1) {
                            msgs.addMessage("_comp_default_pkg" + index, //$NON-NLS-1$
                                    Messages.ComponentListPart_warningDefaultPkg, null, IMessageProvider.WARNING);
                        } else {
                            final String packageName = classOrWildcard.substring(0, dotIndex);
                            final BndEditModel model = (BndEditModel) getManagedForm().getInput();
                            if (!model.isIncludedPackage(packageName)) {
                                String message = MessageFormat
                                        .format(Messages.ComponentListPart_warningPkgNotIncluded, packageName);
                                IAction[] fixes = new Action[] { new Action(MessageFormat
                                        .format(Messages.ComponentListPart_fixAddToPrivatePkgs, packageName)) {
                                    @Override
                                    public void run() {
                                        model.addPrivatePackage(packageName);
                                        markDirty();
                                    }
                                }, new Action(MessageFormat.format(Messages.ComponentListPart_fixAddToExportedPkgs,
                                        packageName)) {
                                    @Override
                                    public void run() {
                                        model.addExportedPackage(new ExportedPackage(packageName, null));
                                        markDirty();
                                    }
                                } };
                                msgs.addMessage("_comp_nonincluded_pkg" + index, message, fixes, //$NON-NLS-1$
                                        IMessageProvider.WARNING);
                            }
                        }
                    }
                }
                index++;
            }
        }
    }

    @Override
    public void initialize(IManagedForm form) {
        super.initialize(form);
        this.managedForm = form;
        this.model = (BndEditModel) form.getInput();
        this.model.addPropertyChangeListener(this);
    }

    @Override
    public void dispose() {
        super.dispose();
        this.model.removePropertyChangeListener(this);
    }

    @Override
    public void refresh() {
        super.refresh();

        // Deep-copy the model
        Collection<ServiceComponent> componentList = model.getServiceComponents();
        if (componentList != null) {
            componentNames = new ArrayList<String>(componentList.size());
            componentMap = new HashMap<String, ServiceComponent>(componentList.size());
            for (ServiceComponent component : componentList) {
                componentNames.add(component.getName());
                componentMap.put(component.getName(), component.clone());
            }
        } else {
            componentNames = new LinkedList<String>();
            componentMap = new HashMap<String, ServiceComponent>();
        }

        viewer.setInput(componentNames);
        checkComponentPackagesIncluded();
    }

    @Override
    public void commit(boolean onSave) {
        try {
            model.removePropertyChangeListener(this);
            model.setServiceComponents(
                    componentMap.isEmpty() ? null : new ArrayList<ServiceComponent>(componentMap.values()));
        } finally {
            model.addPropertyChangeListener(this);
            super.commit(onSave);
        }
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if (Constants.SERVICE_COMPONENT.equals(evt.getPropertyName())) {
            // Refresh content if ServiceComponents changed
            IFormPage page = (IFormPage) managedForm.getContainer();
            if (page.isActive())
                refresh();
            else
                markStale();
        } else if (Constants.PRIVATE_PACKAGE.equals(evt.getPropertyName())
                || Constants.EXPORT_PACKAGE.equals(evt.getPropertyName())) {
            // Content of bundle has changed, re-validate component's for included packages
            checkComponentPackagesIncluded();
        }
    }

    public void updateLabel(String oldName, String newName) {
        int index = componentNames.indexOf(oldName);

        if (index > -1) {
            componentNames.remove(index);
            ServiceComponent component = componentMap.remove(oldName);
            if (component != null) {
                componentNames.add(index, newName);
                componentMap.put(newName, component);
                viewer.replace(newName, index);
            } else {
                viewer.remove(oldName);
            }
        }
    }

    IJavaProject getJavaProject() {
        IFormPage page = (IFormPage) getManagedForm().getContainer();
        IEditorInput input = page.getEditorInput();

        IFile file = ResourceUtil.getFile(input);
        if (file != null) {
            return JavaCore.create(file.getProject());
        } else {
            return null;
        }
    }

    private class ComponentListDropAdapter extends ViewerDropAdapter {

        protected ComponentListDropAdapter(Viewer viewer) {
            super(viewer);
        }

        @Override
        public void dragEnter(DropTargetEvent event) {
            event.detail = DND.DROP_COPY;
            super.dragEnter(event);
        }

        @Override
        public boolean validateDrop(Object target, int operation, TransferData transferType) {
            return ResourceTransfer.getInstance().isSupportedType(transferType);
        }

        @Override
        public boolean performDrop(Object data) {
            Object target = getCurrentTarget();
            int loc = getCurrentLocation();

            int insertionIndex = -1;
            if (target != null) {
                insertionIndex = componentNames.indexOf(target);
                if (insertionIndex > -1 && loc == LOCATION_ON || loc == LOCATION_AFTER)
                    insertionIndex++;
            }

            List<String> addedNames = new ArrayList<String>();
            Map<String, ServiceComponent> addedMap = new HashMap<String, ServiceComponent>();
            if (data instanceof IResource[]) {
                IResource[] resources = (IResource[]) data;
                for (IResource resource : resources) {
                    IJavaElement javaElement = JavaCore.create(resource);
                    if (javaElement != null) {
                        try {
                            if (javaElement instanceof IType) {
                                IType type = (IType) javaElement;
                                if (type.isClass() && Flags.isPublic(type.getFlags())) {
                                    String compName = type.getPackageFragment().getElementName() + "." //$NON-NLS-1$
                                            + type.getElementName();
                                    ServiceComponent component = new ServiceComponent(compName, new Attrs());
                                    addedNames.add(compName);
                                    addedMap.put(compName, component);
                                }
                            } else if (javaElement instanceof ICompilationUnit) {
                                IType[] allTypes = ((ICompilationUnit) javaElement).getAllTypes();
                                for (IType type : allTypes) {
                                    if (type.isClass() && Flags.isPublic(type.getFlags())) {
                                        String compName = type.getPackageFragment().getElementName() + "." //$NON-NLS-1$
                                                + type.getElementName();
                                        ServiceComponent component = new ServiceComponent(compName, new Attrs());
                                        addedNames.add(compName);
                                        addedMap.put(compName, component);
                                    }
                                }
                            }
                        } catch (JavaModelException e) {
                            Plugin.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0,
                                    Messages.ComponentListPart_errorJavaType, e));
                        }
                    } else if (resource.getName().endsWith(XML_SUFFIX)) {
                        IFormPage formPage = (IFormPage) getManagedForm().getContainer();
                        IFile bndFile = ResourceUtil.getFile(formPage.getEditorInput());

                        IPath relativePath = PathUtils.makeRelativeTo(resource.getFullPath(),
                                bndFile.getFullPath());

                        String compName = relativePath.toString();
                        ServiceComponent component = new ServiceComponent(compName, new Attrs());
                        addedNames.add(compName);
                        addedMap.put(compName, component);
                    }
                }
            }

            if (!addedNames.isEmpty()) {
                componentMap.putAll(addedMap);
                if (insertionIndex == -1 || insertionIndex == componentNames.size()) {
                    componentNames.addAll(addedNames);
                    viewer.add(addedNames.toArray(new String[addedNames.size()]));
                } else {
                    componentNames.addAll(insertionIndex, addedNames);
                    viewer.refresh();
                }
            }
            viewer.setSelection(new StructuredSelection(addedNames), true);
            checkComponentPackagesIncluded();
            markDirty();
            return true;
        }
    }

    void setSelectedComponent(ServiceComponent component) {
        viewer.setSelection(new StructuredSelection(component.getName()));
    }
}