org.eclipse.recommenders.internal.apidocs.rcp.ApidocsView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.recommenders.internal.apidocs.rcp.ApidocsView.java

Source

/**
 * Copyright (c) 2010, 2012 Darmstadt University of Technology.
 * 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:
 *     Sebastian Proksch - initial API and implementation
 *     Patrick Gottschaemmer, Olav Lenz - add Drag'n'Drop support
 *     Olav Lenz - externalize Strings.
 */
package org.eclipse.recommenders.internal.apidocs.rcp;

import static org.eclipse.recommenders.internal.apidocs.rcp.ApidocsViewUtils.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
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.ViewerComparator;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.recommenders.apidocs.rcp.ApidocProvider;
import org.eclipse.recommenders.internal.apidocs.rcp.l10n.LogMessages;
import org.eclipse.recommenders.internal.apidocs.rcp.l10n.Messages;
import org.eclipse.recommenders.rcp.JavaElementSelectionEvent;
import org.eclipse.recommenders.rcp.utils.PartListener2Adapter;
import org.eclipse.recommenders.utils.Logs;
import org.eclipse.recommenders.utils.rcp.Selections;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.part.ViewPart;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

public class ApidocsView extends ViewPart {

    public static final String ID = "org.eclipse.recommenders.apidocs.rcp.views.apidocs"; //$NON-NLS-1$

    private final EventBus workspaceBus;
    private final SubscriptionManager subscriptionManager;
    private final List<ApidocProvider> providers;
    private final ApidocsPreferences preferences;

    private static final long LABEL_FLAGS = JavaElementLabels.ALL_FULLY_QUALIFIED
            | JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_TYPES
            | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
            | JavaElementLabels.F_PRE_TYPE_SIGNATURE | JavaElementLabels.T_TYPE_PARAMETERS;
    private static final int MOVE_AFTER = 1;
    private static final int MOVE_BEFORE = 0;

    private final JavaElementLabelProvider labelProvider = new JavaElementLabelProvider((int) LABEL_FLAGS);

    private SashForm sash;
    private ScrolledComposite scrollable;
    private Composite content;
    private TableViewer viewer;
    private List<ApidocProvider> providerRanking;

    private boolean visible = true;

    private ApidocProvider activeProvider;
    private JavaElementSelectionEvent activeSelection;

    @Inject
    public ApidocsView(final EventBus workspaceBus, final SubscriptionManager subscriptionManager,
            final List<ApidocProvider> providers, final ApidocsPreferences preferences) {
        this.workspaceBus = workspaceBus;
        this.subscriptionManager = subscriptionManager;
        this.providers = providers;
        this.preferences = preferences;
        providerRanking = loadProviderRanking();
    }

    private List<ApidocProvider> loadProviderRanking() {
        List<ApidocProvider> providerRanking = new LinkedList<ApidocProvider>();
        Map<String, ApidocProvider> providerMap = fillProviderMap();
        List<String> providerIds = preferences.loadOrderedProviderIds();
        LinkedList<ApidocProvider> remainingProviders = new LinkedList<ApidocProvider>(providers);

        for (String providerName : providerIds) {
            ApidocProvider tmpProvider = providerMap.get(providerName);
            if (tmpProvider != null) {
                providerRanking.add(tmpProvider);
                remainingProviders.remove(tmpProvider);
            }
        }
        providerRanking.addAll(remainingProviders);
        return providerRanking;
    }

    private Map<String, ApidocProvider> fillProviderMap() {
        HashMap<String, ApidocProvider> providerMap = new HashMap<String, ApidocProvider>();
        for (ApidocProvider provider : providers) {
            providerMap.put(provider.getId(), provider);
        }
        return providerMap;
    }

    @VisibleForTesting
    public void storeProviderRanking() {
        preferences.storeProviderRanking(providerRanking);
    }

    @Override
    public void createPartControl(final Composite parent) {
        createSash(parent);
        createProviderOverview();
        createContentArea();
        addVisibilityListener();
        applyUiPreferences();
        workspaceBus.register(this);
    }

    private void createSash(final Composite parent) {
        sash = new SashForm(parent, SWT.SMOOTH);
        sash.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
        sash.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(final DisposeEvent e) {
                preferences.storeSashWeights(sash.getWeights());
            }
        });
    }

    private void createProviderOverview() {
        viewer = new TableViewer(sash, SWT.SINGLE);

        addDnDSupport();

        viewer.setComparator(new ViewerComparator() {

            @Override
            public int compare(Viewer viewer, Object first, Object second) {
                int indexFirst = providerRanking.indexOf(first);
                int indexSecond = providerRanking.indexOf(second);

                return indexFirst - indexSecond;
            }
        });

        viewer.setContentProvider(new ArrayContentProvider());
        viewer.setLabelProvider(new LabelProvider() {

            @Override
            public String getText(Object element) {
                return ((ApidocProvider) element).getDescription().getName();
            }

            @Override
            public Image getImage(Object element) {
                return ((ApidocProvider) element).getDescription().getImage();
            }
        });
        viewer.setInput(providers);
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                ApidocProvider newProvider = Selections.<ApidocProvider>getFirstSelected(event.getSelection())
                        .orNull();
                if (newProvider == activeProvider) {
                    return;
                }
                activeProvider = newProvider;
                Job job = new Job(Messages.JOB_UPDATING_APIDOCS) {

                    @Override
                    protected IStatus run(IProgressMonitor monitor) {
                        onJavaSelection(activeSelection);
                        return Status.OK_STATUS;
                    }
                };
                job.setSystem(true);
                job.schedule();
            }
        });
        viewer.setSelection(new StructuredSelection(Iterables.getFirst(providers, null)));
    }

    private void addDnDSupport() {
        final int operations = DND.DROP_MOVE;
        final Transfer[] transferTypes = new Transfer[] { DnDProviderTransfer.getInstance() };

        viewer.addDragSupport(operations, transferTypes, new DragSourceAdapter() {

            @Override
            public void dragSetData(final DragSourceEvent event) {
                final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();

                if (DnDProviderTransfer.getInstance().isSupportedType(event.dataType)) {
                    final ApidocProvider selectedProvider = (ApidocProvider) selection.getFirstElement();
                    DnDProviderTransfer.getInstance().setExtdocProvider(selectedProvider);
                }
            }
        });

        viewer.addDropSupport(operations, transferTypes, new ViewerDropAdapter(viewer) {

            private int newIndex;
            private int currentFeedback;

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

            @Override
            public void dragOver(final DropTargetEvent event) {
                if (determineLocation(event) == ViewerDropAdapter.LOCATION_BEFORE && isFirstProvider(event)) {
                    event.feedback = DND.FEEDBACK_INSERT_BEFORE;
                } else {
                    event.feedback = DND.FEEDBACK_INSERT_AFTER;
                }
                currentFeedback = event.feedback;
            }

            private boolean isFirstProvider(final DropTargetEvent event) {
                return providerRanking.indexOf(determineTarget(event)) == 0;
            }

            @Override
            public void drop(final DropTargetEvent event) {
                if (event.item != null) {
                    newIndex = providerRanking.indexOf(event.item.getData());
                } else {
                    newIndex = providerRanking.size() - 1;
                }
                performDrop(event.data);
            }

            @Override
            public boolean performDrop(final Object data) {
                final ApidocProvider provider = (ApidocProvider) data;
                final int oldIndex = providerRanking.indexOf(provider);

                if (currentFeedback == DND.FEEDBACK_INSERT_AFTER) {
                    moveAfter(oldIndex, newIndex);
                } else {
                    moveBefore(oldIndex, newIndex);
                }
                storeProviderRanking();
                viewer.refresh();
                return true;
            }
        });
    }

    private void move(int oldIndex, int newIndex, int moveStyle) {
        if (newIndex == oldIndex) {
            return;
        } else if (newIndex < oldIndex) {
            ApidocProvider tmp = providerRanking.remove(oldIndex);
            providerRanking.add(newIndex + moveStyle, tmp);
        } else {
            ApidocProvider tmp = providerRanking.remove(oldIndex);
            providerRanking.add(newIndex - 1 + moveStyle, tmp);
        }
    }

    @VisibleForTesting
    public void moveAfter(int oldIndex, int newIndex) {
        move(oldIndex, newIndex, MOVE_AFTER);
    }

    @VisibleForTesting
    public void moveBefore(int oldIndex, int newIndex) {
        move(oldIndex, newIndex, MOVE_BEFORE);
    }

    @VisibleForTesting
    public List<ApidocProvider> getProviderRanking() {
        return providerRanking;
    }

    private void createContentArea() {
        scrollable = new ScrolledComposite(sash, SWT.H_SCROLL | SWT.V_SCROLL);
        scrollable.getVerticalBar().setIncrement(20);
        scrollable.setExpandHorizontal(true);
        scrollable.setExpandVertical(true);
        content = new Composite(scrollable, SWT.NONE);
        content.setLayout(new GridLayout());
        content.setFont(JFaceResources.getDialogFont());
        ApidocsViewUtils.setInfoBackgroundColor(content);

        scrollable.setContent(content);
    }

    private void applyUiPreferences() {
        sash.setWeights(preferences.loadSashWeights());
    }

    private void addVisibilityListener() {
        getViewSite().getPage().addPartListener(new PartListener2Adapter() {

            @Override
            public void partHidden(final IWorkbenchPartReference partRef) {
                if (isExtdocView(partRef)) {
                    visible = false;
                }
            }

            @Override
            public void partVisible(final IWorkbenchPartReference partRef) {
                if (isExtdocView(partRef)) {
                    visible = true;
                }
            }

            private boolean isExtdocView(final IWorkbenchPartReference partRef) {
                return partRef.getPart(false) == ApidocsView.this;
            }

        });
    }

    @Override
    public void dispose() {
        workspaceBus.unregister(this);
        super.dispose();
    }

    @Subscribe
    public void onJavaSelection(final JavaElementSelectionEvent selection) {
        activeSelection = selection;
        if (visible && activeProvider != null && activeSelection != null) {
            try {
                disposeOldContentAndDisableRedrawOnContentArea();
                runProvider(selection);
                refreshAndEnableDrawContentArea();
            } catch (Exception e) {
                Logs.log(LogMessages.ERROR_FAILED_TO_UPDATE_VIEW, e, selection);
            }
        }
    }

    private void runProvider(JavaElementSelectionEvent selection)
            throws IllegalAccessException, InvocationTargetException {
        Optional<Method> opt = subscriptionManager.findSubscribedMethod(activeProvider, selection);
        if (opt.isPresent()) {
            Method method = opt.get();
            IJavaElement element = selection.getElement();
            method.invoke(activeProvider, element, selection, content);
        }
    }

    private void refreshAndEnableDrawContentArea() {
        content.getDisplay().asyncExec(new Runnable() {

            @Override
            public void run() {
                Point size = content.computeSize(SWT.DEFAULT, SWT.DEFAULT);
                scrollable.setMinSize(size);
                content.layout();
                // content.setRedraw(true);
            }
        });
    }

    private void disposeOldContentAndDisableRedrawOnContentArea() {
        content.getDisplay().syncExec(new Runnable() {

            @Override
            public void run() {
                // content.setRedraw(false);
                ApidocsViewUtils.disposeChildren(content);
                addCurrentSelectionHeader();
            }
        });
    }

    private void addCurrentSelectionHeader() {
        final IJavaElement element = activeSelection.getElement();
        final String text;
        switch (element.getElementType()) {
        case IJavaElement.PACKAGE_FRAGMENT_ROOT:
        case IJavaElement.PACKAGE_FRAGMENT:
            text = element.getElementName();
            break;
        case IJavaElement.LOCAL_VARIABLE:
            text = JavaElementLabels.getElementLabel(element,
                    JavaElementLabels.F_PRE_TYPE_SIGNATURE | JavaElementLabels.F_POST_QUALIFIED);
            break;
        default:
            text = JavaElementLabels.getElementLabel(element, LABEL_FLAGS);
            break;
        }
        Composite header = new Composite(content, SWT.NONE);
        ApidocsViewUtils.setInfoBackgroundColor(header);
        header.setLayout(new GridLayout(2, false));

        Label img = new Label(header, SWT.NONE);
        img.setImage(labelProvider.getImage(element));
        setInfoForegroundColor(img);
        setInfoBackgroundColor(img);

        Label name = createLabel(header, text, true);
        name.setFont(JFaceResources.getHeaderFont());
    }

    @Override
    public void setFocus() {
        viewer.getControl().setFocus();
    }
}