Commit 57f7a740 authored by Nico Mack's avatar Nico Mack

Implemented SegmentedArcGraph corona

parent 30f512da
......@@ -5,6 +5,7 @@ BLINK_ON_OUT_OF_RANGE_NODE=blinkOnOutOfRange
CAPPED_DISPLAY_NODE=cappedDisplay
COLOUR_SCALE_NODE=colourScale
DECIMALS_ATTRIBUTE=decimals
DISPLAY_MODE_NODE=displayMode
FACE_IS_TOUCHABLE_NODE=faceIsTouchable
FOREGROUND_NODE=foreground
ITEMS_VARIABLE_NODE=itemsVariable
......@@ -44,4 +45,7 @@ UPPER_STOP_ANGLE_NODE=upperStopAngle
VALUE_NODE=value
VARIABLE_NODE=variable
VARIABLES_NODE=variables
VERBOSE_NODE=verbose
\ No newline at end of file
VERBOSE_NODE=verbose
OFF_VALUE=off
CONTIGUOUS_VALUE=contiguous
DISCRETE_VALUE=discrete
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.CpsNamespace;
import lu.list.itis.dkd.tui.widget.corona.inner.DisplayMode;
import org.jdom2.Element;
import java.util.HashMap;
import java.util.Map;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.8
* @version 1.0.0
*/
public class DisplayModeBootstrapper {
/**
* @param parentNode
* @param bootstrapContext
* @param callback
* @return
*/
private static Map<String, DisplayMode> DISPLAY_MODES = new HashMap<>();
static {
DISPLAY_MODES.put(CpsNamespace.OFF_VALUE, DisplayMode.OFF);
DISPLAY_MODES.put(CpsNamespace.CONTIGUOUS_VALUE, DisplayMode.CONTIGUOUS);
DISPLAY_MODES.put(CpsNamespace.DISCRETE_VALUE, DisplayMode.DISCRETE);
}
public static DisplayMode buildDisplayModeFromElement(Element parentNode, BootstrapContext bootstrapContext, BootstrapCallback callback) throws BuildException {
DisplayMode mode;
String modeAsString = BootstrappingUtils.getContentAsString(parentNode, CpsNamespace.DISPLAY_MODE_NODE, BootstrappingUtils.OPTIONAL, CpsNamespace.OFF_VALUE, bootstrapContext);
mode = (DISPLAY_MODES.containsKey(modeAsString)) ? DISPLAY_MODES.get(modeAsString) : DisplayMode.OFF;
return mode;
}
}
......@@ -37,6 +37,7 @@ public class CpsNamespace extends NLS {
public static String FOREGROUND_NODE;
public static String DECIMALS_ATTRIBUTE;
public static String DISPLAY_MODE_NODE;
public static String HTML_TEMPLATE_NODE;
......@@ -92,6 +93,10 @@ public class CpsNamespace extends NLS {
public static String VERBOSE_NODE;
public static String OFF_VALUE;
public static String CONTIGUOUS_VALUE;
public static String DISCRETE_VALUE;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, CpsNamespace.class);
......
......@@ -13,22 +13,30 @@
*/
package lu.list.itis.dkd.tui.utility;
import lu.list.itis.dkd.tui.content.InformationReceiver;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.system.VariableBased;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.widget.corona.Corona;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
* @since 1.8
* @version 1.0.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class VariableManager {
public class VariableManager implements VariableBased {
private Corona corona;
private HashMap<String, Variable<?>> variables;
// ---------------------------------------------------------------------------
......@@ -37,13 +45,23 @@ public class VariableManager {
// ***************************************************************************
// ---------------------------------------------------------------------------
public VariableManager() {
variables = new HashMap<>();
public VariableManager(Corona owner) {
this.corona = owner;
this.variables = new HashMap<>();
}
// ---------------------------------------------------------------------------
public VariableManager(Corona owner, Variable<?> variable) {
this.corona = owner;
this.variables = new HashMap<>();
this.variables.put(variable.getName(), variable);
}
// ---------------------------------------------------------------------------
public VariableManager(Collection<Variable<?>> variables) {
public VariableManager(Corona owner, Collection<Variable<?>> variables) {
this.corona = owner;
this.variables = new HashMap<>();
for (Variable<?> variable : variables) {
this.variables.put(variable.getName(), variable);
......@@ -56,16 +74,17 @@ public class VariableManager {
// ***************************************************************************
// ---------------------------------------------------------------------------
private boolean connect(Variable<?> local, Map<String, Variable<?>> globals) {
boolean connected = false;
if ((globals != null) && globals.containsKey(local.getName())) {
Variable<?> global = globals.get(local.getName());
if (globals.getClass().isAssignableFrom(global.getClass())) {
this.variables.put(local.getName(), global);
connected = true;
@SuppressWarnings({"rawtypes", "unchecked"})
private Variable<?> connect(Variable<?> managedVariable, Variable<?> systemVariable) {
if (managedVariable.getClass().isAssignableFrom(systemVariable.getClass())) {
if (corona instanceof InputChangeListener) {
systemVariable.addListener((InputChangeListener) corona);
}
if (corona instanceof InformationReceiver) {
((InformationReceiver) corona).setInformation(systemVariable.getValue());
}
}
return connected;
return systemVariable;
}
// ---------------------------------------------------------------------------
......@@ -74,10 +93,32 @@ public class VariableManager {
// ***************************************************************************
// ---------------------------------------------------------------------------
public void connectWithGlobals(Map<String, Variable<?>> globals) {
for (Variable<?> local : variables.values()) {
connect(local, globals);
/** {@inheritDoc} */
@Override
public List<Variable<?>> connectWithSystemVariables(Map<String, Variable<?>> systemVariables) {
List<Variable<?>> connected = new ArrayList<>();
if (systemVariables == null) {
return connected;
}
for (Entry<String, Variable<?>> entry : this.variables.entrySet()) {
if (systemVariables.containsKey(entry.getKey())) {
Variable<?> connectedVariable = this.connect(entry.getValue(), systemVariables.get(entry.getKey()));
entry.setValue(connectedVariable);
connected.add(connectedVariable);
}
}
return connected;
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
public List<Variable<?>> getDeclaredVariables() {
return new ArrayList<>(this.variables.values());
}
// ---------------------------------------------------------------------------
......@@ -85,6 +126,4 @@ public class VariableManager {
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2020. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.widget.corona;
import lu.list.itis.dkd.tui.content.InformationReceiver;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.system.VariableBased;
import lu.list.itis.dkd.tui.cps.variable.NumericalVariable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.utility.VariableManager;
import lu.list.itis.dkd.tui.widget.corona.builder.BaseSegmentedArcGraphBuilder;
import lu.list.itis.dkd.tui.widget.corona.inner.DisplayMode;
import lu.list.itis.dkd.tui.widget.corona.inner.SegmentedArcGraphProperties;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.List;
import java.util.Map;
/**
* Class implementing an arc shaped corona composed of multiple segments.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 2.8
* @version 1.0.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class SegmentedArcGraph extends SegmentedArc implements InformationReceiver<Object>, VariableBased, InputChangeListener {
protected NumericalVariable variable;
protected DisplayMode mode;
private VariableManager variableManager;
// private List<SegmentedArcGraphProperties> segmentProperties;
private int currentlySelected = -1;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param builder
*/
// ---------------------------------------------------------------------------
public SegmentedArcGraph(BaseSegmentedArcGraphBuilder<?> builder) {
super(builder);
this.variable = builder.variable;
this.mode = builder.mode;
// this.segmentProperties = builder.segmentProperties;
this.buildFromProperties();
}
// ---------------------------------------------------------------------------
/**
* @param original
*/
// ---------------------------------------------------------------------------
public SegmentedArcGraph(SegmentedArcGraph original) {
super(original);
this.variable = original.variable;
this.mode = original.mode;
// this.segmentProperties = original.segmentProperties;
this.buildFromProperties();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private void buildFromProperties() {
this.variableManager = new VariableManager(this, this.variable);
}
// ---------------------------------------------------------------------------
private void setSelected(SegmentedArcGraphProperties property, boolean selectIt) {
if (property.fillColour != null)
property.fillColour.setSwitched(selectIt);
if (property.strokeColour != null)
property.strokeColour.setSwitched(selectIt);
if (property.textColour != null)
property.textColour.setSwitched(selectIt);
}
// ---------------------------------------------------------------------------
private void selectSegmentAt(int index) {
int numberOfSegments = this.segmentProperties.size();
for (int i = 0; i < numberOfSegments; i++) {
SegmentedArcGraphProperties property = (SegmentedArcGraphProperties) segmentProperties.get(i);
if (i < index) {
setSelected(property, (mode == DisplayMode.CONTIGUOUS));
} else {
setSelected(property, (i == index));
}
}
}
// ---------------------------------------------------------------------------
private void updateFromVariable() {
double normalized = this.variable.getNormalizedValue();
currentlySelected = (int) Math.round(this.segmentProperties.size() * normalized);
this.selectSegmentAt(currentlySelected);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
@Override
public void paint(Graphics2D canvas) {
if (!active || (this.opacity == TRANSPARENT))
return;
// if (this.readAndResetPropertyChanged()) {
// this.buildSectorFromProperties();
// }
Graphics2D localCanvas = (Graphics2D) canvas.create();
localCanvas.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform transform = this.getTransform(null);
localCanvas.setTransform(transform);
if (this.opacity < OPAQUE)
localCanvas.setComposite(AlphaComposite.SrcOver.derive(this.opacity));
for (int index = 0; index < segments.size(); index++) {
Shape segment = segments.get(index);
SegmentedArcGraphProperties properties = (SegmentedArcGraphProperties) segmentProperties.get(index);
if (properties.fillColour != null) {
localCanvas.setPaint(properties.fillColour.getColor());
localCanvas.fill(segment);
}
if ((properties.strokeColour != null) && (properties.stroke != null)) {
localCanvas.setPaint(properties.strokeColour.getColor());
localCanvas.setStroke(properties.stroke);
localCanvas.draw(segment);
}
}
localCanvas.dispose();
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public void inputChanged(InputEvent input) {
if (input.getSource().equals(this.variable)) {
this.updateFromVariable();
}
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public List<Variable<?>> connectWithSystemVariables(Map<String, Variable<?>> systemVariables) {
return this.variableManager.connectWithSystemVariables(systemVariables);
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public List<Variable<?>> getDeclaredVariables() {
return this.variableManager.getDeclaredVariables();
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public void setInformation(Object information) {
this.updateFromVariable();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.widget.corona.builder;
import lu.list.itis.dkd.dbc.annotation.NonNull;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.bootstrapping.BootstrappingUtils;
import lu.list.itis.dkd.tui.bootstrapping.DisplayModeBootstrapper;
import lu.list.itis.dkd.tui.bootstrapping.VariableBootstrapper;
import lu.list.itis.dkd.tui.cps.variable.NumericalVariable;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.ColorPair;
import lu.list.itis.dkd.tui.utility.CpsNamespace;
import lu.list.itis.dkd.tui.utility.Externalization;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.widget.corona.SegmentedArcGraph;
import lu.list.itis.dkd.tui.widget.corona.inner.DisplayMode;
import lu.list.itis.dkd.tui.widget.corona.inner.SegmentedArcGraphProperties;
import org.jdom2.Element;
import java.awt.BasicStroke;
import java.awt.Color;
import java.util.List;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.8
* @version 1.0
* @param <B>
* The concrete builder.
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public abstract class BaseSegmentedArcGraphBuilder<B extends BaseSegmentedArcGraphBuilder<B>> extends BaseSegmentedArcBuilder<B> {
public NumericalVariable variable;
public DisplayMode mode;
public List<SegmentedArcGraphProperties> segmentProperties;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param centre
*/
// ---------------------------------------------------------------------------
protected BaseSegmentedArcGraphBuilder(Point centre) {
super(centre);
}
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseSegmentedArcGraphBuilder(Element rootElement) throws BuildException {
super(rootElement);
this.buildFromBootstrap(rootElement, null, null);
}
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @param context
* @param callback
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseSegmentedArcGraphBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
super(rootElement, context, callback);
this.buildFromBootstrap(rootElement, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitive(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
private void buildFromBootstrap(@Nullable Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
Element variableElement = rootElement.getChild(CpsNamespace.VARIABLE_NODE);
if (variableElement != null) {
variable = (NumericalVariable) VariableBootstrapper.buildVariableFromElement(variableElement, context, callback);
}
Element displayModeElement = rootElement.getChild(CpsNamespace.DISPLAY_MODE_NODE);
if (displayModeElement != null) {
mode = DisplayModeBootstrapper.buildDisplayModeFromElement(rootElement, context, callback);
}
// this.segmentProperties = new ArrayList<>();
// Element segmentsNode = rootElement.getChild(Externalization.SEGMENTS_NODE);
// if (segmentsNode != null) {
// List<Element> segmentNodes = segmentsNode.getChildren(Externalization.SEGMENT_NODE);
// if (segmentNodes != null) {
// for (Element segmentNode : segmentNodes) {
// this.segmentProperties.add(this.buildSegmentProperty(segmentNode, context, callback));
// }
// }
// }
}
// ---------------------------------------------------------------------------
@Override
protected SegmentedArcGraphProperties buildSegmentProperty(@NonNull Element segmentElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
SegmentedArcGraphProperties property = new SegmentedArcGraphProperties();
property.title = BootstrappingUtils.getContentAsString(segmentElement, Externalization.TITLE_NODE, BootstrappingUtils.OPTIONAL, Externalization.EMPTY_STRING, context);
property.fillColour = buildColorPair(segmentElement.getChild(Externalization.FILL_COLOUR_ELEMENT), context);
property.textColour = buildColorPair(segmentElement.getChild(Externalization.TEXT_COLOUR_ELEMENT), context);
property.strokeColour = buildColorPair(segmentElement.getChild(Externalization.STROKE_COLOUR_ELEMENT), context);
int strokeWidth = BootstrappingUtils.getContentAsInteger(segmentElement, Externalization.STROKE_WIDTH_NODE, BootstrappingUtils.OPTIONAL, 0, context);
property.stroke = (strokeWidth > 0) ? new BasicStroke(strokeWidth) : null;
return property;
}
// ---------------------------------------------------------------------------
private ColorPair buildColorPair(Element rootElement, BootstrapContext context) throws BuildException {
if (rootElement == null) {
return null;
}
Color selectedColour = BootstrappingUtils.getContentAsColour(rootElement, Externalization.SELECTED_ELEMENT, BootstrappingUtils.OPTIONAL, Color.RED, context);
Color deselectedColour = BootstrappingUtils.getContentAsColour(rootElement, Externalization.DESELECTED_ELEMENT, BootstrappingUtils.OPTIONAL, Color.GRAY, context);
return new ColorPair(selectedColour, deselectedColour);
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public abstract SegmentedArcGraph build() throws BuildException;
}
package lu.list.itis.dkd.tui.widget.corona.builder;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.widget.corona.SegmentedArcGraph;
import org.jdom2.Element;
/**
* @author nmack
* @date 20 Jan 2016
*
* <br>
* $Log: DisplayCoronaBuilder.java,v $
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class SegmentedArcGraphBuilder<B extends SegmentedArcGraphBuilder<B>> extends BaseSegmentedArcGraphBuilder<B> {
// ***************************************************************************
// * Constants *
// ***************************************************************************
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
public SegmentedArcGraphBuilder(Point centre) {
super(centre);
}
// ---------------------------------------------------------------------------
public SegmentedArcGraphBuilder(Element rootElement) throws BuildException {
super(rootElement);
}
// ---------------------------------------------------------------------------
public SegmentedArcGraphBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
super(rootElement, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
@Override
public SegmentedArcGraph build() throws BuildException {
return new SegmentedArcGraph(this);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
package lu.list.itis.dkd.tui.widget.corona.inner;
public enum DisplayMode {
OFF(0x00), CONTIGUOUS(0x01), DISCRETE(0x02);
public final int bitMask;
private DisplayMode(int mask) {
this.bitMask = mask;
}
public int getBitMask() {
return bitMask;
}