/* Copyright (C) 2008 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad 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 2 of the License, or
* (at your option) any later version.
*
* Nomad 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 Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sf.nmedit.jtheme.util;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
import net.sf.nmedit.jpatch.PConnection;
import net.sf.nmedit.jpatch.PConnectionManager;
import net.sf.nmedit.jpatch.PConnector;
import net.sf.nmedit.jpatch.PModule;
import net.sf.nmedit.jpatch.PModuleContainer;
import net.sf.nmedit.jpatch.PModuleDescriptor;
import net.sf.nmedit.jpatch.impl.PBasicModule;
import net.sf.nmedit.jtheme.JTContext;
import net.sf.nmedit.jtheme.JTException;
import net.sf.nmedit.jtheme.cable.Cable;
import net.sf.nmedit.jtheme.cable.CableRenderer;
import net.sf.nmedit.jtheme.cable.JTCableManager;
import net.sf.nmedit.jtheme.cable.JTCableManagerImpl;
import net.sf.nmedit.jtheme.component.JTConnector;
import net.sf.nmedit.jtheme.component.JTModule;
import net.sf.nmedit.jtheme.component.JTModuleContainer;
import net.sf.nmedit.jtheme.component.plaf.SelectionPainter;
import net.sf.nmedit.jtheme.store.StorageContext;
import net.sf.nmedit.jtheme.store2.ModuleElement;
public class ModuleImageRenderer
{
private static final AlphaComposite alphaComposite =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f);
private static final AlphaComposite alphaComposite2 =
AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.25f);
private boolean renderCables = true;
private Dimension maximumSize = null;
private JTModuleContainer container = null;
private List<JTModule> modules = new ArrayList<JTModule>();
private boolean extraBorder;
private boolean forDragAndDrop = false;
public ModuleImageRenderer()
{
super();
}
public ModuleImageRenderer(Collection<? extends JTModule> modules)
{
super();
for (JTModule module: modules)
add(module);
}
public void setForDragAndDrop(boolean even_more_eyecandy)
{
this.forDragAndDrop = even_more_eyecandy;
}
public boolean add(JTModule module)
{
if (container == null)
{
if (module.getParent() instanceof JTModuleContainer)
container = (JTModuleContainer)module.getParent();
}
else
{
if (container != module.getParent())
return false; // not in the same container
}
modules.add(module);
return true;
}
public void setRenderCablesEnabled(boolean enable)
{
this.renderCables = enable;
}
public void setMaximumSize(Dimension max)
{
this.maximumSize = max;
}
public Image render()
{
BufferedImage image;
if (container != null)
{
synchronized (container.getTreeLock())
{
image = _render();
}
}
else
{
image = _render();
}
// scale image if necessary
if (maximumSize != null &&
(maximumSize.width<image.getWidth() || maximumSize.height<image.getHeight()))
{
// TODO
}
return image;
}
private BufferedImage _render()
{
Rectangle bounds = new Rectangle(0,0,0,0);
boolean first = true;
for (JTModule module: modules)
{
if (first)
{
bounds.setBounds(module.getBounds());
first = false;
}
else
{
bounds = SwingUtilities.computeUnion(
module.getX(), module.getY(),
module.getWidth(), module.getHeight(),
bounds);
}
}
boolean opaque =
(!forDragAndDrop) &&
(modules.size() == 1 && modules.get(0).isOpaque());
BufferedImage image = new BufferedImage(bounds.width, bounds.height,
opaque ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB );
Set<PModule> pmodules = null;
if (renderCables)
pmodules = new HashSet<PModule>();
Graphics2D g2 = image.createGraphics();
final Composite defaultComposite = g2.getComposite();
try
{
if (container != null)
{
g2.setFont(container.getFont());
g2.setColor(container.getBackground());
}
if (forDragAndDrop)
{
g2.setComposite(alphaComposite);
}
// paint modules
for (JTModule module: modules)
{
Graphics2D gg2 = (Graphics2D) g2.create();
try
{
// translate
gg2.setFont(module.getFont());
gg2.setColor(module.getBackground());
gg2.translate(module.getX()-bounds.x, module.getY()-bounds.y);
module.print(gg2);
}
finally
{
gg2.dispose();
}
if (renderCables)
{
PModule pmodule = module.getModule();
if (pmodule != null)
pmodules.add(pmodule);
}
}
// render cables
if (container != null && renderCables)
{
JTCableManager cm = container.getCableManager();
if (cm != null)
{
List<Cable> cables = new ArrayList<Cable>();
cm.getCables(cables, pmodules); // get cables
if (!cables.isEmpty())
{
CableRenderer cr = cm.getCableRenderer();
cr.initRenderer(g2);
g2.translate(-bounds.x, -bounds.y);
for (Cable cable: cables)
{
if (pmodules.contains(cable.getSourceModule())
&& pmodules.contains(cable.getDestinationModule()))
{
// only render cables which connect modules in selection
cr.render(g2, cable);
}
}
g2.translate(bounds.x, bounds.y);
}
}
}
if (forDragAndDrop)
{
g2.setColor(Color.BLACK);
g2.setComposite(alphaComposite2);
g2.fillRect(0, 0, bounds.width, bounds.height);
}
g2.setComposite(defaultComposite);
if (extraBorder)
SelectionPainter.paintSelectionBox(g2, modules, -bounds.x, -bounds.y);
}
finally
{
g2.dispose();
}
return image;
}
public void setPaintExtraBorder(boolean extra)
{
this.extraBorder = extra;
}
public static Image createImage(JTModuleContainer containerInContext, PModuleContainer pmoduleContainer,
boolean forDND, boolean extraBorder, boolean renderCables) throws JTException
{
// create user interface
JTContext context = containerInContext.getContext();
JTCableManager cm = new JTCableManagerImpl();
JTModuleContainer mc = new JTModuleContainer(context, cm);
cm.setOwner(mc);
cm.setView(mc);
cm.setCableRenderer(containerInContext.getCableManager().getCableRenderer());
Collection<? extends PModule> pmodules = pmoduleContainer.getModules();
List<JTModule> jtmodules = new ArrayList<JTModule>(pmodules.size());
Map<PModule, JTModule> moduleMap = new HashMap<PModule, JTModule>();
for (PModule pmodule: pmodules)
{
JTModule jtmodule = createJTModule(context, pmodule);
jtmodules.add(jtmodule);
mc.add(jtmodule);
moduleMap.put(pmodule, jtmodule);
}
// create cables
if (renderCables)
{
PConnectionManager connectionManager = pmoduleContainer.getConnectionManager();
for (PConnection connection: connectionManager)
{
PConnector pconnectorA = connection.getA();
PConnector pconnectorB = connection.getB();
PModule pmoduleA = connection.getModuleA();
PModule pmoduleB = connection.getModuleB();
JTModule jtmoduleA = moduleMap.get(pmoduleA);
JTModule jtmoduleB = moduleMap.get(pmoduleB);
JTConnector jtcA = null;
JTConnector jtcB = null;
for (int i=0;i<jtmoduleA.getComponentCount();i++)
{
if (jtmoduleA.getComponent(i) instanceof JTConnector)
{
JTConnector jtc = (JTConnector) jtmoduleA.getComponent(i);
if (jtc.getConnector() == pconnectorA)
{
jtcA = jtc;
break;
}
else if (jtc.getConnector() == pconnectorB)
{
jtcB = jtc;
break;
}
}
}
for (int i=0;i<jtmoduleB.getComponentCount();i++)
{
if (jtmoduleB.getComponent(i) instanceof JTConnector)
{
JTConnector jtc = (JTConnector) jtmoduleB.getComponent(i);
if (jtc.getConnector() == pconnectorA)
{
jtcA = jtc;
break;
}
else if (jtc.getConnector() == pconnectorB)
{
jtcB = jtc;
break;
}
}
}
if (jtcA != null && jtcB != null)
{
// create cable
Cable cable = cm.createCable(jtcA, jtcB);
cable.updateEndPoints(); // update location
Color color = pconnectorA.getRootConnector().getSignalType().getColor();
cable.setColor(color);
cm.add(cable);
}
}
}
// render image
ModuleImageRenderer mir = new ModuleImageRenderer(jtmodules);
mir.setForDragAndDrop(forDND);
mir.setPaintExtraBorder(extraBorder);
mir.setRenderCablesEnabled(renderCables);
Image image = mir.render();
// disconnect from PModule - uninstall listeners
for (JTModule jtmodule: jtmodules)
{
jtmodule.setModule(null);
}
return image;
}
public static Image render(JTContext context, PModuleDescriptor moduleDescriptor, boolean fordnd) throws JTException
{
StorageContext sc = context.getStorageContext();
ModuleElement scModuleElement = sc.getModuleStoreById(moduleDescriptor.getComponentId());
PModule pmodule = new PBasicModule(moduleDescriptor);
JTModule module = scModuleElement.createModule(context, pmodule, true);
ModuleImageRenderer renderer = new ModuleImageRenderer();
renderer.setForDragAndDrop(fordnd);
renderer.add(module);
return renderer.render();
}
public static Image render(JTContext context, PModule pmodule, boolean fordnd) throws JTException
{
JTModule module = createJTModule(context, pmodule);
ModuleImageRenderer renderer = new ModuleImageRenderer();
renderer.setForDragAndDrop(fordnd);
renderer.add(module);
return renderer.render();
}
private static JTModule createJTModule(JTContext context, PModule pmodule) throws JTException
{
StorageContext sc = context.getStorageContext();
ModuleElement scModuleElement = sc.getModuleStoreById(pmodule.getComponentId());
JTModule module = scModuleElement.createModule(context, pmodule, true);
module.setLocation(pmodule.getScreenX(), pmodule.getScreenY());
return module;
}
}