/* Copyright (C) 2006 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.cable;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
import net.sf.nmedit.jpatch.PModule;
import net.sf.nmedit.jtheme.component.JTConnector;
public class JTCableManagerImpl implements JTCableManager, Runnable
{
private CableRenderer cableRenderer;
private JComponent view;
private JComponent owner;
private int autorepaintDisabledCounter = 0;
public JTCableManagerImpl(CableRenderer cableRenderer)
{
this.cableRenderer = cableRenderer;
}
public void setOwner(JComponent owner)
{
this.owner = owner;
}
public JTCableManagerImpl()
{
super();
}
public JComponent getOwner()
{
return owner;
}
public boolean contains(Cable cable)
{
return cables.contains(cable);
}
private boolean isConnected(Cable c, PModule m)
{
return c.getSourceModule() == m || c.getDestinationModule() == m;
}
public void getCables(Collection<Cable> c, PModule module)
{
for (Cable cable: cables)
{
if (isConnected(cable, module))
c.add(cable);
}
}
public void getCables(Collection<Cable> c, Collection<? extends PModule> modules)
{
for (Cable cable: cables)
{
if (modules.contains(cable.getSourceModule()) || modules.contains(cable.getDestinationModule()))
c.add(cable);
}
}
public Cable createCable(JTConnector source, JTConnector destination)
{
return new SimpleCable(source, destination, new SimpleCableGeometrie());
}
public CableRenderer getCableRenderer()
{
return cableRenderer;
}
public void setView(JComponent view)
{
JComponent oldView = this.view;
if (oldView != view)
{
this.view = view;
markCompletelyDirty();
}
}
private void markCompletelyDirty()
{
dirty.setBounds(owner.getBounds());
repaintIfDirty();
}
public JComponent getView()
{
return view;
}
public void paintCables(Graphics2D g2)
{
paintCables(g2, cableRenderer);
}
public void setCableRenderer(CableRenderer cableRenderer)
{
if (this.cableRenderer != cableRenderer)
{
this.cableRenderer = cableRenderer;
markCompletelyDirty();
}
}
public int size()
{
return cables.size();
}
private transient Rectangle cachedRect;
private Rectangle clipRect = new Rectangle(); // must not be null
public void paintCables(Graphics2D g, CableRenderer cableRenderer)
{
Rectangle clip = g.getClipBounds(clipRect);
boolean hasClip = clip.x>0 || clip.y>0 || view == null
|| (clip.x+clip.width<view.getWidth())
|| (clip.y+clip.height<view.getHeight());
if ((!hasClip) || ((!dirty.isEmpty()) && clip.contains(dirty)))
{
dirty.setBounds(0, 0, 0, 0); // ensure bounds are cleared
}
cableRenderer.initRenderer(g);
if (!hasClip)
{
for (Cable c: cables)
cableRenderer.render(g, c);
}
else
{
enlarge(clip, cableRenderer.getCableDiameter()); // enlarge so that we don't miss a cable
for (Cable c: cables)
{
Rectangle b = (cachedRect=c.getBounds(cachedRect));
if (clip.intersects(b))
cableRenderer.render(g, c);
}
}
}
private Rectangle dirty = new Rectangle(0,0,0,0);
private void markDirty(Cable c, boolean automaticRepaint)
{
if (view != null && view.isShowing())
{
Rectangle bounds = c.getBounds();
if (dirty.isEmpty())
dirty.setBounds(bounds);
else
SwingUtilities.computeUnion(bounds.x, bounds.y, bounds.width, bounds.height, dirty);
if (automaticRepaint)
repaintIfDirty();
}
else
{
//System.out.println("not showing");
}
}
private List<Cable> cables = new ArrayList<Cable>();
public void add(Cable c)
{
if (!cables.contains(c))
{
if (cables.add(c))
markDirty(c, true);
}
}
public void remove(Cable c)
{
if (cables.remove(c))
cableRemoved(c);
}
private void cableRemoved(Cable c)
{
markDirty(c, true);
}
public void clear()
{
if (!cables.isEmpty())
{
for (Cable c: cables)
markDirty(c, false);
cables.clear();
repaintIfDirty();
}
}
public void remove(Cable[] cables)
{
for (int i=0;i<cables.length;i++)
{
Cable c = cables[i];
if (this.cables.remove(c))
{
markDirty(c, false);
}
repaintIfDirty();
}
}
public void remove(Collection<Cable> cables)
{
for (Cable c: cables)
{
if (this.cables.remove(c))
{
markDirty(c, false);
}
repaintIfDirty();
}
}
public void update(Cable c)
{
markDirty(c, true);
repaintIfDirty();
}
public void update(Cable[] cables)
{
for (int i=0;i<cables.length;i++)
markDirty(cables[i], false);
repaintIfDirty();
}
public void update(Collection<Cable> cables)
{
for (Cable c: cables)
markDirty(c, false);
repaintIfDirty();
}
private void repaintIfDirty()
{
if (!isAutoRepaintEnabled()) return;
if (!dirty.isEmpty())
{
if (EventQueue.isDispatchThread())
{
run();
}
else
{
EventQueue.invokeLater(this); // invokes this.run()
}
}
}
public void run()
{
letRepaintManagerRepaintIfDirty();
}
private void letRepaintManagerRepaintIfDirty()
{
if (dirty.isEmpty())
return;
enlarge(dirty, 10);
RepaintManager.currentManager(view).addDirtyRegion(view, dirty.x, dirty.y, dirty.width, dirty.height);
dirty.setBounds(0, 0, 0, 0);
}
private void enlarge(Rectangle r, int size)
{
r.x = Math.max(0, r.x-size);
r.y = Math.max(0, r.y-size);
r.width +=size+size;
r.height+=size+size;
}
public Iterator<Cable> iterator()
{
return new Iterator<Cable>()
{
Cable removable;
Iterator<Cable> iter = cables.iterator();
public boolean hasNext()
{
return iter.hasNext();
}
public Cable next()
{
removable = iter.next();
return removable;
}
public void remove()
{
iter.remove();
// reaches here if no exception occured
// removable is then != null
if (removable == null) return; // this should never be true
Cable c = removable;
removable = null;
cableRemoved(c);
}
};
}
public void clearAutoRepaintDisabled()
{
if (autorepaintDisabledCounter>0)
{
autorepaintDisabledCounter--;
if (isAutoRepaintEnabled())
repaintIfDirty();
}
}
public boolean isAutoRepaintEnabled()
{
return autorepaintDisabledCounter<=0;
}
public void setAutoRepaintDisabled()
{
autorepaintDisabledCounter++;
}
public void shake()
{
for (Cable cable: cables)
{
markDirty(cable, false);
cable.shake();
markDirty(cable, false);
}
repaintIfDirty();
}
}