/* * GeoTreeRoot.java * * Created on April 17, 2007, 3:44 PM * */ package ika.geo; import ika.gui.PageFormat; import ika.gui.PageFormatChangeListener; import ika.utils.Serializer; import java.awt.Color; import java.awt.geom.Rectangle2D; /** * GeoTreeRoot has three GeoSets: background, main, and foreground. * Usually the mainGeoSet is edited by the application, the foreground and the * background serve as container for supplemental data. * GeoTreeRoot also has a reference to a PageFormat that determines the size * and position of the map document. * @author Bernhard Jenny, Institute of Cartography, ETH Zurich. */ public class GeoTreeRoot extends GeoSetBroadcaster implements PageFormatChangeListener, MapEventListener{ /** * A GeoSet containing additional information that is drawn, but cannot * usually be manipulated by the user. The data contained by backgroundGeoSet * is not exported by GeoSetExporters. It can be used for a background * raster grid or other usually non-manipulatable graphics. */ private GeoSet backgroundGeoSet = null; /** * The main GeoSet that is displayed by this MapComponent and exported by * GeoExporters. */ private GeoSet mainGeoSet = null; /** * A GeoSet containing additional GeoObjects that are displayed in front of * the backgroundGeoSet and the mainGeoSet, e.g. the page outline. * This GeoSet is not exported by GeoSetExporters. */ private GeoSet foregroundGeoSet = null; /** * The size, position and scale of the page. */ private PageFormat pageFormat = new PageFormat(); /** * The outline of the page that will be added to the map. */ transient private GeoPath pageFormatOutline = new GeoPath(); /** Creates a new instance of GeoTreeRoot */ public GeoTreeRoot() { this.setName("root"); this.mainGeoSet = new GeoSet(); this.mainGeoSet.setName("main"); this.backgroundGeoSet = new GeoSet(); this.backgroundGeoSet.setName("background"); this.foregroundGeoSet = new GeoSet(); this.foregroundGeoSet.setName("foreground"); this.add(this.backgroundGeoSet); this.add(this.mainGeoSet); this.add(this.foregroundGeoSet); // setup the page outline VectorSymbol vs = new VectorSymbol(null, Color.GRAY, 0); vs.setScaleInvariant(true); this.pageFormatOutline.setVectorSymbol(vs); this.foregroundGeoSet.add(this.pageFormatOutline); this.pageFormatOutline.setName("page outline"); this.updatePageFormatOutline(); // register this as a MapEventListener that updates the page format // whenever the map content changes, if the page format is automatic. this.addMapEventListener(this); // register this as a listener for page format changes to update the // page outline represented in the map this.pageFormat.addPageFormatChangeListener(this); } public byte[][] serializeModel() throws java.io.IOException { // serialize the backgroundGeoSet, the mainGeoSet and the foregroundGeoSet. byte[] b = Serializer.serialize(this.backgroundGeoSet, true); byte[] m = Serializer.serialize(this.mainGeoSet, true); byte[] f = Serializer.serialize(this.foregroundGeoSet, true); byte[] pf = Serializer.serialize(this.pageFormat, true); return new byte[][] {b, m, f, pf}; } public void deserializeModel(byte[][] data) throws java.lang.ClassNotFoundException, java.io.IOException { Object b = Serializer.deserialize(data[0], true); Object m = Serializer.deserialize(data[1], true); Object f = Serializer.deserialize(data[2], true); Object pf = Serializer.deserialize(data[3], true); this.setBackgroundGeoSet((GeoSet)b); this.setMainGeoSet((GeoSet)m); this.setForegroundGeoSet((GeoSet)f); this.pageFormat = (PageFormat)pf; this.pageFormat.addPageFormatChangeListener(this); this.updatePageFormatOutline(); } public GeoSet getMainGeoSet() { return this.mainGeoSet; } public void setMainGeoSet(GeoSet newMainGeoSet) { if (newMainGeoSet != null) { GeoSet oldMainGeoSet = this.mainGeoSet; // replaceGeoObject() will trigger a MapEvent. An event listener may // access this.mainGeoSet. Therefore replace this.mainGeoSet before // calling replaceGeoObject(). this.mainGeoSet = newMainGeoSet; this.replaceGeoObject(newMainGeoSet, oldMainGeoSet); } } public GeoSet getBackgroundGeoSet() { return backgroundGeoSet; } public void setBackgroundGeoSet(GeoSet geoSet) { if (geoSet != null) this.backgroundGeoSet = geoSet; } public GeoSet getForegroundGeoSet() { return foregroundGeoSet; } public void setForegroundGeoSet(GeoSet geoSet) { if (geoSet != null) { this.foregroundGeoSet = geoSet; } } /** * Returns this GeoTreeRoot. Overwrites getRoot() of GeoObject which * traverses the tree of GeoObject in upwards direction. This call is the * last one in the chain. * * @return The GeoTreeRoot of the tree. This is the topmost Geoset. */ @Override public GeoTreeRoot getRoot() { return this; } public PageFormat getPageFormat() { return pageFormat; } private void updatePageFormatOutline() { if (this.pageFormat == null) { this.pageFormatOutline.setVisible(false); return; } final boolean oldVisibility = this.pageFormatOutline.isVisible(); final boolean newVisibility = this.pageFormat.isVisible(); MapEventTrigger trigger = new MapEventTrigger(this); try { Rectangle2D outline = pageFormat.getPageSizeWorldCoordinates(); pageFormatOutline.rectangle(outline); pageFormatOutline.setVisible(newVisibility); } finally { if (oldVisibility != newVisibility) { trigger.inform(); } else { trigger.abort(); } } } /** * Implement the PageFormatChangeListener interface. Update the outline of * the page format when the page format changes. */ public void pageFormatChanged(PageFormat pageFormat) { updatePageFormatOutline(); } /** * Implement the MapEventListener interface. * Update the page format when the content of the map changes and if the * page format is set to automatic updating. */ public void mapEvent(MapEvent evt) { if (pageFormat == null || !pageFormat.isAutomatic()) { return; } Rectangle2D bounds = mainGeoSet.getBounds2D(GeoObject.UNDEFINED_SCALE); pageFormat.setPageWorldCoordinates(bounds); } }