/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package gov.nasa.arc.mct.fastplot.policy;
import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.components.FeedProvider;
import gov.nasa.arc.mct.components.Placeholder;
import gov.nasa.arc.mct.evaluator.api.Evaluator;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants;
import gov.nasa.arc.mct.fastplot.view.PlotViewManifestation;
import gov.nasa.arc.mct.policy.ExecutionResult;
import gov.nasa.arc.mct.policy.Policy;
import gov.nasa.arc.mct.policy.PolicyContext;
import gov.nasa.arc.mct.services.component.ViewInfo;
import gov.nasa.arc.mct.services.component.ViewType;
import java.util.ArrayList;
import java.util.List;
public class PlotViewPolicy implements Policy {
static boolean hasFeed(AbstractComponent component) {
return component.getCapability(FeedProvider.class) != null || (component.getCapability(Placeholder.class) != null);
}
@Override
public ExecutionResult execute(PolicyContext context) {
boolean result = true;
ViewInfo viewInfo = context.getProperty(PolicyContext.PropertyName.TARGET_VIEW_INFO.getName(), ViewInfo.class);
if (viewInfo.getViewClass().equals(PlotViewManifestation.class)) {
AbstractComponent targetComponent = context.getProperty(PolicyContext.PropertyName.TARGET_COMPONENT.getName(), AbstractComponent.class);
if (targetComponent.isLeaf() && !hasFeed(targetComponent)) {
String message = "Leaf is not a feed.";
return new ExecutionResult(context, false, message);
}
result = !rejectCanvasView(context,targetComponent);
}
String message;
if (result) {
message = "Requested Plot View has children with data feeds.";
} else {
message = "Requested Plot View did not have children with data feeds.";
}
return new ExecutionResult(context, result, message);
}
/**
* Only allow the plot view to be visible in a canvas view if the component is a leaf, this allow the plot view to be the default canvas
* for a FeedProvider. However, since the plot view is now also a canvas view always allow the canvas view role if the plot view role is
* asked for directly.
* @param context
* @param component
* @return
*/
private boolean rejectCanvasView(PolicyContext context, AbstractComponent component) {
return ViewType.CENTER.equals(context.getProperty(PolicyContext.PropertyName.VIEW_TYPE.getName())) &&
!component.isLeaf();
}
private final static AbstractComponent[][] COMPONENT_MATRIX_TYPE = new AbstractComponent[0][];
private final static AbstractComponent[] COMPONENT_VECTOR_TYPE = new AbstractComponent[0];
/**
* Gets the 2-dimensional matrix of components where the children are collections
* and the grand children are data feeds.
*
* @param targetComponent the parent component of the matrix
* @param ordinalPosition if the ordinal position in the list should determine the stacked plot
* @return a 2-dimensional array of components making up the matrix
*/
public static AbstractComponent[][] getPlotComponents(AbstractComponent targetComponent, boolean ordinalPosition) {
List<AbstractComponent[]> subPlots = new ArrayList<AbstractComponent[]>();
if (targetComponent!=null){
if (hasFeed(targetComponent)) {
// We need only add this component to the plot.
List<AbstractComponent> phantomChildren = new ArrayList<AbstractComponent>();
phantomChildren.add(targetComponent);
subPlots.add(phantomChildren.toArray(COMPONENT_VECTOR_TYPE));
} else if (isCompoundComponentWithAtLeastOneChildThatIsALeafAndThatRequiresAPlot(targetComponent)) {
List<AbstractComponent> children = new ArrayList<AbstractComponent>();
for (AbstractComponent component : targetComponent.getComponents()) {
if (hasFeed(component)) {
children.add(component);
}
}
subPlots.add(children.toArray(COMPONENT_VECTOR_TYPE));
} else if (isCompoundComponentWithCompoundChildrenThatRequirePlots(targetComponent)) {
List<List<AbstractComponent>> stackedPlots = new ArrayList<List<AbstractComponent>>();
if (ordinalPosition) {
// match based on ordinal position in the list
for (AbstractComponent component : targetComponent.getComponents()) {
if (!component.isLeaf() && !isEvaluator(component)) {
int childCount = 0;
for (AbstractComponent childComponent : component.getComponents()) {
if (hasFeed(childComponent)) {
if (stackedPlots.size() < ++childCount) {
stackedPlots.add(new ArrayList<AbstractComponent>());
}
stackedPlots.get(childCount-1).add(childComponent);
if (childCount == PlotConstants.MAX_NUMBER_SUBPLOTS) {
break;
}
}
}
}
}
} else {
int currentStackedPlots = 0;
for (AbstractComponent component : targetComponent.getComponents()) {
if (!component.isLeaf() && !isEvaluator(component)) {
if (++currentStackedPlots == PlotConstants.MAX_NUMBER_SUBPLOTS ) {
break;
}
List<AbstractComponent> feeds = new ArrayList<AbstractComponent>();
for (AbstractComponent childComponent : component.getComponents()) {
if (hasFeed(childComponent)) {
feeds.add(childComponent);
}
}
stackedPlots.add(feeds);
}
}
}
for (List<AbstractComponent> stackedPlot : stackedPlots) {
subPlots.add(stackedPlot.toArray(COMPONENT_VECTOR_TYPE));
}
}
}
return subPlots.toArray(COMPONENT_MATRIX_TYPE);
}
/**
* Returns true if the component is an evaluator component.
* @param component to determine whether it is an evaluator
* @return true if the component is an evaluator, false otherwise
*/
private static boolean isEvaluator(AbstractComponent component) {
return !component.isLeaf() && component.getCapability(Evaluator.class) != null;
}
/**
* Returns true if component is a compound component (has children) and at least one of those children
* isALeafComponentThatRequiresAPlot. False otherwise.
*
* @param component
* @return
*/
static boolean isCompoundComponentWithAtLeastOneChildThatIsALeafAndThatRequiresAPlot(AbstractComponent component) {
if (component.isLeaf()) {
return false;
}
for (AbstractComponent childComponent : component.getComponents()) {
if (hasFeed(childComponent)) {
return true;
}
}
return false;
}
/**
* Returns true if component is a compound component and all its children are compound components with
* at least one grand child component that isALeafComponentThatRequiresAPlot.
*
* @param component
* @return
*/
static boolean isCompoundComponentWithCompoundChildrenThatRequirePlots(AbstractComponent component) {
if (component.isLeaf() ||
isCompoundComponentWithAtLeastOneChildThatIsALeafAndThatRequiresAPlot(component)) {
return false;
}
// We no know that all children of component are not leafs that require a plot.
for (AbstractComponent childComponent : component.getComponents()) {
if (!childComponent.isLeaf() && isCompoundComponentWithAtLeastOneChildThatIsALeafAndThatRequiresAPlot(childComponent)) {
return true;
}
}
return false;
}
public static boolean isScatterPlottable(AbstractComponent comp) {
int count = 0;
for (AbstractComponent child : comp.getComponents()) {
if (!child.isLeaf()) {
return false;
}
if (child.getCapability(FeedProvider.class) != null) {
count++;
}
}
return count >= 2;
}
public static boolean isOverlaidScatterPlottable(AbstractComponent comp) {
for (AbstractComponent child : comp.getComponents()) {
if (!isScatterPlottable(child)) {
return false;
}
}
return comp.getComponents().size() > 0;
}
}