blob: 916baef37ed291bd49337a5df70771974c29a38d [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.emf.ui.forms;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
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.emf.ecore.EObject;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.statet.ecommons.databinding.core.DataBindingSubContext;
import org.eclipse.statet.ecommons.emf.core.databinding.IEMFEditContext;
import org.eclipse.statet.ecommons.emf.ui.databinding.DetailContext;
public class DetailStack extends Composite {
private static class EmptyDetail extends Detail {
public EmptyDetail(final DetailStack parent) {
super(parent);
createContent();
}
@Override
protected Composite createComposite(final DetailStack parent) {
return new Composite(parent, SWT.NONE);
}
@Override
protected void createContent(final Composite composite) {
}
}
private class DetailEntry {
private final Object key;
private final Detail detail;
private IEMFEditContext context;
private DataBindingSubContext dbc;
public DetailEntry(final Object key, final Detail detail) {
this.key= key;
this.detail= detail;
}
}
private final IEFFormPage page;
private final StackLayout layout;
private final List<DetailEntry> details;
private final int limit= 10;
private IEMFEditContext context;
private DetailEntry currentDetail;
private EObject currentValue;
public DetailStack(final IEFFormPage page, final Composite parent) {
super(parent, SWT.NONE);
this.page= page;
this.layout= new StackLayout();
setLayout(this.layout);
this.details= new ArrayList<>(this.limit + 1);
}
public IEFFormPage getPage() {
return this.page;
}
protected void dispose(final DetailEntry entry) {
{ final Composite composite= entry.detail.getComposite();
if (composite != null && !composite.isDisposed()) {
composite.dispose();
}
}
if (entry.dbc != null) {
entry.dbc.dispose();
entry.dbc= null;
}
}
public void showDetail(final EObject value) {
int index= 0;
final Object key= getKey(value);
DetailEntry entry= null;
for (; index < this.details.size(); index++) {
final DetailEntry detail= this.details.get(index);
if (key == detail.key) {
entry= detail;
break;
}
}
if (entry == null) {
final Detail detail= createDetail(value);
entry= new DetailEntry(key, detail);
this.details.add(0, entry);
initDetailBindings(entry, value);
}
else {
if (entry.dbc == null) {
initDetailBindings(entry, value);
}
if (index != 0) {
this.details.remove(index);
this.details.add(0, entry);
}
}
this.currentDetail= this.details.get(0);
this.currentValue= value;
this.layout.topControl= this.currentDetail.detail.getComposite();
layout();
getParent().layout(new Control[] { this });
getPage().reflow(true);
if (this.details.size() > this.limit) {
dispose(this.details.remove(this.details.size() - 1));
}
}
protected Object getKey(final EObject value) {
return value;
}
protected Detail createDetail(final EObject value) {
return new EmptyDetail(this);
}
protected void createDetailContent(final Composite composite, final EObject value) {
if (value == null) {
return;
}
final Label label= new Label(composite, SWT.NONE);
label.setText(value.toString());
}
public void setContext(final IEMFEditContext context) {
this.context= context;
final IObservableValue baseValue= context.getBaseObservable();
baseValue.addValueChangeListener(new IValueChangeListener() {
@Override
public void handleValueChange(final ValueChangeEvent event) {
showDetail((EObject) event.diff.getNewValue());
}
});
showDetail((EObject) baseValue.getValue());
}
protected IEMFEditContext createDetailContext(final IEMFEditContext parent,
final IObservableValue detailValue) {
return new DetailContext(parent, detailValue);
}
private void initDetailBindings(final DetailEntry entry, final EObject value) {
final IEMFEditContext context= this.context;
if (context == null || entry.dbc != null) {
if (entry.context != null) {
entry.context.getBaseObservable().setValue(value);
}
return;
}
final AtomicReference<RuntimeException> error= new AtomicReference<>();
entry.dbc= new DataBindingSubContext(context.getDataBindingContext());
entry.dbc.run(new Runnable() {
@Override
public void run() {
try {
final IObservableValue contextValue= new WritableValue(context.getRealm(),
value, EObject.class );
entry.context= createDetailContext(context, contextValue);
entry.detail.addBindings(entry.context);
}
catch (final RuntimeException e) {
error.set(e);
}
}
});
if (error.get() != null) {
throw error.get();
}
}
// @Override
// public Point computeSize(int wHint, int hHint, boolean changed) {
// Point size= super.computeSize(wHint, hHint, changed);
// System.out.println("" + wHint + ", " + hHint + " -> " + size);
// return size;
// }
}