// // @(#)MapPanel.java 4/2002 // // Copyright 2002 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.world.Position; import dip.world.Province; import dip.world.TurnState; import dip.world.World; import dip.world.RuleOptions; import dip.world.variant.data.Variant; import dip.world.variant.data.SymbolPack; import dip.gui.ClientFrame; import dip.gui.OrderDisplayPanel; import dip.gui.ClientMenu; import dip.gui.StatusBar; import dip.gui.AbstractCFPListener; import dip.gui.dialog.ErrorDialog; import dip.gui.dialog.prefs.GeneralPreferencePanel; import dip.world.variant.VariantManager; import dip.world.variant.data.MapGraphic; import dip.order.ValidationOptions; import dip.misc.Utils; import dip.misc.Log; import java.util.Date; import java.awt.Cursor; import java.awt.geom.AffineTransform; import java.net.URL; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Dimension; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import javax.swing.JPanel; import javax.swing.*; import org.w3c.dom.svg.SVGDocument; import org.w3c.dom.Document; import org.apache.batik.swing.JSVGCanvas; import org.apache.batik.swing.gvt.GVTTreeRendererAdapter; import org.apache.batik.swing.gvt.GVTTreeRendererEvent; import org.apache.batik.swing.svg.GVTTreeBuilderAdapter; import org.apache.batik.swing.svg.GVTTreeBuilderEvent; import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter; import org.apache.batik.swing.svg.SVGDocumentLoaderEvent; import org.apache.batik.bridge.UpdateManagerListener; import org.apache.batik.bridge.UpdateManagerEvent; import org.apache.batik.util.ParsedURL; import org.apache.batik.dom.svg.SVGOMDocument; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.gvt.*; import java.io.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.batik.dom.svg.*; import org.apache.batik.dom.util.*; import org.apache.batik.util.*; import org.w3c.dom.*; /** * The Main Map display component. * <p> * Takes care of setting up the Batik rendering component, as well as loading * the map (in concert with SymbolInjector) * <p> * This is also the container for the Control Bar. * <p> */ public class MapPanel extends JPanel { // constants // il8n localizers private static final String MP_VARIANT_NOT_FOUND = "MapPanel.error.novariant"; private static final String DOC_LOAD_STARTED = "MapPanel.doc.load.start"; private static final String DOC_LOAD_COMPLETED = "MapPanel.doc.load.complete"; private static final String DOC_LOAD_FAILED = "MapPanel.doc.load.failed"; private static final String GVT_RENDER_STARTED = "MapPanel.gvt.render.start"; private static final String GVT_RENDER_EXTRACTING = "MapPanel.gvt.render.extract"; private static final String GVT_RENDER_COMPLETED = "MapPanel.gvt.render.complete"; private static final String GVT_BUILD_STARTED = "MapPanel.gvt.build.start"; private static final String GVT_BUILD_COMPLETED = "MapPanel.gvt.build.complete"; private static final String GVT_BUILD_FAILED = "MapPanel.gvt.build.failed"; // misc private static final String PSEUDO_ATTRIBUTE_TYPE = "type"; private static final String PSEUDO_ATTRIBUTE_HREF = "href"; private static final String XSL_PROCESSING_INSTRUCTION_TYPE = "text/xsl"; /** update text message */ private static final String updateMessage = Utils.getLocalString("MapPanel.update.text"); /** Default cursor */ public static final Cursor DEFAULT_CURSOR = java.awt.Cursor.getDefaultCursor(); /** Cursor for display when order input is invalid. */ public static final Cursor BAD_ACTION; public static final Cursor CURSOR_DRAG_ARMY; public static final Cursor CURSOR_DRAG_FLEET; public static final Cursor CURSOR_DRAG_WING; public static final Cursor CURSOR_DRAG_ARMY_NO; public static final Cursor CURSOR_DRAG_FLEET_NO; public static final Cursor CURSOR_DRAG_WING_NO; /** Default scale factor */ public static final float DEFAULT_SCALE_FACTOR = 1.2f; // final variables private final ClientFrame clientFrame; private final XJSVGCanvas svgCanvas; protected final StatusBarUtils statusBarUtils; private final StatusBar statusBar; private final XJSVGScroller scroller; // non-final variables private MenuController menuController = null; private MapRenderer2 mapRenderer = null; private Position position = null; private TurnState turnState = null; private World world = null; private MP_PropertyListener propListener = null; private ControlBar controlBar = null; private DOMUIEventListener eventListener = null; private float scaleFactor = DEFAULT_SCALE_FACTOR; private JPanel bottomPanel = null; private MP_UpdateManagerListener uml = null; private boolean isLoaded = false; private boolean isReloading = false; // if we are reloading a map private SymbolPack symbolPack = null; private MP_GVTRenderListener gvtRenderListener = null; private MP_DocumentListener documentListener = null; private MP_GVTTreeBuilderListener treeBuilderListener = null; private Object oldLabelLevel = null; // for timing information protected long startTime = 0L; /** Set Default Cursor */ static { // Attempt to set default cursor. java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit(); Dimension d = tk.getBestCursorSize(32, 32); int colors = tk.getMaximumCursorColors(); // determine if the platform supports custom cursors. if (!d.equals(new Dimension(0, 0)) && (colors != 0)) { ImageIcon ii = Utils.getImageIcon("resource/common/cursors/nodrop.gif"); if(ii == null) { // error loading cursor! just use default cursor. // this may not be the best cursor to use. BAD_ACTION = java.awt.dnd.DragSource.DefaultCopyNoDrop; } else { BAD_ACTION = tk.createCustomCursor(ii.getImage(), new java.awt.Point(16, 16), "custom_nodrop"); } // Drag cursors ii = Utils.getImageIcon("resource/common/cursors/drag_army" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. // this may not be the best cursor to use. CURSOR_DRAG_ARMY = DEFAULT_CURSOR; } else { CURSOR_DRAG_ARMY = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_army"); } ii = Utils.getImageIcon("resource/common/cursors/drag_fleet" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. CURSOR_DRAG_FLEET = DEFAULT_CURSOR; } else { CURSOR_DRAG_FLEET = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_fleet"); } ii = Utils.getImageIcon("resource/common/cursors/drag_wing" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. CURSOR_DRAG_WING = DEFAULT_CURSOR; } else { CURSOR_DRAG_WING = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_wing"); } ii = Utils.getImageIcon("resource/common/cursors/drag_army_no" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. CURSOR_DRAG_ARMY_NO = DEFAULT_CURSOR; } else { CURSOR_DRAG_ARMY_NO = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_army_no"); } ii = Utils.getImageIcon("resource/common/cursors/drag_fleet_no" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. CURSOR_DRAG_FLEET_NO = DEFAULT_CURSOR; } else { CURSOR_DRAG_FLEET_NO = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_fleet_no"); } ii = Utils.getImageIcon("resource/common/cursors/drag_wing_no" + (colors == 2? "_2" : "") + ".gif"); if(ii == null) { // error loading cursor! just use default cursor. CURSOR_DRAG_WING_NO = DEFAULT_CURSOR; } else { CURSOR_DRAG_WING_NO = tk.createCustomCursor(ii.getImage(), new java.awt.Point(5, 5), "cursor_drag_wing_no"); } } else { BAD_ACTION = java.awt.dnd.DragSource.DefaultCopyNoDrop; CURSOR_DRAG_ARMY = DEFAULT_CURSOR; CURSOR_DRAG_ARMY_NO = BAD_ACTION; CURSOR_DRAG_FLEET = DEFAULT_CURSOR; CURSOR_DRAG_FLEET_NO = BAD_ACTION; CURSOR_DRAG_WING = DEFAULT_CURSOR; CURSOR_DRAG_WING_NO = BAD_ACTION; } } /** Creates a MapPanel */ public MapPanel(ClientFrame clientFrame) { super(new BorderLayout()); startTime = System.currentTimeMillis(); Log.printTimed(startTime, "MapPanel() constructor start."); this.clientFrame = clientFrame; this.statusBar = clientFrame.getStatusBar(); this.setMinimumSize(new Dimension(10,10)); // bottomPanel: holds control bar / any other components bottomPanel = new JPanel(new BorderLayout()); this.add(bottomPanel, BorderLayout.SOUTH); // add components to frame that do not depend upon GVT statusBarUtils = new StatusBarUtils(this, clientFrame.getStatusBar()); // setup JSVGCanvas svgCanvas = new XJSVGCanvas(this, statusBar, null, true, false); svgCanvas.setValidating(clientFrame.getValidating()); svgCanvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC); svgCanvas.setRecenterOnResize(false); // batik 1.5.1 svgCanvas.setDoubleBufferedRendering(true); svgCanvas.setProgressivePaint(true); // faster?? svgCanvas.setEnableImageZoomInteractor(true); svgCanvas.setEnableResetTransformInteractor(true); svgCanvas.setEnablePanInteractor(false); svgCanvas.setEnableRotateInteractor(false); // rotation disabled svgCanvas.setParent(this); // send all key events here // setup scroller scroller = new XJSVGScroller(svgCanvas); add(scroller, BorderLayout.CENTER); // setup DOMUIEventListener eventListener = new DOMUIEventListener(); // setup property listener propListener = new MP_PropertyListener(); clientFrame.addPropertyChangeListener(propListener); // setup default controlbar setControlBar(null); Log.printTimed(startTime, "MapPanel() constructor end."); }// MapPanel() /** Set the SVG Document from XML Document */ private void setDocument(Document xmlDoc, Variant variant) { Log.println("MP: setDocument()"); // setup private loader-listeners gvtRenderListener = new MP_GVTRenderListener(); documentListener = new MP_DocumentListener(); treeBuilderListener = new MP_GVTTreeBuilderListener(); svgCanvas.addGVTTreeRendererListener(gvtRenderListener); svgCanvas.addSVGDocumentLoaderListener(documentListener); svgCanvas.addGVTTreeBuilderListener(treeBuilderListener); // setup update listener uml = new MP_UpdateManagerListener(); svgCanvas.addUpdateManagerListener(uml); // load map. Note that this bypasses the DocumentLoader // listener, as it createas an SVG document synchronously // from the XML document we submit. svgCanvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC); // we MUST transform the document, prior to setDocument()! // subtle bugs emerge if we do not. // try { svgCanvas.setDocument( transform(xmlDoc, VariantManager.getVariantPackageJarURL(variant).toString()) ); } catch(Exception e) { ErrorDialog.displaySerious(clientFrame, e); } // fix the URI; if we don't do this, we aren't able to load // files that are referred to by the SVG. For example, the bitmap // for detailed standard map. // if(svgCanvas.getSVGDocument() instanceof SVGOMDocument) { final SVGOMDocument omd = (SVGOMDocument) svgCanvas.getSVGDocument(); omd.setURLObject(VariantManager.getVariantPackageJarURL(variant)); } else { // shouldn't happen. Log.println("ERROR: MapPanel::setDocument(): object model replacement? SVGOMDocument not found. URI not set."); } }// setDocument() /** Get the current Scroller container size */ public Dimension getScrollerSize() { return scroller.getSize(); }// getScrollerSize() /** gets URI of current document */ public String getURI() { return svgCanvas.getURI(); }// getURI() /** Get JSVGCanvas */ public JSVGCanvas getJSVGCanvas() { return svgCanvas; }// getJSVGCanvas() /** Get XJSVGCanvas */ public XJSVGCanvas getXJSVGCanvas() { return svgCanvas; }// getJSVGCanvas() /** Gets the map scale factor (for zooming) */ public float getScaleFactor() { return scaleFactor; }// getScaleFactor() public final ClientFrame getClientFrame() { return clientFrame; }// getClientFrame() /** Convenience method: get the order display panel. */ public OrderDisplayPanel getOrderDisplayPanel() { return clientFrame.getOrderDisplayPanel(); }// getOrderDisplayPanel() /** Convenience method: get the map renderer. */ public MapRenderer2 getMapRenderer() { return mapRenderer; }// getMapRenderer() /** Convenience method: get the MapMetadata object */ public MapMetadata getMapMetadata() { if(getMapRenderer() != null) { return getMapRenderer().getMapMetadata(); } return null; }// getMapMetadata() /** Convenience method: get map renderer command factory class. */ public RenderCommandFactory getRenderCommandFactory() { return mapRenderer.getRenderCommandFactory(); }// getRenderCommandFactory() /** Convenience method: get the status bar */ public StatusBar getStatusBar() { return statusBar; }// getStatusBar() /** Convenience method: get the status bar utility class */ public StatusBarUtils getStatusBarUtils() { return statusBarUtils; }// getStatusBarUtils() /** Convenience method: get the World */ public World getWorld() { return world; }// getWorld() /** DOMUI event hook */ protected void setDOMUIEventListener(DOMUIEventListener domEventListener) { eventListener = domEventListener; }// setDOMUIEventListener() /** DOMUI event hook */ protected DOMUIEventListener getDOMUIEventListener() { return eventListener; }// getDOMUIEventListener() /** Sets View or Order control bar, as appropriate, based on the mode */ private void setControlBar() { Log.println("MP::setControlBar())"); ControlBar cb = null; if(turnState == null) { cb = new ViewControlBar(this); } else { String mode = clientFrame.getMode(); if( mode == ClientFrame.MODE_NONE || mode == ClientFrame.MODE_REVIEW ) { cb = new ViewControlBar(this); } else if(mode == ClientFrame.MODE_ORDER) { cb = new OrderControlBar(this); } else if(mode == ClientFrame.MODE_EDIT) { cb = new EditControlBar(this); } else { throw new IllegalArgumentException("unknown mode"); } } // remove old controlBar, and replace, if not null. setControlBar(cb); }// setControlBar() /** * Explicitly set a ControlBar. * If null, uses the default ControlBar, which has * no buttons and does nothing. */ public void setControlBar(ControlBar cb) { // remove old controlBar, and replace, if not null. if(cb == null) { cb = new EmptyControlBar(this); } if(controlBar != null) { bottomPanel.remove(controlBar); } controlBar = cb; eventListener.setDOMUIEventHandler(controlBar); bottomPanel.add(controlBar, BorderLayout.NORTH); bottomPanel.revalidate(); }// setControlBar() /** Gets the current ControlBar */ public ControlBar getControlBar() { return controlBar; }// getControlBar() /** * Sets the cursor over the JSVGScrollCanvas. * <p> * NOTE: this is currently disabled for OS X due to * weird bugs. */ public void setMapCursor(Cursor cursor) { if(!Utils.isOSX()) { svgCanvas.setCursor(cursor); } }// setCursor() /** Get SVGDocument [may be null!] */ public SVGDocument getSVGDocument() { return svgCanvas.getSVGDocument(); }// getJSVGCanvas() /** Get the current Position */ public Position getPosition() { return position; } /** Get the current TurnState */ public TurnState getTurnState() { return turnState; }// getTurnState() /** Gets the RuleOptions */ public RuleOptions getRuleOptions() { return world.getRuleOptions(); }// getRuleOptions() /** Release any resources held by this component / reset state */ public void close() { try { svgCanvas.flushImageCache(); svgCanvas.setSVGDocument(null); svgCanvas.stopProcessing(); svgCanvas.dispose(); if(uml != null) { svgCanvas.removeUpdateManagerListener(uml); uml.resetText(); uml = null; } if(gvtRenderListener != null) { svgCanvas.removeGVTTreeRendererListener(gvtRenderListener); } if(documentListener != null) { svgCanvas.removeSVGDocumentLoaderListener(documentListener); } if(treeBuilderListener != null) { svgCanvas.removeGVTTreeBuilderListener(treeBuilderListener); } if(menuController != null) { menuController.close(); menuController = null; } if(mapRenderer != null) { mapRenderer.close(); mapRenderer = null; } controlBar = null; eventListener = null; symbolPack = null; world = null; turnState = null; } catch(Exception e) { Log.println("MapPanel::close() exception..."); Log.println(e); } }// close() /** * Convenience method: updates the rendering of a province. * */ public void updateProvince(Province province) { RenderCommand rc = mapRenderer.getRenderCommandFactory().createRCRenderProvince(mapRenderer, province); mapRenderer.execRenderCommand(rc); }// updateProvince() /** Sets which labels are enabled/disabled */ private void setMenuLabelOptions() { MapMetadata mmd = mapRenderer.getMapMetadata(); if(mmd == null) { return; } ClientMenu cm = clientFrame.getClientMenu(); boolean fullLabels = mmd.getDisplayParamBoolean(MapMetadata.ATT_LABELS_FULL, false); boolean briefLabels = mmd.getDisplayParamBoolean(MapMetadata.ATT_LABELS_BRIEF, false); // if no label layers, disable all label support if(!fullLabels && !briefLabels) { cm.setEnabled(ClientMenu.VIEW_NAMES, false); } // disable individual label support cm.setEnabled(ClientMenu.VIEW_NAMES_FULL, fullLabels); cm.setEnabled(ClientMenu.VIEW_NAMES_SHORT, briefLabels); }// setMenuLabelOptions() /** Sets min, max, and scale factor variables from metadata (if found) */ private void setScalingParameters() { MapMetadata mmd = mapRenderer.getMapMetadata(); if(mmd == null) { return; } scaleFactor = mmd.getDisplayParamFloat(MapMetadata.ATT_ZOOM_FACTOR, DEFAULT_SCALE_FACTOR); int minZoom = mmd.getDisplayParamInt(MapMetadata.ATT_ZOOM_MIN, 1); // default minimum: 1% int maxZoom = mmd.getDisplayParamInt(MapMetadata.ATT_ZOOM_MAX, 1600); // default maximum: 1600% // swap values if min/max switched. if(minZoom > maxZoom) { int tmp = minZoom; minZoom = maxZoom; maxZoom = tmp; } svgCanvas.setMinimumScale( ((double)minZoom / 100.0) ); svgCanvas.setMaximumScale( ((double)maxZoom / 100.0) ); }// setScalingParameters() /** * This class sets up object/components that depend upon the canvas/map to * be loaded, and the GVT tree set up. It is to execute only a single time. */ private class MP_GVTRenderListener extends GVTTreeRendererAdapter { private boolean loaded = false; public void gvtRenderingStarted(GVTTreeRendererEvent e) { Log.printTimed(startTime, "MapPanel() GVTRender start."); if(!loaded) { statusBar.incPBValue(); statusBar.setText(Utils.getLocalString(GVT_RENDER_STARTED)); } }// gvtRenderingStarted() public void gvtRenderingCompleted(GVTTreeRendererEvent e) { Log.printTimed(startTime, "MapPanel() GVTRender completing..."); if(!loaded) { statusBar.incPBValue(); statusBar.setText(Utils.getLocalString(GVT_RENDER_EXTRACTING)); // DOM - requring events here try { mapRenderer = new DefaultMapRenderer2(MapPanel.this, symbolPack); } catch(MapException me) { ErrorDialog.displaySerious(clientFrame, me); svgCanvas.stopProcessing(); statusBar.hidePB(); svgCanvas.removeGVTTreeRendererListener(this); statusBar.setText(Utils.getLocalString(DOC_LOAD_FAILED)); return; } // alter menu items depending upon metadata value for labels. clientFrame.getClientMenu().setViewRenderItemsEnabled(true); setMenuLabelOptions(); // configure scaling setScalingParameters(); // add components: menuController = new MenuController(MapPanel.this); if(isReloading) { scroller.reset(); } final RenderCommandFactory rcf = mapRenderer.getRenderCommandFactory(); // add property listener for setting position / turnstate information // and set the current position. // // we do a 'force' if we are reloading RenderCommand rc = rcf.createRCSetTurnstate(mapRenderer, turnState); mapRenderer.execRenderCommand(rc); if(isReloading) { // if we have an old label level set, we'll set the // same for the new map // if(oldLabelLevel != null) { rc = rcf.createRCSetLabel(mapRenderer, oldLabelLevel); mapRenderer.execRenderCommand(rc); } // Because we created a new DMR2, it didn't re-create the // orders, because it thought the 'old' turnstate was null // and the new turnstate won't update, because the orders // think that they are already drawn. // // To fix this, we must destroy the existing orders, and // then re-render them. scroller.revalidate(); rc = ((DMR2RenderCommandFactory) rcf).createRCRenderAllForced(mapRenderer); mapRenderer.execRenderCommand(rc); } else { rc = mapRenderer.getRenderCommandFactory().createRCRenderAll(mapRenderer); mapRenderer.execRenderCommand(rc); // set default label level final String defaultLabelLevel = GeneralPreferencePanel.getMapLabelSetting(); rc = rcf.createRCSetLabel(mapRenderer, defaultLabelLevel); mapRenderer.execRenderCommand(rc); } // set default control bar (View Control Bar) setControlBar(); // set focus //MapPanel.this.requestFocusInWindow(); //svgCanvas.requestFocusInWindow(); controlBar.requestFocusInWindow(); statusBar.setText(Utils.getLocalString(GVT_RENDER_COMPLETED)); //svgCanvas.removeGVTTreeRendererListener(this); statusBar.hidePB(); Log.printTimed(startTime, "MapPanel() GVTRender completed."); } loaded = true; }// gvtRenderingCompleted() }// inner class GVTRenderListener /** * This class sets up object/components that depend upon the DOM * NOTE: we use setDocument(), and thus this really isn't used. */ private class MP_DocumentListener extends SVGDocumentLoaderAdapter { public void documentLoadingStarted(SVGDocumentLoaderEvent e) { Log.printTimed(startTime, "MapPanel() DocumentLoad started."); clientFrame.getClientMenu().setViewRenderItemsEnabled(false); statusBar.incPBValue(); //statusBar.setText(Utils.getLocalString(DOC_LOAD_STARTED)); }// documentLoadingStarted() public void documentLoadingFailed(SVGDocumentLoaderEvent e) { statusBar.setText(Utils.getLocalString(DOC_LOAD_FAILED)); statusBar.hidePB(); }// documentLoadingFailed() public void documentLoadingCompleted(SVGDocumentLoaderEvent e) { Log.printTimed(startTime, "MapPanel() DocumentLoad completed."); statusBar.incPBValue(); statusBar.setText(Utils.getLocalString(DOC_LOAD_COMPLETED)); svgCanvas.removeSVGDocumentLoaderListener(this); }// documentLoadingCompleted() }// inner class GVTRenderListener /** * Statusbar messages */ private class MP_GVTTreeBuilderListener extends GVTTreeBuilderAdapter { public void gvtBuildStarted(GVTTreeBuilderEvent e) { Log.printTimed(startTime, "MapPanel() GVTTreeBuild completed."); statusBar.incPBValue(); statusBar.setText(Utils.getLocalString(GVT_BUILD_STARTED)); }// documentLoadingStarted() public void gvtBuildFailed(GVTTreeBuilderEvent e) { statusBar.setText(Utils.getLocalString(GVT_BUILD_FAILED)); statusBar.hidePB(); }// documentLoadingFailed() public void gvtBuildCompleted(GVTTreeBuilderEvent e) { Log.printTimed(startTime, "MapPanel() GVTTreeBuild completed."); statusBar.incPBValue(); statusBar.setText(Utils.getLocalString(GVT_BUILD_COMPLETED)); svgCanvas.removeGVTTreeBuilderListener(this); }// documentLoadingCompleted() }// inner class MP_GVTTreeBuilderListener /** ClientFrame PropertyChangeListener */ private class MP_PropertyListener extends AbstractCFPListener { public void actionWorldCreated(World w) { if(mapRenderer != null) { throw new IllegalStateException(); } else { world = w; } }// actionWorldCreated() public void actionWorldDestroyed(World w) { if(mapRenderer != null) { close(); } }// actionWorldDestroyed() public void actionValOptsChanged(ValidationOptions options) { if(mapRenderer != null) { // if we have an OrderControl bar or derivitive // update its order validation options if(getControlBar() instanceof OrderControlBar) { ((OrderControlBar) getControlBar()).setValidationOptions(options); } } }// actionValOptsChanged() public void actionModeChanged(String mode) { if(mapRenderer != null) { setControlBar(); statusBar.clearText(); } }// actionModeChanged() public synchronized void actionTurnstateChanged(TurnState ts) { if(mapRenderer != null) { turnState = ts; position = turnState.getPosition(); setControlBar(); statusBar.clearText(); } else { if(!isLoaded) { // set turnstate & position turnState = ts; position = turnState.getPosition(); // load URL and resolve World.VariantInfo vi = world.getVariantInfo(); Variant variant = VariantManager.getVariant( vi.getVariantName(), vi.getVariantVersion() ); // TODO: clean this loading logic up if(variant == null) { Exception e = new IllegalStateException( Utils.getLocalString(MP_VARIANT_NOT_FOUND, "?", "?")); ErrorDialog.displayGeneral(clientFrame, e); } MapGraphic mg = variant.getMapGrapic( vi.getMapName() ); if(mg == null) { // try a default map graphic mg = variant.getDefaultMapGraphic(); if(mg == null) { Exception e = new IllegalStateException( Utils.getLocalString(MP_VARIANT_NOT_FOUND, vi.getVariantName(), vi.getMapName()) ); ErrorDialog.displayGeneral(clientFrame, e); } } URL url = VariantManager.getResource( variant, mg.getURI() ); if(url == null) { Exception e = new IllegalStateException( Utils.getLocalString(MP_VARIANT_NOT_FOUND, vi.getVariantName(), vi.getMapName()) ); ErrorDialog.displayGeneral(clientFrame, e); } symbolPack = VariantManager.getSymbolPack(mg, vi.getSymbolPackName(), vi.getSymbolPackVersion()); // actual loading starts here // // setup progress bar // statusBar.showPB(0, 9); // was 7, may make 8 or 9 statusBar.setText(Utils.getLocalString(DOC_LOAD_STARTED)); try { SymbolInjector si = new SymbolInjector(clientFrame, variant, mg, symbolPack); statusBar.incPBValue(); si.inject(); statusBar.incPBValue(); setDocument( si.getDocument(), variant ); } catch(Exception e) { statusBar.setText(Utils.getLocalString(DOC_LOAD_FAILED)); statusBar.hidePB(); ErrorDialog.displayGeneral(clientFrame, e); } isLoaded = true; } } }// actionTurnstateChanged() }// inner class MP_PropertyListener /** Inner class that indicates in the Status Bar when we are drawing */ private class MP_UpdateManagerListener implements UpdateManagerListener { private String lastModeText = null; public void managerResumed(org.apache.batik.bridge.UpdateManagerEvent e) { } public void managerStarted(org.apache.batik.bridge.UpdateManagerEvent e) { } public void managerStopped(org.apache.batik.bridge.UpdateManagerEvent e) { } public void managerSuspended(org.apache.batik.bridge.UpdateManagerEvent e) { } public void updateCompleted(org.apache.batik.bridge.UpdateManagerEvent e) { resetText(); }// updateCompleted() public void updateFailed(org.apache.batik.bridge.UpdateManagerEvent e) { resetText(); }// updateFailed() public void updateStarted(org.apache.batik.bridge.UpdateManagerEvent e) { lastModeText = statusBar.getModeText(); statusBar.setModeText(updateMessage); }// updateStarted() public void resetText() { // if updateMessage was the last message, we also should clear, otherwise // we are always stuck on updateMessage if(lastModeText == null || lastModeText.equals(updateMessage)) { statusBar.clearModeText(); } else { statusBar.setModeText(lastModeText); } }// resetText() }// inner class MP_UpdateManagerListener /** * Reloads the map, using the map URI as defined in World. * This is most useful if the map URI has changed. */ public void reloadMap() { svgCanvas.flushImageCache(); svgCanvas.suspendProcessing(); // cleanup this if(mapRenderer != null) { oldLabelLevel = mapRenderer.getRenderSetting(MapRenderer2.KEY_LABELS); mapRenderer.close(); mapRenderer = null; } if(uml != null) { svgCanvas.removeUpdateManagerListener(uml); uml.resetText(); uml = null; } if(gvtRenderListener != null) { svgCanvas.removeGVTTreeRendererListener(gvtRenderListener); } if(documentListener != null) { svgCanvas.removeSVGDocumentLoaderListener(documentListener); } if(treeBuilderListener != null) { svgCanvas.removeGVTTreeBuilderListener(treeBuilderListener); } // reload the map assert(turnState != null); svgCanvas.resumeProcessing(); isLoaded = false; isReloading = true; // this activates some additional code clientFrame.fireTurnstateChanged(turnState); }// reloadMap() /** * This code is based on: <br> * http://cvs.apache.org/viewcvs.cgi/xml-batik/sources/org/apache/batik/apps/svgbrowser/XMLInputHandler.java?rev=1.7&view=auto * <p> * Essentially, it fixes the namespaces so that resolving URIs to * the variant-pack jar's actually works. This fixes bug #900714. * */ private Document transform(final Document inDoc, final String uri) throws TransformerException, TransformerConfigurationException, IOException { TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); // Now, apply the transformation to the input document. // // <!> Due to issues with namespaces, the transform creates the // result in a stream which is parsed. This is sub-optimal // but this was the only solution found to be able to // generate content in the proper namespaces. // // SVGOMDocument outDoc = // (SVGOMDocument)impl.createDocument(svgNS, "svg", null); // outDoc.setURLObject(new URL(uri)); // transformer.transform // (new DOMSource(inDoc), // new DOMResult(outDoc.getDocumentElement())); // StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); transformer.transform(new DOMSource(inDoc), result); sw.flush(); sw.close(); String parser = XMLResourceDescriptor.getXMLParserClassName(); SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); SVGDocument outDoc = f.createSVGDocument(uri, new StringReader(sw.toString())); return outDoc; } }// class MapPanel