com.googlecode.blaisemath.graphics.core.DelegatingPointSetGraphic Maven / Gradle / Ivy
/**
* DelegatingPointSetGraphic.java
* Created Jan 22, 2011
*/
package com.googlecode.blaisemath.graphics.core;
/*
* #%L
* BlaiseGraphics
* --
* Copyright (C) 2009 - 2015 Elisha Peterson
* --
* 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.
* #L%
*/
import com.google.common.base.Functions;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.googlecode.blaisemath.annotation.InvokedFromThread;
import static com.googlecode.blaisemath.graphics.core.LabeledPointGraphic.LABEL_RENDERER_PROP;
import static com.googlecode.blaisemath.graphics.core.PrimitiveGraphicSupport.RENDERER_PROP;
import com.googlecode.blaisemath.style.ObjectStyler;
import com.googlecode.blaisemath.style.Renderer;
import com.googlecode.blaisemath.style.Styles;
import com.googlecode.blaisemath.util.AnchoredText;
import com.googlecode.blaisemath.util.coordinate.CoordinateChangeEvent;
import com.googlecode.blaisemath.util.coordinate.CoordinateListener;
import com.googlecode.blaisemath.util.coordinate.CoordinateManager;
import com.googlecode.blaisemath.util.swing.BSwingUtilities;
import java.awt.geom.Point2D;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.JPopupMenu;
/**
* Manages a collection of points that are maintained as separate {@link Graphic}s,
* and therefore fully customizable. Point locations are handled by a {@link CoordinateManager},
* which allows their locations to be safely modified from other threads.
*
* @param the type of object being displayed
* @param type of canvas to render to
*
* @see BasicPointSetGraphic
*
* @author Elisha Peterson
*/
public class DelegatingPointSetGraphic extends GraphicComposite {
private static final int NODE_CACHE_SIZE = 20000;
/** Key for flag allowing individual points to be selected */
public static final String POINT_SELECTION_ENABLED = "point-selection-enabled";
/** Graphic objects for individual points */
protected final Map> points = Maps.newHashMap();
/** Whether points can be dragged */
protected boolean dragEnabled = false;
/** Manages locations of points */
protected CoordinateManager manager;
/** Selects styles for graphics */
@Nonnull
protected ObjectStyler styler = ObjectStyler.create();
/** Selects renderer for points */
protected Renderer renderer;
/** Renderer for point labels */
protected Renderer textRenderer;
/** Indicates points are being updated */
protected boolean updatingPoint = false;
/** Responds to coordinate update events */
private final CoordinateListener coordListener;
/**
* Construct with no points
*/
public DelegatingPointSetGraphic() {
this(null, null);
}
/**
* Construct with no points
* @param renderer draws points
* @param labelRenderer draws labels
*/
public DelegatingPointSetGraphic(@Nullable Renderer renderer,
@Nullable Renderer labelRenderer) {
this(CoordinateManager.create(NODE_CACHE_SIZE), renderer, labelRenderer);
}
/**
* Construct with source objects and locations as a map
* @param crdManager manages point locations
* @param renderer used for drawing the points
* @param labelRenderer draws labels
*/
public DelegatingPointSetGraphic(CoordinateManager crdManager,
@Nullable Renderer renderer,
@Nullable Renderer labelRenderer) {
setRenderer(renderer);
setLabelRenderer(labelRenderer);
styler.setStyleConstant(Styles.DEFAULT_POINT_STYLE);
styler.setTipDelegate(Functions.toStringFunction());
coordListener = new CoordinateListener(){
@Override
@InvokedFromThread("unknown")
public void coordinatesChanged(final CoordinateChangeEvent evt) {
BSwingUtilities.invokeOnEventDispatchThread(new Runnable(){
@Override
public void run() {
updatePointGraphics(evt.getAdded(), evt.getRemoved());
}
});
}
};
setCoordinateManager(crdManager);
}
//
//
// EVENT HANDLERS
//
private void updatePointGraphics(Map added, Set removed) {
List> addMe = Lists.newArrayList();
if (added != null) {
for (Entry en : added.entrySet()) {
S src = en.getKey();
DelegatingPrimitiveGraphic dpg = points.get(src);
if (dpg == null) {
LabeledPointGraphic lpg = new LabeledPointGraphic(en.getKey(), en.getValue(), styler);
lpg.setRenderer(renderer);
lpg.setLabelRenderer(textRenderer);
lpg.setDragEnabled(dragEnabled);
lpg.setSelectionEnabled(isPointSelectionEnabled());
points.put(src, lpg);
addMe.add(lpg);
} else {
// this should not result in manager changing
updatingPoint = true;
dpg.setPrimitive(en.getValue());
updatingPoint = false;
}
}
}
Set> removeMe = Sets.newHashSet();
if (removed != null) {
for (S s : removed) {
removeMe.add(points.get(s));
points.remove(s);
}
}
replaceGraphics(removeMe, addMe);
}
@Override
public void graphicChanged(Graphic source) {
if (!updatingPoint && source instanceof LabeledPointGraphic) {
LabeledPointGraphic dpg = (LabeledPointGraphic) source;
manager.put(dpg.getSourceObject(), dpg.getPrimitive());
}
// do not propagate events unless flag is false
if (!updatingPoint) {
super.graphicChanged(source);
}
}
//
//
//
// PROPERTY PATTERNS
//
/**
* Returns true if individual points can be selected.
* @return true if points can be selected
*/
public boolean isPointSelectionEnabled() {
return styleHints.getBoolean(POINT_SELECTION_ENABLED, false);
}
public void setPointSelectionEnabled(boolean val) {
if (isPointSelectionEnabled() != val) {
styleHints.put(POINT_SELECTION_ENABLED, val);
for (DelegatingPrimitiveGraphic dpg : points.values()) {
dpg.setSelectionEnabled(val);
}
}
}
/**
* Manager responsible for tracking point locations
* @return manager
*/
public CoordinateManager getCoordinateManager() {
return manager;
}
/**
* Set manager responsible for tracking point locations
* @param mgr manager
*/
public final void setCoordinateManager(CoordinateManager mgr) {
if (this.manager != checkNotNull(mgr)) {
if (this.manager != null) {
this.manager.removeCoordinateListener(coordListener);
}
this.manager = mgr;
this.manager.addCoordinateListener(coordListener);
updatePointGraphics(mgr.getActiveLocationCopy(), Collections.EMPTY_SET);
}
}
/**
* Returns object used to style points
* @return styler object styler
*/
public ObjectStyler getStyler() {
return styler;
}
/**
* Sets object used to style points
* @param styler object styler
*/
public void setStyler(ObjectStyler styler) {
if (this.styler != checkNotNull(styler)) {
this.styler = styler;
fireGraphicChanged();
}
}
@Nullable
public Renderer getRenderer() {
return renderer;
}
public final void setRenderer(@Nullable Renderer renderer) {
if (this.renderer != renderer) {
Object old = this.renderer;
this.renderer = renderer;
updatingPoint = true;
for (DelegatingPrimitiveGraphic dpg : points.values()) {
dpg.setRenderer(renderer);
}
updatingPoint = false;
fireGraphicChanged();
pcs.firePropertyChange(RENDERER_PROP, old, renderer);
}
}
@Nullable
public Renderer getLabelRenderer() {
return textRenderer;
}
public final void setLabelRenderer(@Nullable Renderer renderer) {
if (this.textRenderer != renderer) {
Object old = this.renderer;
this.textRenderer = renderer;
fireGraphicChanged();
pcs.firePropertyChange(LABEL_RENDERER_PROP, old, renderer);
}
}
public boolean isDragEnabled() {
return dragEnabled;
}
public void setDragEnabled(boolean val) {
if (this.dragEnabled != val) {
this.dragEnabled = val;
for (DelegatingPrimitiveGraphic dpg : points.values()) {
dpg.setDragEnabled(val);
}
}
}
/**
* Return source objects.
* @return source objects
*/
public Set getObjects() {
return manager.getActive();
}
//
//
/**
* Adds objects to the graphic
* @param obj objects to put
*/
public final void addObjects(Map obj) {
manager.putAll(obj);
}
//
@Nullable
public DelegatingPrimitiveGraphic getPointGraphic(S source) {
return points.get(source);
}
@Override
public void initContextMenu(JPopupMenu menu, Graphic src, Point2D point, Object focus, Set selection) {
// provide additional info for context menu
Graphic gfc = graphicAt(point);
super.initContextMenu(menu, this, point,
gfc instanceof DelegatingPrimitiveGraphic ? ((DelegatingPrimitiveGraphic)gfc).getSourceObject() : focus,
selection);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy