blob: 804bf0b15c7c0849626cf1dbeca8ccd785acfd1e [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2009 Bestsolution.at and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* Tom Schindl<tom.schindl@bestsolution.at> - Initial API and implementation
*
* </copyright>
*
* $Id: ProjectExplorerPart.java,v 1.6 2009/06/09 07:36:38 tschindl Exp $
*/
package org.eclipse.emf.example.databinding.project.ui.rcp.views;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IExecutionListener;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.databinding.ObservablesManager;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
import org.eclipse.jface.databinding.viewers.TreeStructureAdvisor;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.services.ISourceProviderService;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.databinding.FeaturePath;
import org.eclipse.emf.databinding.IEMFListProperty;
import org.eclipse.emf.example.databinding.project.ui.rcp.Activator;
import org.eclipse.emf.example.databinding.project.ui.rcp.ResourceProvider;
import org.eclipse.emf.example.databinding.project.ui.rcp.databinding.Base64ToImageConverter;
import org.eclipse.emf.example.databinding.project.ui.rcp.handlers.CreateSublevelProjectHandler;
import org.eclipse.emf.example.databinding.project.ui.rcp.handlers.CreateToplevelProjectHandler;
import org.eclipse.emf.examples.databinding.project.core.model.project.CommitterShip;
import org.eclipse.emf.examples.databinding.project.core.model.project.Foundation;
import org.eclipse.emf.examples.databinding.project.core.model.project.Person;
import org.eclipse.emf.examples.databinding.project.core.model.project.Project;
import org.eclipse.emf.examples.databinding.project.core.model.project.ProjectPackage;
/**
* Part responsible for rendering the project tree
*/
public class ProjectExplorerPart
{
private final TreeViewer viewer;
private FormToolkit toolkit;
private final Image projectImage;
private final Image committerImage;
private final IObservableValue master = new WritableValue();
private final IExecutionListener paramListener;
private final IViewSite site;
/**
* Create a new project explorer
* @param site the view site
* @param parent the parent control to renderer on
* @param toolkit the toolkit
* @param foundation the foundation instance
* @param manager manager for observables to avoid leaks
*/
public ProjectExplorerPart(IViewSite site, Composite parent, FormToolkit toolkit, Foundation foundation, ObservablesManager manager)
{
this.toolkit = toolkit;
this.site = site;
ImageDescriptor desc = Activator.imageDescriptorFromPlugin("org.eclipse.ui", "icons/full/obj16/generic_elements.gif");
if (desc != null)
{
projectImage = desc.createImage();
}
else
{
projectImage = null;
}
desc = Activator.imageDescriptorFromPlugin("org.eclipse.ui", "icons/full/obj16/signed_yes_tbl.gif");
if (desc != null)
{
committerImage = desc.createImage();
}
else
{
committerImage = null;
}
viewer = init(parent, foundation);
paramListener = new CommandListener();
ICommandService service = (ICommandService)site.getService(ICommandService.class);
service.addExecutionListener(paramListener);
}
private TreeViewer init(Composite parent, Foundation foundation)
{
TreeViewer viewer = new TreeViewer(parent);
ObservableListTreeContentProvider cp = new ObservableListTreeContentProvider(new TreeFactoryImpl(), new TreeStructureAdvisorImpl());
viewer.setContentProvider(cp);
IObservableSet set = cp.getKnownElements();
IObservableMap[] map = new IObservableMap [4];
map[0] = EMFProperties.value(ProjectPackage.Literals.PROJECT__SHORTNAME).observeDetail(set);
map[1] = EMFProperties.value(ProjectPackage.Literals.PROJECT__COMMITTERS).observeDetail(set);
map[2] = EMFProperties.value(
FeaturePath.fromList(ProjectPackage.Literals.COMMITTER_SHIP__PERSON, ProjectPackage.Literals.PERSON__FIRSTNAME)).observeDetail(set);
map[3] = EMFProperties.value(
FeaturePath.fromList(ProjectPackage.Literals.COMMITTER_SHIP__PERSON, ProjectPackage.Literals.PERSON__LASTNAME)).observeDetail(set);
viewer.setLabelProvider(new TreeLabelProviderImpl(map));
IEMFListProperty projects = EMFProperties.list(ProjectPackage.Literals.FOUNDATION__PROJECTS);
viewer.setInput(projects.observe(foundation));
MenuManager mgr = new MenuManager();
mgr.add(new GroupMarker("additions"));
viewer.getControl().setMenu(mgr.createContextMenu(viewer.getControl()));
site.registerContextMenu(Activator.PLUGIN_ID + ".projectexp", mgr, viewer);
site.setSelectionProvider(viewer);
ColumnViewerToolTipSupportImpl.enableFor(viewer, toolkit);
IObservableValue treeObs = ViewerProperties.singleSelection().observe(viewer);
treeObs.addValueChangeListener(new IValueChangeListener()
{
public void handleValueChange(ValueChangeEvent event)
{
ISourceProviderService s = (ISourceProviderService)site.getService(ISourceProviderService.class);
ResourceProvider p = (ResourceProvider)s.getSourceProvider(ResourceProvider.MODEL_RESOURCE_NAME);
if (event.diff.getNewValue() instanceof Project)
{
Project pr = (Project)event.diff.getNewValue();
master.setValue(pr);
p.setCommitter(null);
p.setProject(pr);
}
else if (event.diff.getNewValue() != null)
{
CommitterShip cm = (CommitterShip)event.diff.getNewValue();
master.setValue(cm.getProject());
p.setCommitter(cm);
p.setProject(cm.getProject());
}
else
{
p.setCommitter(null);
p.setProject(null);
}
}
});
return viewer;
}
/**
* @return observable of the current active project in the tree
*/
public IObservableValue getProjectObservable()
{
return master;
}
private static class TreeFactoryImpl implements IObservableFactory
{
private IEMFListProperty multi = EMFProperties.multiList(
ProjectPackage.Literals.PROJECT__SUBPROJECTS,
ProjectPackage.Literals.PROJECT__COMMITTERS);
public IObservable createObservable(final Object target)
{
if (target instanceof IObservableList)
{
return (IObservable)target;
}
else if (target instanceof Project)
{
return multi.observe(target);
}
return null;
}
}
private static class TreeStructureAdvisorImpl extends TreeStructureAdvisor
{
@Override
public Object getParent(Object element)
{
if (element instanceof Project)
{
return ((Project)element).getParent();
}
return null;
}
@Override
public Boolean hasChildren(Object element)
{
if (element instanceof Project && (((Project)element).getCommitters().size() > 0 || ((Project)element).getSubprojects().size() > 0))
{
return Boolean.TRUE;
}
return super.hasChildren(element);
}
}
private class TreeLabelProviderImpl extends StyledCellLabelProvider
{
private IMapChangeListener mapChangeListener = new IMapChangeListener()
{
public void handleMapChange(MapChangeEvent event)
{
Set< ? > affectedElements = event.diff.getChangedKeys();
if (!affectedElements.isEmpty())
{
LabelProviderChangedEvent newEvent = new LabelProviderChangedEvent(TreeLabelProviderImpl.this, affectedElements.toArray());
fireLabelProviderChanged(newEvent);
}
}
};
public TreeLabelProviderImpl(IObservableMap... attributeMaps)
{
for (int i = 0; i < attributeMaps.length; i++)
{
attributeMaps[i].addMapChangeListener(mapChangeListener);
}
}
@Override
public String getToolTipText(Object element)
{
return "#dummy#";
}
@Override
public void update(ViewerCell cell)
{
if (cell.getElement() instanceof Project)
{
Project p = (Project)cell.getElement();
StyledString styledString = new StyledString(p.getShortname() != null ? p.getShortname() : "*noname*", null);
String decoration = " (" + p.getCommitters().size() + " Committers)";
styledString.append(decoration, StyledString.COUNTER_STYLER);
cell.setText(styledString.getString());
cell.setImage(projectImage);
cell.setStyleRanges(styledString.getStyleRanges());
}
else if (cell.getElement() instanceof CommitterShip)
{
Person p = ((CommitterShip)cell.getElement()).getPerson();
String value = "*noname*";
if (p != null)
{
value = p.getLastname() + ", " + p.getFirstname();
}
StyledString styledString = new StyledString(value, null);
cell.setText(styledString.getString());
cell.setForeground(cell.getControl().getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
cell.setImage(committerImage);
cell.setStyleRanges(styledString.getStyleRanges());
}
}
}
private static class ColumnViewerToolTipSupportImpl extends ColumnViewerToolTipSupport
{
private FormToolkit toolkit;
protected ColumnViewerToolTipSupportImpl(FormToolkit toolkit, ColumnViewer viewer, int style)
{
super(viewer, style, false);
setHideOnMouseDown(false);
this.toolkit = toolkit;
}
@Override
protected Composite createViewerToolTipContentArea(Event event, ViewerCell cell, Composite parent)
{
if (cell.getElement() instanceof Project)
{
final Project p = (Project)cell.getElement();
StringBuilder b = new StringBuilder();
for (Person lead : p.getProjectleads())
{
if (b.length() > 0)
{
b.append(", ");
}
b.append(lead.getFirstname() + " " + lead.getLastname());
}
Form form = toolkit.createForm(parent);
toolkit.decorateFormHeading(form);
form.setText(p.getShortname() + " - " + p.getLongname());
Composite body = form.getBody();
body.setLayout(new GridLayout(2, false));
toolkit.createLabel(body, "Project creation:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
toolkit.createLabel(body, p.getStart() != null ? DateFormat.getDateInstance().format(p.getStart()) : "");
toolkit.createLabel(body, "Project lead:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
toolkit.createLabel(body, b.toString());
toolkit.createLabel(body, "Committers:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
toolkit.createLabel(body, p.getCommitters().size() + "");
toolkit.createLabel(body, "Mailing-List:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
if (p.getDevmail() != null)
{
toolkit.createHyperlink(body, p.getDevmail(), SWT.NONE).addHyperlinkListener(new IHyperlinkListener()
{
public void linkExited(HyperlinkEvent e)
{
}
public void linkEntered(HyperlinkEvent e)
{
}
public void linkActivated(HyperlinkEvent e)
{
Program.launch(p.getDevmail());
}
});
}
else
{
toolkit.createLabel(body, "-");
}
toolkit.createLabel(body, "Homepage:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
if (p.getHomepage() != null)
{
toolkit.createHyperlink(body, p.getHomepage(), SWT.NONE).addHyperlinkListener(new IHyperlinkListener()
{
public void linkExited(HyperlinkEvent e)
{
}
public void linkEntered(HyperlinkEvent e)
{
}
public void linkActivated(HyperlinkEvent e)
{
Program.launch(p.getHomepage());
}
});
}
else
{
toolkit.createLabel(body, "-");
}
return form;
}
else
{
final CommitterShip committership = (CommitterShip)cell.getElement();
Form form = toolkit.createForm(parent);
toolkit.decorateFormHeading(form);
form.setText(committership.getPerson().getFirstname() + ", " + committership.getPerson().getLastname());
Composite formBody = form.getBody();
formBody.setLayout(new GridLayout(2, false));
GridData gd = new GridData();
final Label l = toolkit.createLabel(formBody, "");
l.setLayoutData(gd);
Base64ToImageConverter c = new Base64ToImageConverter(form.getDisplay());
l.setImage((Image)c.convert(committership.getPerson().getImage()));
l.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
if (l.getImage() != null)
l.getImage().dispose();
}
});
Composite body = toolkit.createComposite(formBody);
body.setLayout(new GridLayout(2, false));
toolkit.createLabel(body, "Start:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
toolkit.createLabel(body, committership.getStart() != null ? DateFormat.getDateInstance().format(committership.getStart()) : "");
toolkit.createLabel(body, "End:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
toolkit.createLabel(body, committership.getEnd() != null ? DateFormat.getDateInstance().format(committership.getEnd()) : "");
toolkit.createLabel(body, "E-Mail:").setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
if (committership.getPerson().getEmail() != null)
{
toolkit.createHyperlink(body, committership.getPerson().getEmail(), SWT.NONE).addHyperlinkListener(new IHyperlinkListener()
{
public void linkExited(HyperlinkEvent e)
{
}
public void linkEntered(HyperlinkEvent e)
{
}
public void linkActivated(HyperlinkEvent e)
{
Program.launch(committership.getPerson().getEmail());
}
});
}
else
{
toolkit.createLabel(body, "");
}
return form;
}
}
static void enableFor(ColumnViewer viewer, FormToolkit toolkit)
{
new ColumnViewerToolTipSupportImpl(toolkit, viewer, ToolTip.NO_RECREATE);
}
}
/**
* Set the focus
*/
public void setFocus()
{
viewer.getControl().setFocus();
if (viewer.getTree().getItemCount() > 0)
{
viewer.setSelection(new StructuredSelection(viewer.getTree().getItem(0).getData()));
}
}
/**
* Dispose all resources and remove all listeners
*/
public void dispose()
{
ICommandService service = (ICommandService)site.getService(ICommandService.class);
service.removeExecutionListener(paramListener);
if (projectImage != null)
{
projectImage.dispose();
}
if (committerImage != null)
{
committerImage.dispose();
}
}
/**
* @return the current selected committer
*/
public CommitterShip getCommitter()
{
Object obj = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
return (CommitterShip)((obj instanceof CommitterShip) ? obj : null);
}
private class CommandListener implements IExecutionListener
{
public void preExecute(String commandId, ExecutionEvent event)
{
}
public void postExecuteSuccess(String commandId, Object returnValue)
{
if (site.getPage() != null && site.getPage().getActivePart() != null && site.getPage().getActivePart().getSite() == site)
{
if (commandId.equals(CreateToplevelProjectHandler.ID) && returnValue != null)
{
viewer.setSelection(new StructuredSelection(returnValue));
}
else if (commandId.equals(CreateSublevelProjectHandler.ID) && returnValue != null)
{
Project project = (Project)returnValue;
List<Project> path = new ArrayList<Project>();
path.add(project);
while ((project = project.getParent()) != null)
{
path.add(0, project);
}
viewer.expandToLevel(new TreePath(path.toArray()), 0);
viewer.setSelection(new TreeSelection(new TreePath(path.toArray())));
}
}
}
public void postExecuteFailure(String commandId, ExecutionException exception)
{
}
public void notHandled(String commandId, NotHandledException exception)
{
}
}
}