bndtools.views.ResolutionView.java Source code

Java tutorial

Introduction

Here is the source code for bndtools.views.ResolutionView.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.views;

import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bndtools.core.ui.icons.Icons;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
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.action.IToolBarManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.resource.Capability;

import aQute.bnd.osgi.Clazz;
import bndtools.Plugin;
import bndtools.model.resolution.CapReqMapContentProvider;
import bndtools.model.resolution.CapabilityLabelProvider;
import bndtools.model.resolution.RequirementWrapper;
import bndtools.model.resolution.RequirementWrapperLabelProvider;
import bndtools.tasks.AnalyseBundleResolutionJob;
import bndtools.utils.PartAdapter;
import bndtools.utils.SelectionUtils;

public class ResolutionView extends ViewPart implements ISelectionListener, IResourceChangeListener {

    private static String[] FILTERED_CAPABILITY_NAMESPACES = { IdentityNamespace.IDENTITY_NAMESPACE,
            HostNamespace.HOST_NAMESPACE };

    private Display display = null;

    private Tree reqsTree = null;
    private Table capsTable = null;

    private TreeViewer reqsViewer;
    private TableViewer capsViewer;

    private ViewerFilter hideSelfImportsFilter;

    private boolean inputLocked = false;
    private boolean outOfDate = false;
    private File[] selectedFiles;
    private Job analysisJob;

    private final Set<String> filteredCapabilityNamespaces;

    public ResolutionView() {
        filteredCapabilityNamespaces = new HashSet<String>(Arrays.asList(FILTERED_CAPABILITY_NAMESPACES));
    }

    private final IPartListener partAdapter = new PartAdapter() {
        @Override
        public void partActivated(IWorkbenchPart part) {
            if (part == ResolutionView.this) {
                if (outOfDate) {
                    executeAnalysis();
                }
            } else if (part instanceof IEditorPart) {
                IEditorInput editorInput = ((IEditorPart) part).getEditorInput();
                IFile file = ResourceUtil.getFile(editorInput);
                if (file != null) {
                    if (file.getName().toLowerCase().endsWith(".bnd")
                            || file.getName().toLowerCase().endsWith(".jar")) {
                        selectedFiles = new File[] { file.getLocation().toFile() };

                        if (getSite().getPage().isPartVisible(ResolutionView.this)) {
                            executeAnalysis();
                        } else {
                            outOfDate = true;
                        }
                    }
                }
            }
        }
    };

    @Override
    public void createPartControl(Composite parent) {
        this.display = parent.getDisplay();

        SashForm splitPanel = new SashForm(parent, SWT.HORIZONTAL);
        splitPanel.setLayout(new FillLayout());

        Composite reqsPanel = new Composite(splitPanel, SWT.NONE);
        reqsPanel.setBackground(parent.getBackground());

        GridLayout reqsLayout = new GridLayout(1, false);
        reqsLayout.marginWidth = 0;
        reqsLayout.marginHeight = 0;
        reqsLayout.verticalSpacing = 2;
        reqsPanel.setLayout(reqsLayout);
        new Label(reqsPanel, SWT.NONE).setText("Requirements:");
        reqsTree = new Tree(reqsPanel, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER);
        reqsTree.setHeaderVisible(false);
        reqsTree.setLinesVisible(false);
        reqsTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        reqsViewer = new TreeViewer(reqsTree);
        ColumnViewerToolTipSupport.enableFor(reqsViewer);
        reqsViewer.setLabelProvider(new RequirementWrapperLabelProvider(true));
        reqsViewer.setContentProvider(new CapReqMapContentProvider());

        Composite capsPanel = new Composite(splitPanel, SWT.NONE);
        capsPanel.setBackground(parent.getBackground());

        GridLayout capsLayout = new GridLayout(1, false);
        capsLayout.marginWidth = 0;
        capsLayout.marginHeight = 0;
        capsLayout.verticalSpacing = 2;
        capsPanel.setLayout(capsLayout);
        new Label(capsPanel, SWT.NONE).setText("Capabilities:");
        capsTable = new Table(capsPanel, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER);
        capsTable.setHeaderVisible(false);
        capsTable.setLinesVisible(false);
        capsTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        capsViewer = new TableViewer(capsTable);
        ColumnViewerToolTipSupport.enableFor(capsViewer);
        capsViewer.setLabelProvider(new CapabilityLabelProvider(true));
        capsViewer.setContentProvider(new CapReqMapContentProvider());
        capsViewer.setFilters(new ViewerFilter[] { new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parent, Object element) {
                return !filteredCapabilityNamespaces.contains(((Capability) element).getNamespace());
            }
        } });

        hideSelfImportsFilter = new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                if (element instanceof RequirementWrapper) {
                    RequirementWrapper rw = (RequirementWrapper) element;
                    return !rw.resolved;
                }
                return true;
            }
        };
        reqsViewer.setFilters(new ViewerFilter[] { hideSelfImportsFilter });

        reqsViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY,
                new Transfer[] { LocalSelectionTransfer.getTransfer() }, new LocalTransferDragListener(reqsViewer));

        capsViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY,
                new Transfer[] { LocalSelectionTransfer.getTransfer() }, new LocalTransferDragListener(capsViewer));

        reqsViewer.addOpenListener(new IOpenListener() {
            @Override
            public void open(OpenEvent event) {
                IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                for (Iterator<?> iter = selection.iterator(); iter.hasNext();) {
                    Object item = iter.next();
                    if (item instanceof Clazz) {
                        Clazz clazz = (Clazz) item;
                        String className = clazz.getFQN();
                        IType type = null;
                        if (selectedFiles != null) {
                            IWorkspaceRoot wsroot = ResourcesPlugin.getWorkspace().getRoot();
                            for (File selectedFile : selectedFiles) {
                                IFile[] wsfiles = wsroot.findFilesForLocationURI(selectedFile.toURI());
                                for (IFile wsfile : wsfiles) {
                                    IJavaProject javaProject = JavaCore.create(wsfile.getProject());
                                    try {
                                        type = javaProject.findType(className);
                                        if (type != null)
                                            break;
                                    } catch (JavaModelException e) {
                                        ErrorDialog.openError(getSite().getShell(), "Error", "", new Status(
                                                IStatus.ERROR, Plugin.PLUGIN_ID, 0,
                                                MessageFormat.format("Error opening Java class '{0}'.", className),
                                                e));
                                    }
                                }
                            }
                        }
                        try {
                            if (type != null)
                                JavaUI.openInEditor(type, true, true);
                        } catch (PartInitException e) {
                            ErrorDialog.openError(getSite().getShell(), "Error", "", new Status(IStatus.ERROR,
                                    Plugin.PLUGIN_ID, 0,
                                    MessageFormat.format("Error opening Java editor for class '{0}'.", className),
                                    e));
                        } catch (JavaModelException e) {
                            ErrorDialog.openError(getSite().getShell(), "Error", "",
                                    new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0,
                                            MessageFormat.format("Error opening Java class '{0}'.", className), e));
                        }
                    }
                }
            }
        });

        fillActionBars();

        getSite().getPage().addPostSelectionListener(this);
        getSite().getPage().addPartListener(partAdapter);
        ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);

        // Current selection & part
        IWorkbenchPart activePart = getSite().getPage().getActivePart();
        ISelection activeSelection = getSite().getWorkbenchWindow().getSelectionService().getSelection();
        selectionChanged(activePart, activeSelection);
    }

    void fillActionBars() {
        IAction toggleShowSelfImports = new Action("showSelfImports", IAction.AS_CHECK_BOX) {
            @Override
            public void runWithEvent(Event event) {
                if (isChecked()) {
                    reqsViewer.removeFilter(hideSelfImportsFilter);
                } else {
                    reqsViewer.addFilter(hideSelfImportsFilter);
                }
            }
        };
        toggleShowSelfImports.setChecked(false);
        toggleShowSelfImports.setImageDescriptor(
                AbstractUIPlugin.imageDescriptorFromPlugin(Plugin.PLUGIN_ID, "/icons/package_folder_impexp.gif"));
        toggleShowSelfImports.setToolTipText(
                "Show resolved requirements.\n\nInclude requirements that are resolved within the set of selected bundles.");

        IAction toggleLockInput = new Action("lockInput", IAction.AS_CHECK_BOX) {
            @Override
            public void runWithEvent(Event event) {
                inputLocked = isChecked();
                if (!inputLocked) {
                    executeAnalysis();
                }
            }
        };
        toggleLockInput.setChecked(false);
        toggleLockInput.setImageDescriptor(Icons.desc("lock"));
        toggleLockInput.setToolTipText("Lock to current selection");

        IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
        toolBarManager.add(toggleShowSelfImports);
        toolBarManager.add(toggleLockInput);
    }

    @Override
    public void setFocus() {
    }

    @Override
    public void dispose() {
        getSite().getPage().removeSelectionListener(this);
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
        getSite().getPage().removePartListener(partAdapter);
        super.dispose();
    }

    public void setInput(File[] sourceFiles, Map<String, List<Capability>> capabilities,
            Map<String, List<RequirementWrapper>> requirements) {
        selectedFiles = sourceFiles;
        if (reqsTree != null && !reqsTree.isDisposed() && capsTable != null && !capsTable.isDisposed()) {
            reqsViewer.setInput(requirements);
            capsViewer.setInput(capabilities);

            String label;
            if (sourceFiles != null && sourceFiles.length > 0) {
                StringBuilder builder = new StringBuilder();

                if (sourceFiles.length == 1)
                    builder.append(sourceFiles[0].getName()).append(" - ")
                            .append(sourceFiles[0].getParentFile().getAbsolutePath());
                else {
                    for (int i = 0; i < sourceFiles.length; i++) {
                        if (i > 0)
                            builder.append(", ");
                        builder.append(sourceFiles[i].getName());
                    }
                }
                label = builder.toString();
            } else {
                label = "<no input>";
            }
            setContentDescription(label);
        }
    }

    @Override
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        if (selection == null || selection.isEmpty())
            return;

        Collection<File> fileList = getFilesFromSelection(selection);

        // Filter out non-bundle files/dirs
        for (Iterator<File> iter = fileList.iterator(); iter.hasNext();) {
            File file = iter.next();
            if (file.isDirectory()) {
                File manifestFile = new File(file, "META-INF/MANIFEST.MF");
                if (!manifestFile.isFile())
                    iter.remove();
            } else {
                String fileName = file.getName().toLowerCase();
                if (!fileName.endsWith(".bnd") && !fileName.endsWith(".jar"))
                    iter.remove();
            }
        }

        if (fileList.isEmpty())
            return;

        File[] files = fileList.toArray(new File[fileList.size()]);
        if (!Arrays.equals(files, selectedFiles)) {
            this.selectedFiles = files;

            if (getSite().getPage().isPartVisible(this)) {
                executeAnalysis();
            } else {
                outOfDate = true;
            }
        }
    }

    private static Collection<File> getFilesFromSelection(ISelection selection) {
        if (selection.isEmpty() || !(selection instanceof IStructuredSelection)) {
            return Collections.emptyList();
        }

        IStructuredSelection structSel = (IStructuredSelection) selection;
        Collection<File> result = new ArrayList<File>();
        Iterator<?> iter = structSel.iterator();
        while (iter.hasNext()) {
            Object element = iter.next();
            File file = SelectionUtils.adaptObject(element, File.class);
            if (file != null) {
                result.add(file);
            } else {
                IResource resource = SelectionUtils.adaptObject(element, IResource.class);
                if (resource != null) {
                    IPath location = resource.getLocation();
                    if (location != null)
                        result.add(location.toFile());
                }
            }
        }
        return result;
    }

    void executeAnalysis() {
        if (inputLocked)
            return;

        outOfDate = false;
        synchronized (this) {
            Job oldJob = analysisJob;
            if (oldJob != null && oldJob.getState() != Job.NONE)
                oldJob.cancel();

            if (selectedFiles != null) {
                final AnalyseBundleResolutionJob tmp = new AnalyseBundleResolutionJob("importExportAnalysis",
                        selectedFiles);
                tmp.setSystem(true);

                tmp.addJobChangeListener(new JobChangeAdapter() {
                    @Override
                    public void aboutToRun(IJobChangeEvent event) {
                        if (display != null && !display.isDisposed()) {
                            Runnable update = new Runnable() {
                                @Override
                                public void run() {
                                    setContentDescription("Working...");
                                }
                            };
                            if (display.getThread() == Thread.currentThread())
                                update.run();
                            else
                                display.asyncExec(update);
                        }
                    }

                    @Override
                    public void done(IJobChangeEvent event) {
                        IStatus result = tmp.getResult();
                        if (result != null && result.isOK()) {
                            if (display != null && !display.isDisposed())
                                display.asyncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        setInput(tmp.getResultFileArray(), tmp.getCapabilities(),
                                                tmp.getRequirements());
                                    }
                                });
                        }
                    }
                });

                analysisJob = tmp;
                analysisJob.schedule(500);
            } else {
                analysisJob = null;
            }
        }
    }

    @Override
    public void resourceChanged(IResourceChangeEvent event) {
        if (selectedFiles != null) {
            IWorkspaceRoot wsroot = ResourcesPlugin.getWorkspace().getRoot();
            for (File file : selectedFiles) {
                IFile[] wsfiles = wsroot.findFilesForLocationURI(file.toURI());
                for (IFile wsfile : wsfiles) {
                    if (event.getDelta().findMember(wsfile.getFullPath()) != null) {
                        executeAnalysis();
                        break;
                    }
                }
            }
        }
    }

    static class LocalTransferDragListener implements DragSourceListener {

        private final Viewer viewer;

        public LocalTransferDragListener(Viewer viewer) {
            this.viewer = viewer;
        }

        @Override
        public void dragStart(DragSourceEvent event) {
        }

        @Override
        public void dragSetData(DragSourceEvent event) {
            LocalSelectionTransfer transfer = LocalSelectionTransfer.getTransfer();
            if (transfer.isSupportedType(event.dataType))
                transfer.setSelection(viewer.getSelection());
        }

        @Override
        public void dragFinished(DragSourceEvent event) {
        }
    }

}