//
// @(#)MapRenderer2.java 5/2003
//
// Copyright 2003 Zachary DelProposto. All rights reserved.
// Use is subject to license terms.
//
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// Or from http://www.gnu.org/
//
package dip.gui.map;
import dip.gui.map.RenderCommandFactory.RenderCommand;
//import dip.gui.ClientFrame;
//import dip.gui.AbstractCFPListener;
import dip.gui.order.GUIOrder;
import dip.order.Orderable;
import dip.misc.Log;
import dip.world.Province;
import dip.world.TurnState;
import dip.world.Location;
import dip.world.Power;
import dip.world.Unit;
import java.util.LinkedList;
import java.util.Iterator;
import org.w3c.dom.svg.SVGDocument;
//import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.RunnableQueue;
import org.apache.batik.util.RunnableQueue.RunnableQueueState;
//import org.apache.batik.bridge.UpdateManagerListener;
//import org.apache.batik.bridge.UpdateManagerEvent;
/**
* Base class for the new MapRenderer.
* <p>
* Implementation notes: remember to <b>always</b> synchronize around the
* <code>renderQueue</code> object.
*
*/
public abstract class MapRenderer2
{
// constant key values for getRenderSetting()
//
/** Key for getSettings(): */
public static final String KEY_LABELS = "KEY_LABELS";
/** Key for getSettings(): */
public static final String KEY_SHOW_SUPPLY_CENTERS = "KEY_SHOW_SUPPLY_CENTERS";
/** Key for getSettings(): */
public static final String KEY_SHOW_UNITS = "KEY_SHOW_UNITS";
/** Key for getSettings(): */
public static final String KEY_SHOW_DISLODGED_UNITS = "KEY_SHOW_DISLODGED_UNITS";
/** Key for getSettings(): */
public static final String KEY_SHOW_UNORDERED = "KEY_SHOW_UNORDERED";
/** Key for getSettings(): */
public static final String KEY_SHOW_ORDERS_FOR_POWERS = "KEY_SHOW_ORDERS_FOR_POWERS";
/** Key for getSettings(): */
public static final String KEY_INFLUENCE_MODE = "KEY_INFLUENCE_MODE";
/** Key for getSettings(): */
public static final String KEY_SHOW_MAP = "KEY_SHOW_MAP";
// constant return values for getRenderSetting()
//
/** Value returned from getSettings(): */
public static final String VALUE_LABELS_NONE = "VALUE_LABELS_NONE";
/** Value returned from getSettings(): */
public static final String VALUE_LABELS_FULL = "VALUE_LABELS_FULL";
/** Value returned from getSettings(): */
public static final String VALUE_LABELS_BRIEF = "VALUE_LABELS_BRIEF";
// instance variables
//
private boolean isReady = false; // internal flag indicating if turnstate has been set
private LinkedList tempQueue = null;
//private RunnableQueue runqueue;
//protected final MapPanel mapPanel;
//protected CFPropertyListener propListener = null;
//protected final JSVGCanvas svgCanvas;
protected SVGDocument doc;
public MapRenderer2(){}
/**
* Default Constructor
* JSVGCanvas and SVGDocument of MapPanel <b>must not be null</b>
*/
public MapRenderer2(SVGDocument svg)
{
//Log.printTimed(mp.startTime, "MR2 constructor start");
//mapPanel = mp;
//svgCanvas = mapPanel.getJSVGCanvas();
doc = svg;
//runqueue = null
//propListener = new CFPropertyListener();
//mapPanel.getClientFrame().addPropertyChangeListener(propListener);
tempQueue = new LinkedList();
//Log.printTimed(mp.startTime, "MR2 constructor end");
}// MapRenderer()
/** Convenience method */
//public final ClientFrame getClientFrame()
//{
// return mapPanel.getClientFrame();
//}// getClientFrame()
/**
* Gets the Runnable Queue for the canvas.
* Return null if this cannot be done (e.g., we are exiting).
*/
// public final RunnableQueue getRunnableQueue()
// {
// return runqueue;
// }// getRunnableQueue()
/**
* Get a setting (as defined by the KEY_ constants)
*/
public abstract Object getRenderSetting(final Object key);
/**
* Execute a RenderCommand. No commands are executed until the TurnState
* has been set.
* @throws InterruptedException
*/
public synchronized void execRenderCommand(RenderCommand rc)
{
if(rc instanceof RenderCommandFactory.RCSetTurnstate)
{
// focus
//mapPanel.requestFocusInWindow();
// dequeue pending events
isReady = true;
Log.println("MR2:execRenderCommand(): first RCSetTurnstate: ", rc);
clearAndExecute(rc, null);
// dequeue pending events, if any
if(!tempQueue.isEmpty())
{
Log.println("MR2::execRenderCommand(): removing pending events from queue. size: ",
String.valueOf(tempQueue.size()));
//RunnableQueue rq = getRunnableQueue();
// if(rq != null)
// {
Iterator iter = tempQueue.iterator();
while(iter.hasNext())
{
((RenderCommand) iter.next()).execute();
}
tempQueue.clear();
// }
}
}
else if(true)
{
// a RCSetTurnstate() has been issued. We can accept render events.
// if we have queued events, add them.
Log.println("MR2::execRenderCommand(): adding to RunnableQueue: ", rc);
//RunnableQueue rq = getRunnableQueue();
// if(rq != null)
// {
rc.execute();
// }
}
else
{
// we are not yet ready -- add the rendering events to a temporary queue.
Log.println("MR2::execRenderCommand(): adding to tempQueue: ", rc);
tempQueue.add(rc);
}
}// execRenderCommand()
/** Clean up any resources used by the MapRenderer. */
public void close()
{
isReady = false;
//mapPanel.getClientFrame().removePropertyChangeListener(propListener);
}// close()
/** Get the RenderCommandFactory */
public abstract RenderCommandFactory getRenderCommandFactory();
/** Get the MapMetadata object */
//public abstract MapMetadata getMapMetadata();
/** Get the Symbol Name for the given unit type */
public abstract String getSymbolName(Unit.Type unitType);
/** Get a location that corresponds to an ID */
public abstract Location getLocation(String id);
/** Called when an order has been deleted from the order list */
protected abstract void orderDeleted(GUIOrder order);
/** Called when an order has been added to the order list */
protected abstract void orderCreated(GUIOrder order);
/** Called when multiple orders have been deleted from the order list */
protected abstract void multipleOrdersDeleted(GUIOrder[] orders);
/** Called when multiple orders have been added from the order list */
protected abstract void multipleOrdersCreated(GUIOrder[] orders);
/** Called when the displayable powers have changed
* @throws InterruptedException */
protected abstract void displayablePowersChanged(Power[] powers) throws InterruptedException;
/**
* Prevents any enqueued RenderCommands from being executed.
* If a command is currently executing, it is not affected.
* Adds the given commands (or none, if null) to the queue.
* @throws InterruptedException
*/
protected void clearAndExecute(RenderCommand rc1, RenderCommand rc2)
{
Log.println("MR2::clearAndExecute()");
//RunnableQueue rq = getRunnableQueue();
// if(rq != null)
// {
// synchronized(rq.getIteratorLock())
// {
// kill our pending render events
//Iterator iter = rq.iterator();
// while(iter.hasNext())
// {
// Object obj = iter.next();
// if(obj instanceof RenderCommand)
// {
// Log.println(" killing: ", obj);
// ((RenderCommand) obj).die();
// }
// }
// add our new render commands
// NOTE: not sure if this should be in synchronized block.
if(rc1 != null)
{
rc1.execute();
}
if(rc2 != null)
{
rc2.execute();
}
// }
// }
}// clearAndExecute()
/**
* Listener class for order updates and TurnState changes
*
*/
// private class CFPropertyListener extends AbstractCFPListener
// {
// public void actionOrderCreated(Orderable order)
// {
// orderCreated((GUIOrder) order);
// }
//
// public void actionOrderDeleted(Orderable order)
// {
// orderDeleted((GUIOrder) order);
// }
//
// public void actionOrdersCreated(Orderable[] orders)
// {
// GUIOrder[] guiOrders = new GUIOrder[orders.length];
// for(int i=0; i<guiOrders.length; i++)
// {
// guiOrders[i] = (GUIOrder) orders[i];
// }
//
// multipleOrdersCreated(guiOrders);
// }
//
// public void actionOrdersDeleted(Orderable[] orders)
// {
// GUIOrder[] guiOrders = new GUIOrder[orders.length];
// for(int i=0; i<guiOrders.length; i++)
// {
// guiOrders[i] = (GUIOrder) orders[i];
// }
//
// multipleOrdersDeleted(guiOrders);
// }
//
// public void actionDisplayablePowersChanged(Power[] oldPowers, Power[] newPowers)
// {
// displayablePowersChanged(newPowers);
// }
//
// public void actionTurnstateChanged(TurnState ts)
// {
// // OPTIMIZATION:
// // any pending queued events may be deleted, because
// // we are changing the turnstate and doing a complete re-render.
// //
// RenderCommand rc1 =
// getRenderCommandFactory().createRCSetTurnstate(
// MapRenderer2.this, ts);
//
// RenderCommand rc2 =
// getRenderCommandFactory().createRCRenderAll(
// MapRenderer2.this);
//
// clearAndExecute(rc1, rc2);
// }
//
// }// inner class CFPropertyListener
/**
* Returns a Label-Level constant for the given label level.
* Does a case-insensitive compare. Instance equality is preserved.
* Returns the given default if parsing fails.
*/
public static String parseLabelValue(String in, String defaultValue)
{
if(defaultValue != VALUE_LABELS_NONE
&& defaultValue != VALUE_LABELS_FULL
&& defaultValue != VALUE_LABELS_BRIEF
&& defaultValue != null)
{
throw new IllegalArgumentException();
}
if(VALUE_LABELS_NONE.equalsIgnoreCase(in))
{
return VALUE_LABELS_NONE;
}
else if(VALUE_LABELS_BRIEF.equalsIgnoreCase(in))
{
return VALUE_LABELS_BRIEF;
}
else if(VALUE_LABELS_FULL.equalsIgnoreCase(in))
{
return VALUE_LABELS_FULL;
}
return defaultValue;
}// parseLabelValue()
}// abstract class MapRenderer2