blob: 096b7d2143582f6beb96dc4e58018865bc3924bd [file] [log] [blame]
/*
* Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others.
* 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.explorer.ui;
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.explorer.ui.bundle.OM;
import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutContentProvider;
import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutLabelProvider;
import org.eclipse.net4j.util.ui.views.ItemProvider;
import org.eclipse.emf.ecore.EObject;
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.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Eike Stepper
*/
public class ObjectListController
{
private final CDOCheckoutContentProvider contentProvider = new CDOCheckoutContentProvider();
private final LabelProvider labelProvider = new LabelProvider(contentProvider);
private final AtomicBoolean refreshing = new AtomicBoolean();
private final Set<EObject> objects = new HashSet<EObject>();
private final List<Wrapper> wrappers = new ArrayList<Wrapper>();
private final CDOCheckout checkout;
public ObjectListController(CDOCheckout checkout)
{
this.checkout = checkout;
}
public final CDOCheckout getCheckout()
{
return checkout;
}
public final EObject getObject(Object wrapper)
{
if (wrapper instanceof Wrapper)
{
return ((Wrapper)wrapper).getObject();
}
return null;
}
public final void addObject(EObject object, boolean delete)
{
if (objects.add(object))
{
String name = labelProvider.getSuperText(object);
wrappers.add(new Wrapper(object, delete, name));
}
}
public void configure(final TreeViewer treeViewer)
{
Control control = treeViewer.getControl();
contentProvider.disposeWith(control);
// The contentProvider field just makes the labelProvider happy.
treeViewer.setContentProvider(new ContentProvider());
treeViewer.setLabelProvider(new DecoratingStyledCellLabelProvider(labelProvider, new LabelDecorator(), null));
treeViewer.setInput(wrappers);
control.getDisplay().asyncExec(new Runnable()
{
public void run()
{
configureAsync(treeViewer, labelProvider);
}
});
}
@SuppressWarnings("deprecation")
protected void configureAsync(final TreeViewer treeViewer, final LabelProvider labelProvider)
{
if (treeViewer instanceof CheckboxTreeViewer)
{
CheckboxTreeViewer checkboxTreeViewer = (CheckboxTreeViewer)treeViewer;
checkboxTreeViewer.setAllChecked(true);
}
new Job("Compute paths")
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
updateWrappers(treeViewer, labelProvider);
return Status.OK_STATUS;
}
}.schedule();
}
protected void updateWrappers(final TreeViewer treeViewer, final LabelProvider labelProvider)
{
for (Wrapper wrapper : wrappers)
{
try
{
boolean hasPath;
synchronized (wrappers)
{
hasPath = wrapper.computePath(checkout, labelProvider);
}
if (hasPath)
{
refresh(treeViewer);
}
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
}
}
private void refresh(final TreeViewer treeViewer)
{
if (!refreshing.getAndSet(true))
{
Control control = treeViewer.getControl();
if (!control.isDisposed())
{
control.getDisplay().asyncExec(new Runnable()
{
public void run()
{
refreshing.set(false);
treeViewer.refresh(wrappers);
}
});
}
}
}
/**
* @author Eike Stepper
*/
private static final class Wrapper implements Comparable<Wrapper>
{
private final EObject object;
private final boolean delete;
private final String name;
private String path;
public Wrapper(EObject object, boolean delete, String name)
{
this.object = object;
this.delete = delete;
this.name = name;
}
public final EObject getObject()
{
return object;
}
public final boolean isDelete()
{
return delete;
}
public final String getPath()
{
return path;
}
public final String getName()
{
return name;
}
public boolean computePath(CDOCheckout checkout, LabelProvider labelProvider)
{
LinkedList<Object> nodes = CDOExplorerUtil.getPath(object);
if (nodes != null)
{
nodes.removeLast();
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Object node : nodes)
{
builder.append('/');
if (first)
{
builder.append(checkout.getLabel());
first = false;
}
else
{
builder.append(labelProvider.getText(node));
}
}
path = builder.toString();
return true;
}
return false;
}
public int compareTo(Wrapper o)
{
return toString().compareTo(o.toString());
}
@Override
public String toString()
{
if (path != null)
{
return path + name;
}
return name;
}
}
/**
* @author Eike Stepper
*/
private final class ContentProvider implements ITreeContentProvider
{
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
public void dispose()
{
}
public Object[] getElements(Object element)
{
if (element == wrappers)
{
Object[] result = wrappers.toArray();
synchronized (wrappers)
{
Arrays.sort(result);
}
return result;
}
return ItemProvider.NO_ELEMENTS;
}
public Object getParent(Object element)
{
return null;
}
public Object[] getChildren(Object element)
{
return getElements(element);
}
public boolean hasChildren(Object element)
{
return element == wrappers && !wrappers.isEmpty();
}
}
/**
* @author Eike Stepper
*/
private static final class LabelProvider extends CDOCheckoutLabelProvider
{
public LabelProvider(CDOCheckoutContentProvider contentProvider)
{
super(contentProvider);
}
@Override
public Image getImage(Object element)
{
if (element instanceof Wrapper)
{
Wrapper wrapper = (Wrapper)element;
return super.getImage(wrapper.getObject());
}
return super.getImage(element);
}
@Override
public String getText(Object element)
{
if (element instanceof Wrapper)
{
Wrapper wrapper = (Wrapper)element;
String name = wrapper.getName();
if (name.length() == 0)
{
return "/";
}
return name;
}
return getSuperText(element);
}
public String getSuperText(Object element)
{
return super.getText(element);
}
}
/**
* @author Eike Stepper
*/
private static final class LabelDecorator extends BaseLabelDecorator
{
private static final Image DELETE_OVERLAY_IMAGE = OM.getImage("icons/delete_ovr.gif");
@Override
public Image decorateImage(Image image, Object element)
{
if (element instanceof Wrapper)
{
Wrapper wrapper = (Wrapper)element;
if (wrapper.isDelete())
{
return OM.getOverlayImage(image, DELETE_OVERLAY_IMAGE, 9, 0);
}
}
return super.decorateImage(image, element);
}
@Override
public String decorateText(String text, Object element)
{
if (element instanceof Wrapper && !text.equals("/"))
{
Wrapper wrapper = (Wrapper)element;
String path = wrapper.getPath();
if (path != null)
{
text = path + "/" + text;
}
return text;
}
return super.decorateText(text, element);
}
}
}