/*******************************************************************************
* Copyright (c) 2008, 2011 Obeo.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.eef.runtime.ui.gwt.editor.widget;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.IChangeNotifier;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.emf.eef.runtime.ui.gwt.editor.EEFEditor;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.TreeViewModel;
/**
* @author glefur
*
*/
public class EEFTreeViewerContentProvider implements TreeViewModel {
private SingleSelectionModel<Object> treeSelection;
private EEFEditor editor;
private EditingDomain editingDomain;
public <T> EEFTreeViewerContentProvider(EEFEditor editor) {
this.treeSelection = new SingleSelectionModel<Object>();
this.editor = editor;
}
/**
* @param editingDomain the editingDomain to set
*/
public void setEditingDomain(EditingDomain editingDomain) {
this.editingDomain = editingDomain;
}
/**
* @param newSelection
*/
public void setSelected(Object selection, boolean state) {
treeSelection.setSelected(selection, state);
}
/**
* @param handler
*/
public void addSelectionChangeHandler(SelectionChangeEvent.Handler handler) {
treeSelection.addSelectionChangeHandler(handler);
}
/**
* @return the selection
*/
public Object getTreeSelection() {
return treeSelection.getSelectedObject();
}
public <T> NodeInfo<?> getNodeInfo(final T value) {
final ListDataProvider<Object> abstractListViewAdapter = new ListDataProvider<Object>() {
int size;
class NodeAdapter extends AdapterImpl implements INotifyChangedListener {
Set<Object> children = new HashSet<Object>();
@Override
public void notifyChanged(Notification msg) {
if (msg.getEventType() != Notification.REMOVING_ADAPTER) {
update();
if (!(msg.getNotifier() instanceof EObject)) {
for (Runnable runnable : editor.getPropertiesPanel().getPropertyUpdater()) {
runnable.run();
}
}
}
}
public void listenTo(Object target) {
if (target instanceof Notifier) {
((Notifier) target).eAdapters().add(this);
} else if (target instanceof IChangeNotifier) {
((IChangeNotifier) target).addListener(this);
}
}
public void stopListeningTo(Object target) {
if (target instanceof Notifier) {
((Notifier) target).eAdapters().remove(this);
} else if (target instanceof IChangeNotifier) {
((IChangeNotifier) target).removeListener(this);
}
}
public void listenTo(List<Object> children) {
// TODO
// I don't know how to update just one child. :-(
boolean isListeningToValue = !this.children.isEmpty();
Set<Object> oldChildren = new HashSet<Object>(this.children);
for (Object child : children) {
if (this.children.contains(child)) {
oldChildren.remove(child);
} else {
this.children.add(child);
listenTo(child);
}
}
for (Object child : oldChildren) {
stopListeningTo(child);
this.children.remove(child);
}
if (isListeningToValue) {
if (children.isEmpty()) {
stopListeningTo(value);
}
} else if (!children.isEmpty()) {
listenTo(value);
}
}
}
protected NodeAdapter nodeAdapter = new NodeAdapter();
@Override
protected void onRangeChanged(HasData<Object> display) {
if (value instanceof Resource) {
Resource resource = (Resource) value;
if (!resource.isLoaded()) {
try {
resource.load(editingDomain.getResourceSet().getLoadOptions());
} catch (IOException e) {
// Ignore.
}
}
}
update();
}
protected void update() {
Collection<?> children = editor.getItemDelegator().getChildren(value);
ArrayList<Object> childrenList = new ArrayList<Object>(children);
nodeAdapter.listenTo(childrenList);
int size = children.size();
if (this.size < size) {
updateRowCount(size, true);
this.size = size;
} else {
// Pad with dummy objects.
for (int i = size; i < this.size; ++i) {
childrenList.add(new Object());
}
}
updateRowData(0, childrenList);
if (this.size > size) {
updateRowCount(size, true);
this.size = size;
}
}
};
return new DefaultNodeInfo<Object>(abstractListViewAdapter, new ModelViewerCell(editor.getItemDelegator()), treeSelection, null);
}
public boolean isLeaf(Object value) {
return !editor.getItemDelegator().hasChildren(value);
}
}