blob: 780be4e307beb6f8989ca9dfdfe24593a298bee1 [file] [log] [blame]
// RelativeValueHistoryPlotter.java
package org.eclipse.stem.ui.reports.views;
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.stem.core.common.Identifiable;
import org.eclipse.stem.core.graph.DynamicLabel;
import org.eclipse.stem.core.graph.DynamicNodeLabel;
import org.eclipse.stem.core.graph.Graph;
import org.eclipse.stem.core.graph.Node;
import org.eclipse.stem.core.graph.NodeLabel;
import org.eclipse.stem.core.model.Decorator;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProvider;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProviderAdapter;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProviderAdapterFactory;
import org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryExtendedListener;
import org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryProvider;
import org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryProviderAdapter;
import org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryProviderAdapterFactory;
import org.eclipse.stem.diseasemodels.standard.DiseaseModel;
import org.eclipse.stem.diseasemodels.standard.DiseaseModelLabel;
import org.eclipse.stem.jobs.simulation.ISimulation;
import org.eclipse.stem.jobs.simulation.ISimulationListener;
import org.eclipse.stem.jobs.simulation.SimulationEvent;
import org.eclipse.stem.jobs.simulation.SimulationManager;
import org.eclipse.stem.jobs.simulation.SimulationState;
import org.eclipse.stem.populationmodels.standard.StandardPopulationModelLabel;
import org.eclipse.stem.ui.widgets.DecoratorSelector;
import org.eclipse.stem.ui.widgets.DecoratorSelector.DecoratorSelectionEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
/**
* This class is a SWT GUI component that uses BIRT to plot
*/
public class RelativeValueHistoryPlotter extends ReportControl implements
RelativeValueHistoryExtendedListener, ISimulationListener {
TimeSeriesCanvas timeSeriesCanvas;
DecoratorSelector decoratorSelector;
List<IItemPropertyDescriptor> selectedProperties;
boolean plotUpdateScheduled = false;
/**
* This interface is implemented by classes that select out the properties
* to be displayed.
*/
public interface PropertySieve {
/**
* @param dynamicLabel
* the label that contains the candidate properties to be
* displayed.
* @return a <code>List</code> of the properties that should be
* displayed in the order that they should be displayed.
*/
List<ItemPropertyDescriptor> sieve(final DynamicLabel dynamicLabel);
} // PropertySieve
/**
* This sieve selects all of those properties that have relative values.
*/
private final PropertySieve propertySieve = new PropertySieve() {
/**
* @see org.eclipse.stem.ui.widgets.DecoratorSelector.PropertySieve#sieve(org.eclipse.stem.core.graph.DynamicLabel)
*/
public List<ItemPropertyDescriptor> sieve(
final DynamicLabel dynamicLabel) {
final List<ItemPropertyDescriptor> retValue = new ArrayList<ItemPropertyDescriptor>();
final RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE
.adapt(dynamicLabel, RelativeValueProvider.class);
// Does the label have relative values?
if (rvp != null) {
// Yes
rvp.setTarget(dynamicLabel);
for (final Object element : rvp.getProperties()) {
final ItemPropertyDescriptor property = (ItemPropertyDescriptor) element;
retValue.add(property);
} // for each property
} // if the label has relative values
return retValue;
} // sieve
};
/**
* @param parent
*/
public RelativeValueHistoryPlotter(final Composite parent) {
super(parent, SWT.None);
createContents();
} // RelativeValueHistoryPlotter
/**
* Create the contents of the plotter
*/
private void createContents() {
setLayout(new FormLayout());
identifiableTitle = new Label(this, SWT.NONE);
timeSeriesCanvas = new TimeSeriesCanvas(this);
decoratorSelector = new DecoratorSelector(this, SWT.NONE, true);
removeButton = new Button(this, SWT.NONE);
removeButton.setText(REMOVE_TEXT);
final FormData titleFormData = new FormData();
identifiableTitle.setLayoutData(titleFormData);
titleFormData.top = new FormAttachment(0, 0);
titleFormData.left = new FormAttachment(0, 0);
titleFormData.right = new FormAttachment(100, 0);
final FormData chartFormData = new FormData();
timeSeriesCanvas.setLayoutData(chartFormData);
chartFormData.top = new FormAttachment(identifiableTitle, 0);
chartFormData.bottom = new FormAttachment(decoratorSelector, 0);
chartFormData.left = new FormAttachment(0, 0);
chartFormData.right = new FormAttachment(100, 0);
// Property Selector
final FormData decoratorSelectorFormData = new FormData();
// decoratorSelectorFormData.top = new FormAttachment(timeSeriesCanvas,
// 0);
decoratorSelectorFormData.bottom = new FormAttachment(100, 0);
decoratorSelectorFormData.left = new FormAttachment(0, 0);
decoratorSelectorFormData.right = new FormAttachment(30, 0);
decoratorSelector.setLayoutData(decoratorSelectorFormData);
// RemoveButton
final FormData removeButtonFormData = new FormData();
// decoratorSelectorFormDataX.top = new FormAttachment(decoratorSelectorY,
// 0);
removeButtonFormData.bottom = new FormAttachment(100, 0);
removeButtonFormData.left = new FormAttachment(decoratorSelector, 0);
removeButtonFormData.right = new FormAttachment(60, 0);
removeButton.setLayoutData(removeButtonFormData);
decoratorSelector
.addDecoratorSelectionListener(new DecoratorSelector.DecoratorSelectionListener() {
/**
* @see org.eclipse.stem.ui.widgets.DecoratorSelector.PropertySelectionListener#propertySelected(org.eclipse.stem.ui.widgets.DecoratorSelector.PropertySelectionEvent)
*/
public void decoratorSelected(
final DecoratorSelectionEvent decoratorSelectionEvent) {
selectedDecorator = decoratorSelectionEvent
.getDecorator();
if(selectedDecorator!=null) {
synchronized(timeSeriesCanvas) {
String selectedPopId = decoratorSelectionEvent.getId();
List<DynamicLabel>allLabels = decoratorToLabelsMap.get(selectedDecorator);
if(allLabels != null)
for(DynamicLabel lab:allLabels) {
if(lab instanceof DiseaseModelLabel && ((DiseaseModelLabel)lab).getPopulationModelLabel().getPopulationIdentifier().equals(selectedPopId)) {
selectedDynamicLabel = lab;
break;
}
if(lab instanceof StandardPopulationModelLabel && ((StandardPopulationModelLabel)lab).getPopulationIdentifier().equals(selectedPopId)) {
selectedDynamicLabel = lab;
break;
}
}
// This will also remove the old rvhp as a listener
if(selectedDynamicLabel != null)
switchToRVHP((RelativeValueHistoryProviderAdapter) RelativeValueHistoryProviderAdapterFactory.INSTANCE
.adapt(selectedDynamicLabel,
RelativeValueHistoryProvider.class));
selectedProperties = getPropertiesToDisplay(selectedDecorator, selectedPopId);
timeSeriesCanvas.setDataSourceAndRedraw(rvhp, selectedProperties);
}
}// if decorator not null
}
});
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(
@SuppressWarnings("unused") final SelectionEvent e) {
fireRemoveEvent(identifiable);
remove();
}
});
} // createContents
/**
* to remove the control e.g. by a remove button event
*/
@Override
@SuppressWarnings("cast")
public void remove() {
removeListeners.clear();
switchToRVHP(null);
relativeValueHistoryExtended(null);
identifiableTitle.setText("");
decoratorSelector
.setDecorators((List<Decorator>) Collections.EMPTY_LIST);
dispose();
}
/**
* @param identifiable
* the {@link Identifiable} to be the source of the data to be
* plotted.
*/
@Override
public void setIdentifiable(final Identifiable identifiable) {
// Same Identifiable?
if (this.identifiable == identifiable) {
// Yes
return;
} // if
this.identifiable = identifiable;
final List<Decorator> decorators = new ArrayList<Decorator>();
decoratorToLabelsMap = new HashMap<Decorator, List<DynamicLabel>>();
identifiableTitle.setText(identifiable.getDublinCore().getTitle());
// Get the dynamic labels associated with this Identifiable
// A node?
if (identifiable instanceof Node) {
// Yes
final Node node = (Node) identifiable;
for (final NodeLabel nodeLabel : node.getLabels()) {
// Updated by a decorator?
if (nodeLabel instanceof DynamicNodeLabel) {
// Yes
final DynamicNodeLabel dynamicNodeLabel = (DynamicNodeLabel) nodeLabel;
// Can it provide relative values?
final RelativeValueHistoryProviderAdapter rvhp = (RelativeValueHistoryProviderAdapter) RelativeValueHistoryProviderAdapterFactory.INSTANCE
.adapt(nodeLabel, RelativeValueHistoryProvider.class);
if (rvhp != null) {
// Yes
final Decorator decorator = dynamicNodeLabel
.getDecorator();
if(decorator != null) {
if(decoratorToLabelsMap.get(decorator)!=null) {
List<DynamicLabel>list = decoratorToLabelsMap.get(decorator);
list.add(dynamicNodeLabel);
} else {
ArrayList<DynamicLabel>newList = new ArrayList<DynamicLabel>();
newList.add(dynamicNodeLabel);
decoratorToLabelsMap.put(decorator, newList);
}
if (!decorators.contains(decorator)) {
decorators.add(decorator);
}
}
} // if
} // if DynamicNodeLabel
} // for each NodeLabel
// Are there any Decorators that we'll plot?
if (decorators.size() > 0) {
// Yes
// We need to listen to the life-cycle of the Simulation
// associated with the Graph that contains the Identifable that
// was passed in. When it disappears, we need to "un-hook"
// ourselves from the RelativeValueHistoryProviderAdapter
// instance so that the Graph that it is attached to can be
// garbage collected and we need to reset ourselves so that we
// don't display a plot for a Simulation that doesn't exist any
// more.
final ISimulation newSimulation = SimulationManager
.getManager().mapGraphToSimulation(getGraph(node));
// Stop listening to the old one?
if (simulation != null) {
// Yes
simulation.removeSimulationListener(this);
} // if
simulation = newSimulation;
// Listen to the new one?
if (simulation != null) {
// Yes
simulation.addSimulationListener(this);
} // if
} // if any Decorators to plot
} // if Node
decoratorSelector.setDecorators(decorators);
} // setIdentifiable
/**
* @see org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryExtendedListener#relativeValueHistoryExtended(org.eclipse.stem.definitions.adapters.relativevalue.history.RelativeValueHistoryProviderAdapter)
*/
public void relativeValueHistoryExtended(
final RelativeValueHistoryProviderAdapter rvhp) {
// The event notification doesn't come from the UI thread so we need to
// add a Runnable to the UI thread's execution queue to give the new
// source to the chart
// If a plot update is already scheduled, then don't add another to the queue
if (plotUpdateScheduled) {
return;
}
final Display display = Display.getDefault();
if (!display.isDisposed()) {
// Yes
try {
plotUpdateScheduled = true;
display.asyncExec(new Runnable() {
public void run() {
try {
if (!timeSeriesCanvas.isDisposed()) {
synchronized(timeSeriesCanvas) {
timeSeriesCanvas.draw();
}
}
} finally {
plotUpdateScheduled = false;
}
} // run
}); // display.asyncExec
} // try
catch (final Exception e) {
// Ignore there could be a race condition with the display being
// disposed when the system is shut down with a running
// simulation.
} // catch Exception
} // if
} // relativeValueHistoryExtended
/**
* Initialize the control from a
* {@link org.eclipse.stem.jobs.simulation.Simulation} instance.
*
* @param simulation
* the {@link org.eclipse.stem.jobs.simulation.Simulation}
* whose state will be visualized in the control.
*/
@Override
protected void initializeFromSimulation(final ISimulation simulation) {
simulationNameLabel.setText(simulation.getName());
decoratorSelector.setSimulation(simulation);
} // initializeFromSimulation
/**
*
*/
@Override
public void refresh2() {
// nothing
} // refresh2
/**
* @param decorator
* a {@link Decorator} that modifies the state of the canonical
* {@link Graph} in the
* {@link org.eclipse.stem.jobs.simulation.Simulation}.
* @param simulation
* the {@link org.eclipse.stem.jobs.simulation.Simulation}
* @return a {@link List} of the properties of the {@link Decorator} that
* can should be displayed.
*/
List<IItemPropertyDescriptor> getPropertiesToDisplay(
final Decorator decorator, final String populationIdentifier) {
final List<IItemPropertyDescriptor> retValue = new ArrayList<IItemPropertyDescriptor>();
// Got Decorator?
if (decorator != null) {
// Yes
// Are there any labels to update?
if (!decorator.getLabelsToUpdate().isEmpty()) {
// Yes
if (decorator instanceof DiseaseModel) {
// Different labels exist for different populations
retValue.addAll(propertySieve.sieve(((DiseaseModel) decorator)
.createDiseaseModelLabel(populationIdentifier)));
} else {
// The first one is good enough
retValue.addAll(propertySieve.sieve(decorator
.getLabelsToUpdate().get(0)));
}
} // if labels to update
} // if got decorator
return retValue;
} // getPropertiesToDisplay
private Graph getGraph(final Node node) {
return (Graph) node.eContainer().eContainer();
} // getGraph
/**
* @see org.eclipse.stem.jobs.simulation.ISimulationListener#simulationChanged(org.eclipse.stem.jobs.simulation.SimulationEvent)
*/
@SuppressWarnings("cast")
public void simulationChanged(final SimulationEvent event) {
if (event.getSimulationState() == SimulationState.RESET) {
// Yes
timeSeriesCanvas.resetData();
} // if
// Is the Simulation stopping (i.e. being deleted?)
if (event.getSimulationState() == SimulationState.STOPPED) {
// Yes
if(simulation !=null) {
simulation.removeSimulationListener(this);
simulation = null;
switchToRVHP(null);
relativeValueHistoryExtended(null);
identifiableTitle.setText("");
decoratorSelector.setDecorators((List<Decorator>) Collections.EMPTY_LIST);
}
} // if
} // simulationChanged
/**
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
@Override
public void dispose() {
super.dispose();
if (this.rvhp != null) {
// Yes
rvhp.removeExtensionListener(this);
} // if
if (simulation != null) {
// Yes
simulation.removeSimulationListener(this);
} // if
} // dispose
/**
* @see org.eclipse.stem.ui.reports.views.ReportControl#getIdentifiable()
*/
@Override
public Identifiable getIdentifiable() {
return identifiable;
}
/**
* This Control is associated with an Identifiable
* @see org.eclipse.stem.ui.reports.views.ReportControl#getControlType()
*/
public String getControlType() {
return ReportControlFactory.IDENTIFABLE_TYPE;
}
} // RelativeValueHistoryPlotter