/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.fge.view;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.dnd.Autoscroll;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import org.openflexo.fge.ConnectorGraphicalRepresentation;
import org.openflexo.fge.Drawing;
import org.openflexo.fge.DrawingGraphicalRepresentation;
import org.openflexo.fge.DrawingNeedsToBeRedrawn;
import org.openflexo.fge.FGEConstants;
import org.openflexo.fge.GeometricGraphicalRepresentation;
import org.openflexo.fge.GraphicalRepresentation;
import org.openflexo.fge.ShapeGraphicalRepresentation;
import org.openflexo.fge.controller.DrawingController;
import org.openflexo.fge.controller.DrawingController.EditorTool;
import org.openflexo.fge.controller.DrawingPalette;
import org.openflexo.fge.controller.RectangleSelectingAction;
import org.openflexo.fge.cp.ControlArea;
import org.openflexo.fge.graphics.FGEDrawingGraphics;
import org.openflexo.fge.graphics.ForegroundStyle;
import org.openflexo.fge.notifications.FGENotification;
import org.openflexo.fge.notifications.GraphicalRepresentationAdded;
import org.openflexo.fge.notifications.GraphicalRepresentationRemoved;
import org.openflexo.fge.notifications.ObjectResized;
import org.openflexo.fge.view.listener.DrawingViewMouseListener;
import org.openflexo.fge.view.listener.FocusRetriever;
import org.openflexo.swing.MouseResizer;
public class DrawingView<D extends Drawing<?>> extends FGELayeredView<D> implements Autoscroll {
private final class DrawingViewResizer extends MouseResizer {
protected DrawingViewResizer() {
super(DrawingView.this, new MouseResizer.MouseResizerDelegate() {
@Override
public void resizeBy(int deltaX, int deltaY) {
}
@Override
public void resizeDirectlyBy(int deltaX, int deltaY) {
if (deltaX != 0) {
getDrawing().getDrawingGraphicalRepresentation().setWidth(
getDrawing().getDrawingGraphicalRepresentation().getWidth() + deltaX / getScale());
}
if (deltaY != 0) {
getDrawing().getDrawingGraphicalRepresentation().setHeight(
getDrawing().getDrawingGraphicalRepresentation().getHeight() + deltaY / getScale());
}
}
}, ResizeMode.SOUTH, ResizeMode.EAST, ResizeMode.SOUTH_EAST);
}
@Override
protected int getComponentWidth() {
return getDrawing().getDrawingGraphicalRepresentation().getViewWidth(getScale());
}
@Override
protected int getComponentHeight() {
return getDrawing().getDrawingGraphicalRepresentation().getViewHeight(getScale());
}
}
private static final Logger logger = Logger.getLogger(DrawingView.class.getPackage().getName());
private D drawing;
private Map<GraphicalRepresentation<?>, FGEView<?>> contents;
private DrawingController<D> _controller;
private FocusRetriever _focusRetriever;
private FGEPaintManager _paintManager;
private MouseResizer resizer;
private DrawingViewMouseListener mouseListener;
protected FGEDrawingGraphics graphics;
public DrawingView(D aDrawing, DrawingController<D> controller) {
_controller = controller;
drawing = aDrawing;
aDrawing.getDrawingGraphicalRepresentation().updateBindingModel();
contents = new Hashtable<GraphicalRepresentation<?>, FGEView<?>>();
graphics = new FGEDrawingGraphics(drawing.getDrawingGraphicalRepresentation());
_focusRetriever = new FocusRetriever(this);
if (aDrawing.getDrawingGraphicalRepresentation().isResizable()) {
resizer = new DrawingViewResizer();
}
mouseListener = makeDrawingViewMouseListener();
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
installKeyBindings();
resizeView();
getGraphicalRepresentation().addObserver(this);
for (Object gr : getGraphicalRepresentation().getContainedGraphicalRepresentations()) {
if (gr instanceof GeometricGraphicalRepresentation) {
((GeometricGraphicalRepresentation) gr).addObserver(this);
}
}
if (controller.getPalettes() != null) {
for (DrawingPalette p : controller.getPalettes()) {
registerPalette(p);
}
}
updateBackground();
setOpaque(true);
_paintManager = new FGEPaintManager(this);
setToolTipText(getClass().getSimpleName() + hashCode());
// setDoubleBuffered(true);
setFocusable(true);
// GPO: no LayoutManager here, so next line is useless?
revalidate();
}
private void installKeyBindings() {
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "move_left");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "move_right");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "move_up");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "move_down");
getActionMap().put("move_left", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
getController().leftKeyPressed();
}
});
getActionMap().put("move_right", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
getController().rightKeyPressed();
}
});
getActionMap().put("move_up", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
getController().upKeyPressed();
}
});
getActionMap().put("move_down", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
getController().downKeyPressed();
}
});
}
public D getDrawing() {
return drawing;
}
@Override
public DrawingView<D> getDrawingView() {
return this;
}
@Override
public LabelView<D> getLabelView() {
return null;
}
@Override
public DrawingGraphicalRepresentation getGraphicalRepresentation() {
return drawing.getDrawingGraphicalRepresentation();
}
public DrawingGraphicalRepresentation<?> getDrawingGraphicalRepresentation() {
return getGraphicalRepresentation();
}
@Override
public double getScale() {
return getController().getScale();
}
public Integer getLayer() {
return JLayeredPane.DEFAULT_LAYER;
}
@Override
public D getModel() {
return drawing;
}
public Dimension getComputedMinimumSize() {
Rectangle r = getBounds();
for (int i = 0; i < getComponents().length; i++) {
Component c = getComponents()[i];
r = r.union(c.getBounds());
}
return r.getSize();
}
@Override
public void rescale() {
for (FGEView<?> v : contents.values()) {
v.rescale();
if (v.getLabelView() != null) {
v.getLabelView().rescale();
}
}
resizeView();
// revalidate();
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(this);
}
private void resizeView() {
int offset = getGraphicalRepresentation().isResizable() ? 20 : 0;
setPreferredSize(new Dimension(getGraphicalRepresentation().getViewWidth(getController().getScale()) + offset,
getGraphicalRepresentation().getViewHeight(getController().getScale()) + offset));
if (getParent() != null) {
getParent().doLayout();
}
}
private void updateBackground() {
if (getGraphicalRepresentation().getDrawWorkingArea()) {
setBackground(Color.GRAY);
} else {
setBackground(getGraphicalRepresentation().getBackgroundColor());
}
}
protected DrawingViewMouseListener makeDrawingViewMouseListener() {
return new DrawingViewMouseListener(getGraphicalRepresentation(), this);
}
@Override
public DrawingController<D> getController() {
return _controller;
}
@Override
public void update(final Observable o, final Object notification) {
if (isDeleted) {
logger.warning("Received notifications for deleted view: observable=" + o);
return;
}
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
update(o, notification);
}
});
} else {
// logger.info("Received: "+notification);
if (notification instanceof FGENotification) {
FGENotification notif = (FGENotification) notification;
if (notification instanceof GraphicalRepresentationAdded) {
GraphicalRepresentation newGR = ((GraphicalRepresentationAdded) notification).getAddedGraphicalRepresentation();
logger.fine("DrawingView: Received ObjectAdded notification, creating view for " + newGR);
if (newGR instanceof ShapeGraphicalRepresentation) {
ShapeGraphicalRepresentation shapeGR = (ShapeGraphicalRepresentation) newGR;
add(shapeGR.makeShapeView(getController()));
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (newGR instanceof ConnectorGraphicalRepresentation) {
ConnectorGraphicalRepresentation connectorGR = (ConnectorGraphicalRepresentation) newGR;
add(connectorGR.makeConnectorView(getController()));
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (newGR instanceof GeometricGraphicalRepresentation) {
newGR.addObserver(this);
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
}
} else if (notification instanceof GraphicalRepresentationRemoved) {
GraphicalRepresentation<?> removedGR = ((GraphicalRepresentationRemoved) notification)
.getRemovedGraphicalRepresentation();
if (removedGR instanceof ShapeGraphicalRepresentation) {
ShapeView<?> view = shapeViewForObject((ShapeGraphicalRepresentation<?>) removedGR);
if (view != null) {
remove(view);
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else {
// That may happen, remove warning
// logger.warning("Cannot find view for " + removedGR);
}
} else if (removedGR instanceof ConnectorGraphicalRepresentation) {
ConnectorView<?> view = connectorViewForObject((ConnectorGraphicalRepresentation<?>) removedGR);
if (view != null) {
remove(view);
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else {
// That may happen, remove warning
// logger.warning("Cannot find view for " + removedGR);
}
} else if (removedGR instanceof GeometricGraphicalRepresentation) {
removedGR.deleteObserver(this);
revalidate();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
}
} else if (notification instanceof ObjectResized) {
rescale();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (notif.getParameter() == DrawingGraphicalRepresentation.Parameters.backgroundColor) {
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
updateBackground();
getPaintManager().repaint(this);
} else if (notif.getParameter() == DrawingGraphicalRepresentation.Parameters.drawWorkingArea) {
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
updateBackground();
getPaintManager().repaint(this);
} else if (notif.getParameter() == DrawingGraphicalRepresentation.Parameters.width) {
rescale();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (notif.getParameter() == DrawingGraphicalRepresentation.Parameters.height) {
rescale();
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (notif.getParameter() == DrawingGraphicalRepresentation.Parameters.isResizable) {
if (getDrawingGraphicalRepresentation().isResizable()) {
removeMouseListener(mouseListener); // We remove the mouse
// listener, so that the
// mouse resizer is
// called before
// mouseListener
if (resizer == null) {
resizer = new DrawingViewResizer();
} else {
addMouseListener(resizer);
}
addMouseListener(mouseListener);
} else {
removeMouseListener(resizer);
}
} else if (notif instanceof DrawingNeedsToBeRedrawn) {
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (o instanceof GeometricGraphicalRepresentation) {
getPaintManager().invalidate(getDrawingGraphicalRepresentation());
getPaintManager().repaint(this);
}
}
}
}
private RectangleSelectingAction _rectangleSelectingAction;
public void setRectangleSelectingAction(RectangleSelectingAction action) {
_rectangleSelectingAction = action;
}
public void resetRectangleSelectingAction() {
_rectangleSelectingAction = null;
getPaintManager().repaint(this);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
getGraphicalRepresentation().paint(g, getController());
}
private long cumulatedRepaintTime = 0;
private boolean isBuffering = false;
private boolean bufferingHasBeenStartedAgain = false;
private boolean paintTemporary;
/**
*
* @param g
* graphics on which buffering will be performed
*/
protected synchronized void prepareForBuffering(Graphics2D g) {
isBuffering = true;
}
public synchronized boolean isBuffering() {
return isBuffering;
}
/**
* Perform a new buffering (cancel currently performed buffering)
*/
protected void startBufferingAgain() {
bufferingHasBeenStartedAgain = true;
}
private void forcePaintTemporaryObjects(GraphicalRepresentation<?> fatherGraphicalRepresentation, Graphics g) {
forcePaintObjects(fatherGraphicalRepresentation, g, true);
}
private void forcePaintObjects(GraphicalRepresentation<?> fatherGraphicalRepresentation, Graphics g) {
forcePaintObjects(fatherGraphicalRepresentation, g, false);
}
private void forcePaintObjects(GraphicalRepresentation<?> fatherGraphicalRepresentation, final Graphics g, boolean temporaryObjectsOnly) {
List<? extends GraphicalRepresentation<?>> containedGR = fatherGraphicalRepresentation
.getOrderedContainedGraphicalRepresentations();
if (containedGR == null) {
return;
}
paintTemporary = true;
for (GraphicalRepresentation<?> gr : new ArrayList<GraphicalRepresentation<?>>(containedGR)) {
if (gr.shouldBeDisplayed()
&& (!temporaryObjectsOnly || getPaintManager().isTemporaryObject(gr) || getPaintManager().containsTemporaryObject(gr))) {
FGEView<?> view = viewForObject(gr);
if (view == null) {
continue;
}
Component viewAsComponent = (Component) view;
Graphics childGraphics = g.create(viewAsComponent.getX(), viewAsComponent.getY(), viewAsComponent.getWidth(),
viewAsComponent.getHeight());
if (getPaintManager().isTemporaryObject(gr) || !temporaryObjectsOnly) {
if (FGEPaintManager.paintPrimitiveLogger.isLoggable(Level.FINE)) {
FGEPaintManager.paintPrimitiveLogger.fine("DrawingView: continuous painting, paint " + gr
+ " temporaryObjectsOnly=" + temporaryObjectsOnly);
}
gr.paint(childGraphics, getController());
LabelView<?> labelView = view.getLabelView();
if (labelView != null) {
Graphics labelGraphics = g.create(labelView.getX(), labelView.getY(), labelView.getWidth(), labelView.getHeight());
// Tricky area: if label is currently being edited,
// call to paint is required here
// to paint text component above buffer image.
// Otherwise, just call doPaint to force paint label
labelView.paint(labelGraphics);
labelGraphics.dispose();
}
// do the job for childs
forcePaintObjects(gr, childGraphics, false);
} else {
// do the job for childs
forcePaintObjects(gr, childGraphics, true);
}
}
}
paintTemporary = false;
}
public boolean isPaintTemporary() {
return paintTemporary;
}
@Override
public synchronized void paint(Graphics g) {
if (isDeleted()) {
return;
}
long startTime = System.currentTimeMillis();
if (getPaintManager().isPaintingCacheEnabled()) {
if (isBuffering) {
// Buffering painting
if (FGEPaintManager.paintPrimitiveLogger.isLoggable(Level.FINE)) {
FGEPaintManager.paintPrimitiveLogger.fine("DrawingView: Paint for image buffering area, clip=" + g.getClipBounds());
}
super.paint(g);
if (bufferingHasBeenStartedAgain) {
g.clearRect(0, 0, getGraphicalRepresentation().getViewWidth(getController().getScale()), getGraphicalRepresentation()
.getViewHeight(getController().getScale()));
super.paint(g);
bufferingHasBeenStartedAgain = false;
}
} else {
if (getPaintManager().renderUsingBuffer((Graphics2D) g, g.getClipBounds(), getDrawingGraphicalRepresentation(), getScale())) {
// Now, we still have to paint objects that are declared
// to be temporary and continuously to be redrawn
forcePaintTemporaryObjects(getDrawingGraphicalRepresentation(), g);
} else {
// This failed for some reasons (eg rendering request
// outside cached image)
// Skip buffering and perform normal rendering
super.paint(g);
}
paintCapturedNode(g);
}
} else {
// Normal painting
super.paint(g);
}
paintGeometricGraphicalRepresentation(g);
if (!isBuffering) {
FGEDrawingGraphics graphics = getDrawingGraphicalRepresentation().getGraphics();
Graphics2D g2 = (Graphics2D) g;
graphics.createGraphics(g2, getController());
// Don't paint those things in case of buffering
for (GraphicalRepresentation<?> o : new ArrayList<GraphicalRepresentation<?>>(getController().getFocusedObjects())) {
// logger.info("Paint focused " + o);
paintFocused(o, graphics);
}
for (GraphicalRepresentation<?> o : new ArrayList<GraphicalRepresentation<?>>(getController().getSelectedObjects())) {
// logger.info("Paint selected " + o + "shouldBeDisplayed=" + o.shouldBeDisplayed());
if (o.shouldBeDisplayed()) {
paintSelected(o, graphics);
}
}
/*
* if ((getController().getFocusedFloatingLabel() != null &&
* getController().getFocusedFloatingLabel().hasFloatingLabel())) {
* paintFocusedFloatingLabel
* (getController().getFocusedFloatingLabel(), g); }
*/
if (getController().getCurrentTool() == EditorTool.DrawShapeTool) {
// logger.info("Painting current edited shape");
paintCurrentEditedShape(graphics);
}
graphics.releaseGraphics();
if (_rectangleSelectingAction != null) {
_rectangleSelectingAction.paint(g, getController());
}
}
// Do it once only !!!
isBuffering = false;
long endTime = System.currentTimeMillis();
// System.out.println("END paint() in DrawingView, this took "+(endTime-startTime)+" ms");
cumulatedRepaintTime += endTime - startTime;
if (FGEPaintManager.paintStatsLogger.isLoggable(Level.FINE)) {
FGEPaintManager.paintStatsLogger.fine("PAINT " + getName() + " clip=" + g.getClip() + " time=" + (endTime - startTime)
+ "ms cumulatedRepaintTime=" + cumulatedRepaintTime + " ms");
}
}
private void paintGeometricGraphicalRepresentation(Graphics g) {
List<GeometricGraphicalRepresentation<?>> geomList = new ArrayList<GeometricGraphicalRepresentation<?>>();
for (Object gr : getGraphicalRepresentation().getOrderedContainedGraphicalRepresentations()) {
if (gr instanceof GeometricGraphicalRepresentation<?>) {
geomList.add((GeometricGraphicalRepresentation<?>) gr);
}
}
if (geomList.size() > 0) {
Collections.sort(geomList, new Comparator<GeometricGraphicalRepresentation<?>>() {
@Override
public int compare(GeometricGraphicalRepresentation<?> o1, GeometricGraphicalRepresentation<?> o2) {
return o1.getLayer() - o2.getLayer();
}
});
for (GeometricGraphicalRepresentation<?> gr : geomList) {
gr.paint(g, getController());
}
}
}
private void paintFocusedFloatingLabel(GraphicalRepresentation<?> focusedFloatingLabel, Graphics g) {
Color color = Color.BLACK;
if (focusedFloatingLabel.getIsSelected()) {
color = getDrawingView().getDrawingGraphicalRepresentation().getSelectionColor();
} else if (focusedFloatingLabel.getIsFocused()) {
color = getDrawingView().getDrawingGraphicalRepresentation().getFocusColor();
} else {
return;
}
FGEView<?> view = viewForObject(focusedFloatingLabel);
LabelView<?> labelView = view.getLabelView();
if (labelView != null) {
Point p1 = SwingUtilities.convertPoint(labelView, new Point(0, labelView.getHeight() / 2), this);
Point p2 = SwingUtilities.convertPoint(labelView, new Point(labelView.getWidth(), labelView.getHeight() / 2), this);
paintControlPoint(p1, color, g);
paintControlPoint(p2, color, g);
}
}
public void paintControlArea(ControlArea<?> ca, FGEDrawingGraphics graphics) {
Rectangle invalidatedArea = ca.paint(graphics);
if (invalidatedArea != null) {
getPaintManager().addTemporaryRepaintArea(invalidatedArea, this);
}
}
private void paintControlPoint(Point location, Color color, Graphics g) {
int size = FGEConstants.CONTROL_POINT_SIZE;
g.setColor(color);
Rectangle r = new Rectangle(location.x - size, location.y - size, size * 2, size * 2);
g.fillRect(r.x, r.y, r.width, r.height);
getPaintManager().addTemporaryRepaintArea(r, this);
}
private void paintSelected(GraphicalRepresentation<?> selected, FGEDrawingGraphics graphics) {
if (selected.isDeleted()) {
logger.warning("Cannot paint for a deleted GR");
return;
}
if (!selected.getDrawControlPointsWhenSelected()) {
// Don't paint control points in this case
return;
}
Graphics2D oldGraphics = graphics.cloneGraphics();
graphics.setDefaultForeground(ForegroundStyle.makeStyle(getGraphicalRepresentation().getSelectionColor()));
if (selected instanceof ShapeGraphicalRepresentation) {
ShapeGraphicalRepresentation<?> gr = (ShapeGraphicalRepresentation<?>) selected;
for (ControlArea<?> ca : gr.getControlAreas()) {
if (selected.isConnectedToDrawing()) {
paintControlArea(ca, graphics);
}
}
}
else if (selected instanceof ConnectorGraphicalRepresentation) {
ConnectorGraphicalRepresentation<?> gr = (ConnectorGraphicalRepresentation<?>) selected;
// g.setColor(getGraphicalRepresentation().getSelectionColor());
if (gr.getStartObject() == null || gr.getStartObject().isDeleted()) {
logger.warning("Could not paint connector: start object is null or deleted");
return;
}
if (gr.getEndObject() == null || gr.getEndObject().isDeleted()) {
logger.warning("Could not paint connector: end object is null or deleted");
return;
}
for (ControlArea<?> ca : gr.getControlAreas()) {
if (selected.isConnectedToDrawing()) {
paintControlArea(ca, graphics);
}
}
}
if (selected.hasFloatingLabel()) {
paintFocusedFloatingLabel(selected, graphics.getGraphics());
}
graphics.releaseClonedGraphics(oldGraphics);
}
private void paintCurrentEditedShape(FGEDrawingGraphics graphics) {
// logger.info("Painting current edited shape");
/*GeometricGraphicalRepresentation<?> currentEditedShape = getController().getDrawShapeToolController().getCurrentEditedShapeGR();
if (currentEditedShape.isDeleted()) {
logger.warning("Cannot paint for a deleted GR");
return;
}*/
if (!getController().getDrawShapeToolController().editionHasBeenStarted()) {
return;
}
getController().getDrawShapeToolController().paintCurrentEditedShape(graphics);
Graphics2D oldGraphics = graphics.cloneGraphics();
graphics.setDefaultForeground(ForegroundStyle.makeStyle(getGraphicalRepresentation().getFocusColor()));
for (ControlArea<?> ca : getController().getDrawShapeToolController().getControlAreas()) {
paintControlArea(ca, graphics);
}
graphics.releaseClonedGraphics(oldGraphics);
}
private void paintFocused(GraphicalRepresentation<?> focused, FGEDrawingGraphics graphics) {
if (focused.isDeleted()) {
logger.warning("Cannot paint for a deleted GR");
return;
}
if (!focused.getDrawControlPointsWhenFocused()) {
// Don't paint control points in this case
return;
}
Graphics2D oldGraphics = graphics.cloneGraphics();
graphics.setDefaultForeground(ForegroundStyle.makeStyle(getGraphicalRepresentation().getFocusColor()));
if (focused instanceof ShapeGraphicalRepresentation) {
ShapeGraphicalRepresentation<?> gr = (ShapeGraphicalRepresentation<?>) focused;
for (ControlArea<?> ca : gr.getControlAreas()) {
if (focused.isConnectedToDrawing()) {
paintControlArea(ca, graphics);
}
}
} else if (focused instanceof ConnectorGraphicalRepresentation) {
ConnectorGraphicalRepresentation<?> gr = (ConnectorGraphicalRepresentation<?>) focused;
if (gr.getStartObject() == null || gr.getStartObject().isDeleted()) {
logger.warning("Could not paint connector: start object is null or deleted");
return;
}
if (gr.getEndObject() == null || gr.getEndObject().isDeleted()) {
logger.warning("Could not paint connector: end object is null or deleted");
return;
}
for (ControlArea<?> ca : gr.getControlAreas()) {
if (focused.isConnectedToDrawing()) {
paintControlArea(ca, graphics);
}
}
}
if (focused.hasFloatingLabel()) {
paintFocusedFloatingLabel(focused, graphics.getGraphics());
}
/*
* else if (focused instanceof GeometricGraphicalRepresentation) {
* GeometricGraphicalRepresentation gr =
* (GeometricGraphicalRepresentation)focused; Graphics2D g2 =
* (Graphics2D) g; graphics.createGraphics(g2,getController());
* graphics.
* setDefaultForeground(ForegroundStyle.makeStyle(getGraphicalRepresentation
* ().getFocusColor()));
* graphics.setDefaultBackground(BackgroundStyle.makeColoredBackground
* (getGraphicalRepresentation().getFocusColor()));
* gr.getGeometricObject().paint(graphics); graphics.releaseGraphics();
* }
*/
graphics.releaseClonedGraphics(oldGraphics);
}
/*
* private void paintFocusedFloatingLabel(GraphicalRepresentation focused,
* Graphics g) { if (focused instanceof ShapeGraphicalRepresentation) { }
* else if (focused instanceof ConnectorGraphicalRepresentation) {
* ConnectorGraphicalRepresentation gr =
* (ConnectorGraphicalRepresentation)focused;
* g.setColor(getGraphicalRepresentation().getFocusColor()); Point p1 =
* getGraphicalRepresentation
* ().convertRemoteNormalizedPointToLocalViewCoordinates
* (gr.getConnector().getLabelCP1().getPoint(), focused, getScale());
* g.fillRect(p1.x-FGEConstants.CONTROL_POINT_SIZE,
* p1.y-FGEConstants.CONTROL_POINT_SIZE, FGEConstants.CONTROL_POINT_SIZE*2,
* FGEConstants.CONTROL_POINT_SIZE*2); Point p2 =
* getGraphicalRepresentation(
* ).convertRemoteNormalizedPointToLocalViewCoordinates
* (gr.getConnector().getLabelCP2().getPoint(), focused, getScale());
* g.fillRect(p2.x-FGEConstants.CONTROL_POINT_SIZE,
* p2.y-FGEConstants.CONTROL_POINT_SIZE, FGEConstants.CONTROL_POINT_SIZE*2,
* FGEConstants.CONTROL_POINT_SIZE*2); } }
*/
public Map<GraphicalRepresentation<?>, FGEView<?>> getContents() {
return contents;
}
@SuppressWarnings("unchecked")
public <O> FGEView<O> viewForObject(GraphicalRepresentation<O> gr) {
if (gr == getGraphicalRepresentation()) {
return (FGEView<O>) this;
}
return (FGEView<O>) contents.get(gr);
}
public <O> ShapeView<O> shapeViewForObject(ShapeGraphicalRepresentation<O> gr) {
return (ShapeView<O>) viewForObject(gr);
}
public <O> ConnectorView<O> connectorViewForObject(ConnectorGraphicalRepresentation<O> gr) {
return (ConnectorView<O>) viewForObject(gr);
}
public FocusRetriever getFocusRetriever() {
return _focusRetriever;
}
public DrawingViewMouseListener getMouseListener() {
return mouseListener;
}
private DrawingPalette activePalette;
@Override
public void registerPalette(DrawingPalette aPalette) {
// A palette is registered, listen to drag'n'drop events
logger.fine("Registering drop target");
setDropTarget(new DropTarget(this, DnDConstants.ACTION_COPY, aPalette.buildPaletteDropListener(this, _controller), true));
activePalette = aPalette;
for (FGEView<?> v : contents.values()) {
v.registerPalette(aPalette);
}
}
@Override
public FGEPaintManager getPaintManager() {
return _paintManager;
}
public boolean contains(FGEView<?> view) {
if (view == null) {
return false;
}
if (view == this) {
return true;
}
if (((JComponent) view).getParent() != null && ((JComponent) view).getParent() instanceof FGEView) {
return contains((FGEView<?>) ((JComponent) view).getParent());
}
return false;
}
@Override
public String getToolTipText(MouseEvent event) {
return getController().getToolTipText();
}
private boolean isDeleted = false;
@Override
public boolean isDeleted() {
return isDeleted;
}
@Override
public void delete() {
// logger.info("delete() in DrawingView");
removeMouseListener(mouseListener);
removeMouseMotionListener(mouseListener);
List<FGEView<?>> views = new ArrayList<FGEView<?>>(contents.values());
for (FGEView<?> v : views) {
v.delete();
// logger.info("Deleted view "+v);
}
contents.clear();
getGraphicalRepresentation().deleteObserver(this);
for (Object gr : getGraphicalRepresentation().getContainedGraphicalRepresentations()) {
if (gr instanceof GeometricGraphicalRepresentation) {
((GeometricGraphicalRepresentation<?>) gr).deleteObserver(this);
}
}
isDeleted = true;
}
private Rectangle drawnRectangle = new Rectangle();
private BufferedImage capturedDraggedNodeImage;
private Point capturedNodeLocation;
// This call is made on the edition drawing view
public final void updateCapturedDraggedNodeImagePosition(DropTargetDragEvent e, DrawingView<?> source) {
capturedNodeLocation = SwingUtilities.convertPoint(((DropTarget) e.getSource()).getComponent(), e.getLocation(), this);
if (source != this) {
dragOrigin = activePalette.getPaletteView().dragOrigin; // transfer from
// the palette
// to the
// edition view
}
if (dragOrigin == null) {
return;
}
capturedNodeLocation.x -= dragOrigin.x * getScale();
capturedNodeLocation.y -= dragOrigin.y * getScale();
capturedDraggedNodeImage = source.capturedDraggedNodeImage;
if (capturedNodeLocation == null || capturedDraggedNodeImage == null || drawnRectangle != null
&& capturedNodeLocation.equals(drawnRectangle.getLocation())) {
return;
}
getPaintManager().repaint(this, drawnRectangle.getBounds());
// System.out.println("Paint: "+drawnRectangle.getBounds()+" isDoubleBuffered="+isDoubleBuffered());
int scaledWidth = (int) (capturedDraggedNodeImage.getWidth() * getScale());
int scaledHeight = (int) (capturedDraggedNodeImage.getHeight() * getScale());
drawnRectangle.setRect((int) capturedNodeLocation.getX(), (int) capturedNodeLocation.getY(), scaledWidth, scaledHeight);
getPaintManager().repaint(this, drawnRectangle.getBounds());
}
private void paintCapturedNode(Graphics g) {
if (capturedDraggedNodeImage != null && drawnRectangle != null) {
Graphics2D g2 = (Graphics2D) g;
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.7f));
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.drawImage(capturedDraggedNodeImage, (int) drawnRectangle.getX(), (int) drawnRectangle.getY(),
(int) drawnRectangle.getWidth(), (int) drawnRectangle.getHeight(), this);
}
}
private Point dragOrigin;
// This call is made on the drawing view of the palette
public void captureDraggedNode(ShapeView<?> view, MouseEvent e) {
capturedDraggedNodeImage = view.getScreenshot();
dragOrigin = SwingUtilities.convertPoint((Component) e.getSource(), e.getPoint(), view);
}
public void captureDraggedNode(ShapeView<?> view, DragGestureEvent e) {
capturedDraggedNodeImage = view.getScreenshot();
dragOrigin = SwingUtilities.convertPoint(e.getComponent(), e.getDragOrigin(), view);
}
public void resetCapturedNode() {
if (capturedDraggedNodeImage != null) {
getPaintManager().repaint(this, drawnRectangle.getBounds());
capturedDraggedNodeImage = null;
}
}
public DrawingPalette getActivePalette() {
return activePalette;
}
private static final int margin = 20;
@Override
public void autoscroll(Point p) {
JScrollPane scroll = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
if (scroll == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Not inside a scroll pane, cannot scroll!");
}
return;
}
Rectangle visible = this.getVisibleRect();
p.x -= visible.x;
p.y -= visible.y;
Rectangle inner = this.getParent().getBounds();
inner.x += margin;
inner.y += margin;
inner.height -= 2 * margin;
inner.width -= 2 * margin;
if (p.x < inner.x) {// Move Left
JScrollBar bar = scroll.getHorizontalScrollBar();
if (bar != null) {
if (bar.getValue() > bar.getMinimum()) {
bar.setValue(bar.getValue() - bar.getUnitIncrement(-1));
}
}
} else if (p.x > inner.x + inner.width) { // Move right
JScrollBar bar = scroll.getHorizontalScrollBar();
if (bar != null) {
if (bar.getValue() < bar.getMaximum()) {
bar.setValue(bar.getValue() + bar.getUnitIncrement(1));
}
}
}
if (p.y < inner.y) { // Move up
JScrollBar bar = scroll.getVerticalScrollBar();
if (bar != null) {
if (bar.getValue() > bar.getMinimum()) {
bar.setValue(bar.getValue() - bar.getUnitIncrement(-1));
}
}
} else if (p.y > inner.y + inner.height) { // Move down
JScrollBar bar = scroll.getVerticalScrollBar();
if (bar != null) {
if (bar.getValue() < bar.getMaximum()) {
bar.setValue(bar.getValue() + bar.getUnitIncrement(1));
}
}
}
}
@Override
public Insets getAutoscrollInsets() {
Rectangle outer = getBounds();
Rectangle inner = getParent().getBounds();
return new Insets(inner.y - outer.y + margin, inner.x - outer.x + margin, outer.height - inner.height - inner.y + outer.y + margin,
outer.width - inner.width - inner.x + outer.x + margin);
}
}