/*****************************************************************************
* Copyright (c) 2010 CEA LIST.
*
* 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:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.views.properties.widgets;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.papyrus.infra.tools.databinding.MultipleObservableValue;
import org.eclipse.papyrus.infra.widgets.editors.AbstractEditor;
import org.eclipse.papyrus.views.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.Context;
import org.eclipse.papyrus.views.properties.contexts.Section;
import org.eclipse.papyrus.views.properties.contexts.View;
import org.eclipse.papyrus.views.properties.runtime.ConfigurationManager;
import org.eclipse.papyrus.views.properties.runtime.DefaultDisplayEngine;
import org.eclipse.papyrus.views.properties.runtime.DisplayEngine;
import org.eclipse.papyrus.views.properties.widgets.layout.PropertiesLayout;
import org.eclipse.papyrus.views.properties.xwt.XWTSection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* An Editor for displaying a whole property {@link View} on a sub-object.
* If the property is a list, there will be one view per element in the list.
*
* The view's tabs will be ignored : the sections are embedded in the caller's
* tab.
*/
public class ViewEditor extends AbstractPropertyEditor {
private String viewPath;
private Composite self;
private Collection<XWTSection> sections;
/**
* Constructor.
*
* @param parent
* The composite in which the widget will be displayed
* @param style
* The style for the widget
*/
public ViewEditor(Composite parent, int style) {
self = new Composite(parent, SWT.NONE);
PropertiesLayout layout = new PropertiesLayout(1, true);
layout.horizontalSpacing = 0;
layout.marginWidth = 0;
self.setLayout(layout);
}
@Override
public void checkInput() {
if(propertyPath != null && input != null && viewPath != null) {
display();
}
}
/**
* Sets the number of columns for this editor. If the property is a list,
* there will be one view per element in the list : these views will be
* distributed in the given number of columns.
*
* @param numColumns
*/
public void setNumColumns(int numColumns) {
((PropertiesLayout)self.getLayout()).numColumns = numColumns;
}
/**
* @return the number of columns for this editor.
*/
public int getNumColumns() {
return ((PropertiesLayout)self.getLayout()).numColumns;
}
/**
* Sets the view for this editor. The view is represented by its viewPath, which is
* of form ContextName:ViewName
* e.g. : UML:Class
* The Context should be registered in the ConfigurationManager
*
* @param viewPath
* The path of the view used to display the given property
*/
public void setView(String viewPath) {
this.viewPath = viewPath;
checkInput();
}
/**
* @return the qualified name of the view associated to this editor
*/
public String getView() {
return viewPath;
}
private View resolveView() {
String contextName = viewPath.substring(0, viewPath.indexOf(":")); //$NON-NLS-1$
String viewName = viewPath.substring(viewPath.indexOf(":") + 1); //$NON-NLS-1$
Context context = ConfigurationManager.instance.getContext(contextName);
for(View view : context.getViews()) {
if(view.getName().equals(viewName)) {
return view;
}
}
return null;
}
private void display() {
View view = resolveView();
if(view == null) {
Activator.log.warn("Unabled to resolve view : " + viewPath); //$NON-NLS-1$
return;
}
IObservable observable = getInputObservable();
if(observable == null) {
return;
}
DisplayEngine display = new DefaultDisplayEngine(true);
sections = new LinkedList<XWTSection>();
if(observable instanceof IObservableValue) {
IObservableValue observableValue = (IObservableValue)observable;
if(observableValue instanceof MultipleObservableValue) {
MultipleObservableValue multipleObservable = (MultipleObservableValue)observableValue;
display(display, multipleObservable.getObservedValues(), view);
} else {
Object value = observableValue.getValue();
display(display, value, view);
}
} else if(observable instanceof IObservableList) {
IObservableList observableList = (IObservableList)observable;
for(Object value : observableList) {
display(display, value, view);
}
}
updateControls();
}
/**
* Displays the given view in the display engine, with the given object.
*
* @param display
* The Display engine used to display the view. It should allow duplication,
* as for list properties, the same section will be displayed for each element
* in the list.
* @param data
* The raw object for which we are displaying the view.
* @param view
* The view to display
*/
protected void display(DisplayEngine display, Object data, View view) {
display(display, Collections.singletonList(data), view);
}
/**
* Displays the given view in the display engine, with the given object.
*
* @param display
* The Display engine used to display the view. It should allow duplication,
* as for list properties, the same section will be displayed for each element
* in the list.
* @param selectedElements
* The list of objects for which we are displaying the view
* @param view
* The view to display
*/
protected void display(DisplayEngine display, List<Object> selectedElements, View view) {
for(Section section : view.getSections()) {
XWTSection xwtSection = new XWTSection(section, view, display);
sections.add(xwtSection);
ISelection selection = new StructuredSelection(selectedElements);
xwtSection.createControls(new Composite(self, SWT.NONE), null);
xwtSection.setInput(null, selection);
xwtSection.refresh();
}
}
/**
* Updates the displayed widgets to mark them as readOnly if needed.
*/
protected void updateControls() {
for(Control container : self.getChildren()) {
//TODO : Browse recursively ?
if(container instanceof Composite) {
for(Control control : ((Composite)container).getChildren()) {
if(control instanceof AbstractEditor) {
AbstractEditor editor = (AbstractEditor)control;
editor.setReadOnly(getReadOnly() || editor.isReadOnly());
}
}
}
}
self.setEnabled(!getReadOnly());
}
@Override
protected IObservable getInputObservable() {
//Override the generic behavior: ViewEditor doesn't rely on an AbstractEditor
return input.getObservable(propertyPath);
}
@Override
public void setReadOnly(boolean readOnly) {
super.setReadOnly(readOnly);
updateControls();
}
@Override
protected void doBinding() {
//Nothing to do here
}
@Override
public Control getControl() {
return self;
}
}