/**
* Copyright (c) 2010, 2013 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:
* Olav Lenz, Marcel Bruch - initial API and implementation
*/
package org.eclipse.recommenders.internal.models.rcp;
import static org.eclipse.recommenders.internal.models.rcp.ModelsRcpModule.MODEL_CLASSIFIER;
import static org.eclipse.recommenders.rcp.SharedImages.Images.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.recommenders.coordinates.DependencyInfo;
import org.eclipse.recommenders.coordinates.IDependencyListener;
import org.eclipse.recommenders.coordinates.ProjectCoordinate;
import org.eclipse.recommenders.internal.models.rcp.l10n.Messages;
import org.eclipse.recommenders.models.IModelIndex;
import org.eclipse.recommenders.models.ModelCoordinate;
import org.eclipse.recommenders.models.rcp.IProjectCoordinateProvider;
import org.eclipse.recommenders.models.rcp.ModelEvents.AdvisorConfigurationChangedEvent;
import org.eclipse.recommenders.models.rcp.actions.TriggerModelDownloadForDependencyInfosAction;
import org.eclipse.recommenders.rcp.SharedImages;
import org.eclipse.recommenders.utils.Checks;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
public class DependencyOverviewView extends ViewPart {
private final EventBus bus;
private final IDependencyListener dependencyListener;
private final IProjectCoordinateProvider pcProvider;
private final IModelIndex modelIndex;
private final EclipseModelRepository modelRepository;
private final SharedImages images;
private final List<String> modelClassifiers;
private TreeViewer treeViewer;
@Inject
public DependencyOverviewView(final EventBus workspaceBus, final IDependencyListener dependencyListener,
final IProjectCoordinateProvider pcProvider, final IModelIndex modelIndex,
final EclipseModelRepository modelRepository, SharedImages images,
@Named(MODEL_CLASSIFIER) ImmutableSet<String> modelClassifiers) {
bus = workspaceBus;
this.dependencyListener = dependencyListener;
this.pcProvider = pcProvider;
this.modelIndex = modelIndex;
this.modelRepository = modelRepository;
this.images = images;
this.modelClassifiers = Lists.newArrayList(modelClassifiers);
Collections.sort(this.modelClassifiers);
bus.register(this);
}
@Override
public void createPartControl(Composite parent) {
Tree dependencyTree = new Tree(parent,
SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
dependencyTree.setHeaderVisible(true);
dependencyTree.setLinesVisible(true);
createColumn(dependencyTree, Messages.COLUMN_LABEL_DEPENDENCY, 400);
createColumn(dependencyTree, Messages.COLUMN_LABEL_PROJECT_COORDINATE, 200);
for (String classifier : modelClassifiers) {
createColumn(dependencyTree, classifier.toUpperCase(), 50);
}
treeViewer = new TreeViewer(dependencyTree);
treeViewer.setContentProvider(new ContentProvider());
treeViewer.setLabelProvider(new LabelProvider());
treeViewer.setSorter(new ViewerSorter());
addContextMenu();
updateContent();
}
private void addContextMenu() {
final MenuManager menuManager = new MenuManager();
Menu contextMenu = menuManager.createContextMenu(treeViewer.getTree());
menuManager.setRemoveAllWhenShown(true);
treeViewer.getControl().setMenu(contextMenu);
menuManager.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
IStructuredSelection selection = Checks.cast(treeViewer.getSelection());
Set<DependencyInfo> deps = extractSelectedDependencies(selection);
if (!deps.isEmpty()) {
menuManager.add(new TriggerModelDownloadForDependencyInfosAction(Messages.MENUITEM_DOWNLOAD_MODELS,
deps, modelClassifiers, pcProvider, modelIndex, modelRepository, bus));
}
}
});
}
private Set<DependencyInfo> extractSelectedDependencies(IStructuredSelection selection) {
final Set<DependencyInfo> selectedDependencies = Sets.newHashSet();
for (Object element : selection.toList()) {
if (element instanceof Dependency) {
Dependency dependency = (Dependency) element;
selectedDependencies.add(dependency.info);
} else if (element instanceof Project) {
Project project = (Project) element;
for (Dependency dependency : project.dependencies) {
selectedDependencies.add(dependency.info);
}
}
}
return selectedDependencies;
}
private void createColumn(Tree dependencyTree, String label, int width) {
TreeColumn column = new TreeColumn(dependencyTree, SWT.LEFT);
column.setText(label);
column.setWidth(width);
}
private void refreshData() {
new UIJob(Messages.JOB_NAME_REFRESHING_DEPENDENCY_OVERVIEW_VIEW) {
{
schedule();
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
updateContent();
return Status.OK_STATUS;
}
};
}
private void updateContent() {
List<Project> projects = createModel();
treeViewer.setInput(projects);
}
private List<Project> createModel() {
List<Project> result = new ArrayList<Project>();
Set<DependencyInfo> projectsDependencyInfos = dependencyListener.getProjects();
for (DependencyInfo projectDI : projectsDependencyInfos) {
Project project = new Project(projectDI);
List<Dependency> dependencies = new ArrayList<Dependency>();
Set<DependencyInfo> dependenciesForProject = dependencyListener.getDependenciesForProject(projectDI);
for (DependencyInfo dependencyInfo : dependenciesForProject) {
if (!dependencyInfo.equals(projectDI)) {
dependencies.add(new Dependency(dependencyInfo, project));
}
}
project.dependencies = dependencies;
result.add(project);
}
return result;
}
@Override
public void setFocus() {
treeViewer.getControl().setFocus();
}
@Subscribe
public void onEvent(AdvisorConfigurationChangedEvent e) throws IOException {
refreshData();
}
public static final class Project {
List<Dependency> dependencies;
DependencyInfo info;
public Project(DependencyInfo projectDependencyInfo) {
info = projectDependencyInfo;
}
@Override
public String toString() {
return info.getFile().getName();
}
}
public static final class Dependency {
public DependencyInfo info;
public Project parent;
public Dependency(DependencyInfo dependencyInfo, Project parent) {
info = dependencyInfo;
this.parent = parent;
}
@Override
public String toString() {
return info.getFile().getName();
}
}
public class LabelProvider extends org.eclipse.jface.viewers.LabelProvider implements ITableLabelProvider {
@Override
public Image getColumnImage(Object element, int columnIndex) {
switch (columnIndex) {
case 0:
if (element instanceof Project) {
return images.getImage(OBJ_JAVA_PROJECT);
}
if (element instanceof Dependency) {
Dependency dependency = (Dependency) element;
return getImageForDependencyTyp(dependency.info);
}
}
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
switch (columnIndex) {
case 0:
if (element instanceof Project) {
return ((Project) element).info.getFile().getName();
}
if (element instanceof Dependency) {
return ((Dependency) element).info.getFile().getName();
}
case 1:
if (element instanceof Dependency) {
Dependency dependency = (Dependency) element;
ProjectCoordinate pc = pcProvider.resolve(dependency.info).orNull();
return pc == null ? null : pc.toString();
}
default:
if (element instanceof Dependency) {
return findModelCoordinateVersion((Dependency) element, modelClassifiers.get(columnIndex - 2));
}
}
return null;
}
private String findModelCoordinateVersion(Dependency dependency, String modelType) {
ProjectCoordinate pc = pcProvider.resolve(dependency.info).orNull();
if (pc != null) {
ModelCoordinate mc = modelIndex.suggest(pc, modelType).orNull();
return mc == null ? "" : mc.getVersion(); //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}
private Image getImageForDependencyTyp(final DependencyInfo dependencyInfo) {
switch (dependencyInfo.getType()) {
case JRE:
return images.getImage(OBJ_JRE);
case JAR:
return images.getImage(OBJ_JAR);
case PROJECT:
return images.getImage(OBJ_JAVA_PROJECT);
default:
return null;
}
}
}
public static final class ContentProvider extends ArrayContentProvider implements ITreeContentProvider {
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof Project) {
return ((Project) parentElement).dependencies.toArray();
}
return new Object[0];
}
@Override
public Object getParent(Object element) {
return element instanceof Dependency ? ((Dependency) element).parent : null;
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof List) {
return !((List<?>) element).isEmpty();
}
if (element instanceof Project) {
return !((Project) element).dependencies.isEmpty();
}
return false;
}
}
}