/*
* (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.AlphaComposite;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;
import org.openflexo.fge.ConnectorGraphicalRepresentation;
import org.openflexo.fge.DrawingGraphicalRepresentation;
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.DrawingPalette;
import org.openflexo.fge.notifications.FGENotification;
import org.openflexo.fge.notifications.GraphicalRepresentationAdded;
import org.openflexo.fge.notifications.GraphicalRepresentationDeleted;
import org.openflexo.fge.notifications.GraphicalRepresentationRemoved;
import org.openflexo.fge.notifications.ObjectHasMoved;
import org.openflexo.fge.notifications.ObjectHasResized;
import org.openflexo.fge.notifications.ObjectMove;
import org.openflexo.fge.notifications.ObjectResized;
import org.openflexo.fge.notifications.ObjectWillMove;
import org.openflexo.fge.notifications.ObjectWillResize;
import org.openflexo.fge.notifications.ShapeNeedsToBeRedrawn;
import org.openflexo.fge.view.listener.ShapeViewMouseListener;
public class ShapeView<O> extends FGELayeredView<O> {
private static final Logger logger = Logger.getLogger(ShapeView.class.getPackage().getName());
private ShapeGraphicalRepresentation<O> graphicalRepresentation;
private ShapeViewMouseListener mouseListener;
private DrawingController _controller;
private LabelView<O> _labelView;
public ShapeView(ShapeGraphicalRepresentation<O> aGraphicalRepresentation, DrawingController<?> controller) {
super();
logger.fine("Create ShapeView " + Integer.toHexString(hashCode()) + " for " + aGraphicalRepresentation);
_controller = controller;
graphicalRepresentation = aGraphicalRepresentation;
graphicalRepresentation.finalizeConstraints();
updateLabelView();
relocateAndResizeView();
mouseListener = makeShapeViewMouseListener();
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
getGraphicalRepresentation().addObserver(this);
setOpaque(false);
updateVisibility();
setFocusable(true);
if (controller.getPalettes() != null) {
for (DrawingPalette p : controller.getPalettes()) {
registerPalette(p);
}
}
// logger.info("make ShapeView with "+aGraphicalRepresentation+" bounds="+getBounds());
// setToolTipText(getClass().getSimpleName()+hashCode());
// System.out.println("isDoubleBuffered()="+isDoubleBuffered());
}
public void disableFGEViewMouseListener() {
System.out.println("Disable FGEViewMouseListener ");
removeMouseListener(mouseListener);
removeMouseMotionListener(mouseListener);
}
public void enableFGEViewMouseListener() {
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
private boolean isDeleted = false;
@Override
public boolean isDeleted() {
return isDeleted;
}
@Override
public synchronized void delete() {
logger.fine("Delete ShapeView " + Integer.toHexString(hashCode()) + " for " + getGraphicalRepresentation());
if (getParentView() != null) {
FGELayeredView parentView = getParentView();
// logger.warning("Unexpected not null parent, proceeding anyway");
parentView.remove(this);
parentView.revalidate();
if (getPaintManager() != null) {
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(parentView);
}
}
if (getGraphicalRepresentation() != null) {
getGraphicalRepresentation().deleteObserver(this);
}
setDropTarget(null);
removeMouseListener(mouseListener);
removeMouseMotionListener(mouseListener);
if (_labelView != null) {
_labelView.delete();
}
_labelView = null;
_controller = null;
mouseListener = null;
graphicalRepresentation = null;
isDeleted = true;
}
@Override
public O getModel() {
return getDrawable();
}
public O getDrawable() {
return getGraphicalRepresentation().getDrawable();
}
@Override
public DrawingView<?> getDrawingView() {
if (getController() != null) {
return getController().getDrawingView();
}
return null;
}
@Override
public FGELayeredView getParent() {
return (FGELayeredView) super.getParent();
}
public FGELayeredView getParentView() {
return getParent();
}
@Override
public ShapeGraphicalRepresentation<O> getGraphicalRepresentation() {
return graphicalRepresentation;
}
public DrawingGraphicalRepresentation<?> getDrawingGraphicalRepresentation() {
return graphicalRepresentation.getDrawingGraphicalRepresentation();
}
@Override
public double getScale() {
return getController().getScale();
}
@Override
public void rescale() {
relocateAndResizeView();
}
private void relocateAndResizeView() {
relocateView();
resizeView();
// System.out.println("relocateAndResizeView() for "+drawable+" bounds="+getBounds());
}
private void relocateView() {
if (getX() != getGraphicalRepresentation().getViewX(getScale()) || getY() != getGraphicalRepresentation().getViewY(getScale())) {
if (_labelView != null) {
_labelView.updateBounds();
}
setLocation(getGraphicalRepresentation().getViewX(getScale()), getGraphicalRepresentation().getViewY(getScale()));
} else {
// logger.info("Ignore relocateView() because unchanged");
}
}
private void resizeView() {
if (getWidth() != getGraphicalRepresentation().getViewWidth(getScale())
|| getHeight() != getGraphicalRepresentation().getViewHeight(getScale())) {
if (_labelView != null) {
_labelView.updateBounds();
}
setSize(getGraphicalRepresentation().getViewWidth(getScale()), getGraphicalRepresentation().getViewHeight(getScale()));
} else {
// logger.info("Ignore resizeView() because unchanged");
}
}
private void updateLayer() {
if (getParent() instanceof JLayeredPane) {
if (_labelView != null) {
getParent().setLayer((Component) _labelView, getLayer());
getParent().setPosition(_labelView, getGraphicalRepresentation().getLayerOrder() * 2);
}
getParent().setLayer((Component) this, getLayer());
getParent().setPosition(this, getGraphicalRepresentation().getLayerOrder() * 2 + 1);
}
}
private void updateVisibility() {
if (_labelView != null) {
_labelView.setVisible(getGraphicalRepresentation().shouldBeDisplayed());
}
setVisible(getGraphicalRepresentation().shouldBeDisplayed());
}
private void updateLabelView() {
if (!getGraphicalRepresentation().getHasText() && _labelView != null) {
_labelView.delete();
_labelView = null;
} else if (getGraphicalRepresentation().getHasText() && _labelView == null) {
_labelView = new LabelView<O>(getGraphicalRepresentation(), getController(), this);
if (getParentView() != null) {
getParentView().add(getLabelView(), getLayer(), -1);
}
}
}
public Integer getLayer() {
return FGEConstants.INITIAL_LAYER + getGraphicalRepresentation().getLayer();
}
@Override
public void paint(Graphics g) {
if (isDeleted()) {
return;
}
if (getPaintManager().isPaintingCacheEnabled()) {
if (getDrawingView().isBuffering()) {
// Buffering painting
if (getPaintManager().isTemporaryObject(getGraphicalRepresentation())) {
// This object is declared to be a temporary object, to be redrawn
// continuously, so we need to ignore it: do nothing
if (FGEPaintManager.paintPrimitiveLogger.isLoggable(Level.FINE)) {
FGEPaintManager.paintPrimitiveLogger.fine("ShapeView: buffering paint, ignore: " + getGraphicalRepresentation());
}
} else {
if (FGEPaintManager.paintPrimitiveLogger.isLoggable(Level.FINE)) {
FGEPaintManager.paintPrimitiveLogger.fine("ShapeView: buffering paint, draw: " + getGraphicalRepresentation()
+ " clip=" + g.getClip());
}
doPaint(g);
}
} else {
if (!getPaintManager().renderUsingBuffer((Graphics2D) g, g.getClipBounds(), getGraphicalRepresentation(), getScale())) {
doPaint(g);
}
/*
// Use buffer
Image buffer = getPaintManager().getPaintBuffer();
Rectangle localViewBounds = g.getClipBounds();
Rectangle viewBoundsInDrawingView = GraphicalRepresentation.convertRectangle(getGraphicalRepresentation(), localViewBounds, getDrawingGraphicalRepresentation(), getScale());
//System.out.println("SHAPEVIEW Paint buffer "+g.getClipBounds());
Point dp1 = localViewBounds.getLocation();
Point dp2 = new Point(localViewBounds.x+localViewBounds.width,localViewBounds.y+localViewBounds.height);
Point sp1 = viewBoundsInDrawingView.getLocation();
Point sp2 = new Point(viewBoundsInDrawingView.x+viewBoundsInDrawingView.width,viewBoundsInDrawingView.y+viewBoundsInDrawingView.height);
if (FGEPaintManager.paintPrimitiveLogger.isLoggable(Level.FINE))
FGEPaintManager.paintPrimitiveLogger.fine("ShapeView: use image buffer, copy area from "+sp1+"x"+sp2+" to "+dp1+"x"+dp2);
g.drawImage(buffer,
dp1.x,dp1.y,dp2.x,dp2.y,
sp1.x,sp1.y,sp2.x,sp2.y,
null);
*/
}
} else {
// Normal painting
doPaint(g);
}
// getGraphicalRepresentation().paint(g,getController());
// super.paint(g);
}
private void doPaint(Graphics g) {
getGraphicalRepresentation().paint(g, getController());
super.paint(g);
}
protected ShapeViewMouseListener makeShapeViewMouseListener() {
return new ShapeViewMouseListener(graphicalRepresentation, this);
}
@Override
public DrawingController<?> getController() {
return _controller;
}
@Override
public void update(final Observable o, final Object aNotification) {
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, aNotification);
}
});
} else {
// logger.info("For " + getGraphicalRepresentation().getClass().getSimpleName() + " received: " + aNotification);
if (aNotification instanceof FGENotification) {
FGENotification notification = (FGENotification) aNotification;
if (notification instanceof GraphicalRepresentationAdded) {
GraphicalRepresentation<?> newGR = ((GraphicalRepresentationAdded) notification).getAddedGraphicalRepresentation();
logger.fine("ShapeView: Received ObjectAdded notification, creating view for " + newGR);
if (newGR instanceof ShapeGraphicalRepresentation) {
ShapeGraphicalRepresentation<?> shapeGR = (ShapeGraphicalRepresentation<?>) newGR;
add(shapeGR.makeShapeView(getController()));
revalidate();
getPaintManager().repaint(this);
shapeGR.notifyShapeNeedsToBeRedrawn();
} else if (newGR instanceof ConnectorGraphicalRepresentation) {
ConnectorGraphicalRepresentation<?> connectorGR = (ConnectorGraphicalRepresentation<?>) newGR;
add(connectorGR.makeConnectorView(getController()));
revalidate();
getPaintManager().repaint(this);
} else if (newGR instanceof GeometricGraphicalRepresentation) {
newGR.addObserver(this);
revalidate();
getPaintManager().repaint(this);
}
} else if (notification instanceof GraphicalRepresentationRemoved) {
GraphicalRepresentation<?> removedGR = ((GraphicalRepresentationRemoved) notification)
.getRemovedGraphicalRepresentation();
if (removedGR instanceof ShapeGraphicalRepresentation) {
ShapeView<?> view = getDrawingView().shapeViewForObject((ShapeGraphicalRepresentation<?>) removedGR);
if (view != null) {
remove(view);
revalidate();
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(this);
} else {
logger.warning("Cannot find view for " + removedGR);
}
} else if (removedGR instanceof ConnectorGraphicalRepresentation) {
ConnectorView<?> view = getDrawingView().connectorViewForObject((ConnectorGraphicalRepresentation<?>) removedGR);
if (view != null) {
remove(view);
revalidate();
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(this);
} else {
logger.warning("Cannot find view for " + removedGR);
}
} else if (removedGR instanceof GeometricGraphicalRepresentation) {
removedGR.deleteObserver(this);
revalidate();
getPaintManager().repaint(this);
}
} else if (notification instanceof GraphicalRepresentationDeleted) {
GraphicalRepresentation<?> deletedGR = ((GraphicalRepresentationDeleted) notification)
.getDeletedGraphicalRepresentation();
// If was not removed, try to do it now
if (getGraphicalRepresentation() != null && getGraphicalRepresentation().getContainerGraphicalRepresentation() != null
&& getGraphicalRepresentation().getContainerGraphicalRepresentation().contains(getGraphicalRepresentation())) {
getGraphicalRepresentation().getContainerGraphicalRepresentation().notifyDrawableRemoved(deletedGR);
}
if (getGraphicalRepresentation() != null && getController().getFocusedObjects().contains(getGraphicalRepresentation())) {
getController().removeFromFocusedObjects(getGraphicalRepresentation());
}
if (getGraphicalRepresentation() != null && getController().getSelectedObjects().contains(getGraphicalRepresentation())) {
getController().removeFromSelectedObjects(getGraphicalRepresentation());
}
delete();
} else if (notification instanceof ObjectWillMove) {
if (getPaintManager().isPaintingCacheEnabled()) {
getPaintManager().addToTemporaryObjects(getGraphicalRepresentation());
getPaintManager().invalidate(getGraphicalRepresentation());
}
} else if (notification instanceof ObjectMove) {
relocateView();
if (getParentView() != null) {
getPaintManager().repaint(this);
}
} else if (notification instanceof ObjectHasMoved) {
if (getPaintManager().isPaintingCacheEnabled()) {
getPaintManager().removeFromTemporaryObjects(getGraphicalRepresentation());
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(getParentView());
}
} else if (notification instanceof ObjectWillResize) {
if (getPaintManager().isPaintingCacheEnabled()) {
getPaintManager().addToTemporaryObjects(getGraphicalRepresentation());
getPaintManager().invalidate(getGraphicalRepresentation());
}
} else if (notification instanceof ObjectResized) {
resizeView();
if (getParentView() != null) {
getParentView().revalidate();
getPaintManager().repaint(this);
}
} else if (notification instanceof ObjectHasResized) {
resizeView();
if (getPaintManager().isPaintingCacheEnabled()) {
getPaintManager().removeFromTemporaryObjects(getGraphicalRepresentation());
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(getParentView());
}
} else if (notification instanceof ShapeNeedsToBeRedrawn) {
getPaintManager().invalidate(getGraphicalRepresentation());
getPaintManager().repaint(this);
} else if (notification.getParameter() == GraphicalRepresentation.Parameters.layer) {
updateLayer();
if (!getPaintManager().isTemporaryObjectOrParentIsTemporaryObject(getGraphicalRepresentation())) {
getPaintManager().invalidate(getGraphicalRepresentation());
}
getPaintManager().repaint(this);
} else if (notification.getParameter() == GraphicalRepresentation.Parameters.isFocused) {
getPaintManager().repaint(this);
} else if (notification.getParameter() == GraphicalRepresentation.Parameters.hasText) {
updateLabelView();
} else if (notification.getParameter() == GraphicalRepresentation.Parameters.isSelected) {
if (getParent() != null) {
getParent().moveToFront(this);
}
if (getParent() != null && getLabelView() != null) {
getParent().moveToFront(getLabelView());
}
getPaintManager().repaint(this);
if (graphicalRepresentation.getIsSelected()) {
requestFocusInWindow();
// requestFocus();
}
} else if (notification.getParameter() == GraphicalRepresentation.Parameters.isVisible) {
updateVisibility();
if (getPaintManager().isPaintingCacheEnabled()) {
if (!getPaintManager().isTemporaryObjectOrParentIsTemporaryObject(getGraphicalRepresentation())) {
getPaintManager().invalidate(getGraphicalRepresentation());
}
}
getPaintManager().repaint(this);
} else {
// revalidate();
if (getPaintManager().isPaintingCacheEnabled()) {
if (!getPaintManager().isTemporaryObjectOrParentIsTemporaryObject(getGraphicalRepresentation())) {
getPaintManager().invalidate(getGraphicalRepresentation());
}
}
getPaintManager().repaint(this);
// revalidate();
// getPaintManager().repaint(this);
}
} else {
revalidate();
getPaintManager().repaint(this);
}
}
}
@Override
public LabelView<O> getLabelView() {
return _labelView;
}
@Override
public void registerPalette(DrawingPalette aPalette) {
// A palette is registered, listen to drag'n'drop events
setDropTarget(new DropTarget(this, DnDConstants.ACTION_COPY, aPalette.buildPaletteDropListener(this, _controller), true));
}
@Override
public FGEPaintManager getPaintManager() {
return getDrawingView().getPaintManager();
}
@Override
public String getToolTipText(MouseEvent event) {
return getController().getToolTipText();
}
private BufferedImage screenshot;
public BufferedImage getScreenshot() {
if (screenshot == null) {
captureScreenshot();
}
return screenshot;
}
private void captureScreenshot() {
JComponent lbl = this;
getController().disablePaintingCache();
try {
Rectangle bounds = new Rectangle(getBounds());
if (getLabelView() != null) {
bounds = bounds.union(getLabelView().getBounds());
}
GraphicsConfiguration gc = getGraphicsConfiguration();
if (gc == null) {
gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
screenshot = gc.createCompatibleImage(bounds.width, bounds.height, Transparency.TRANSLUCENT);// buffered image
// reference passing
// the label's ht
// and width
Graphics2D graphics = screenshot.createGraphics();// creating the graphics for buffered image
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // Sets the Composite for the Graphics2D
// context
lbl.print(graphics); // painting the graphics to label
/*if (this.getGraphicalRepresentation().getBackground() instanceof BackgroundImage) {
graphics.drawImage(((BackgroundImage)this.getGraphicalRepresentation().getBackground()).getImage(),0,0,null);
}*/
if (getLabelView() != null) {
Rectangle r = getLabelView().getBounds();
getLabelView().print(graphics.create(r.x - bounds.x, r.y - bounds.y, r.width, r.height));
}
graphics.dispose();
if (logger.isLoggable(Level.INFO)) {
logger.info("Captured image on " + this);
}
} finally {
getController().enablePaintingCache();
}
}
}