예제 #1
0
  /**
   * This main function basically reads in the data sources (the shape file and the csv information
   * file, and creates a serialized graphics file that will act like a cache later.
   */
  public static void main(String[] argv) {
    String propertiesFile = null;
    String prefix = null;
    String outputFile = null;

    Debug.init();

    if (argv.length < 6) printUsage();

    for (int i = 0; i < argv.length; i++) {
      if (argv[i].equalsIgnoreCase("-props")) {
        propertiesFile = argv[++i];
      } else if (argv[i].equalsIgnoreCase("-prefix")) {
        prefix = argv[++i];
      } else if (argv[i].equalsIgnoreCase("-file")) {
        outputFile = argv[++i];
      }
    }

    if (propertiesFile == null || prefix == null || outputFile == null) {
      printUsage();
    }

    try {
      Properties properties = new Properties();
      // Read in the properties.
      URL propertiesURL = new URL(propertiesFile);
      InputStream is = propertiesURL.openStream();
      properties.load(is);

      // Let's make a file
      ShapeLayer sl = new ShapeLayer();
      sl.setProperties(prefix, properties);

      AreaHandler ah = new AreaHandler(sl.getSpatialIndex(), sl.getDrawingAttributes());

      // Set the properties in the handler.
      ah.setProperties(prefix, properties);
      // Write the saved graphics.
      ah.getGraphics().writeGraphics(outputFile);

    } catch (java.net.MalformedURLException murle) {
      Debug.error("Bad URL for properties file : " + propertiesFile);
      printUsage();
    } catch (java.io.IOException ioe) {
      Debug.error("IOException creating cached graphics file: " + outputFile);
      printUsage();
    }
  }
예제 #2
0
  /**
   * Method to set the properties in the PropertyConsumer. The prefix is a string that should be
   * prepended to each property key (in addition to a separating '.') in order for the
   * PropertyConsumer to uniquely identify properties meant for it, in the midst of Properties meant
   * for several objects.
   *
   * @param prefix a String used by the PropertyConsumer to prepend to each property value it wants
   *     to look up - setList.getProperty(prefix.propertyKey). If the prefix had already been set,
   *     then the prefix passed in should replace that previous value.
   * @param setList a Properties object that the PropertyConsumer can use to retrieve expected
   *     properties it can use for configuration.
   */
  public void setProperties(String prefix, Properties setList) {
    super.setProperties(prefix, setList);
    prefix = PropUtils.getScopedPropertyPrefix(prefix);

    wmsServer = setList.getProperty(prefix + WMSServerProperty);
    if (wmsServer == null) {
      Debug.error("WMSPlugIn needs a WMS server.");
    }

    queryHeader = wmsServer;

    setImageFormat(setList.getProperty(prefix + ImageFormatProperty, getImageFormat()));

    setTransparent(setList.getProperty(prefix + TransparentProperty, getTransparent()));

    setBackgroundColor(setList.getProperty(prefix + BackgroundColorProperty, getBackgroundColor()));

    setWmsVersion(setList.getProperty(prefix + WMSVersionProperty, getWmsVersion()));

    layers = setList.getProperty(prefix + LayersProperty);
    styles = setList.getProperty(prefix + StylesProperty);

    /** Include for vendor specific parameters */
    setVendorSpecificNames(
        setList.getProperty(prefix + VendorSpecificNamesProperty, getVendorSpecificNames()));
    setVendorSpecificValues(
        setList.getProperty(prefix + VendorSpecificValuesProperty, getVendorSpecificValues()));
  } // end setProperties
예제 #3
0
  /** Write an OMPoint to the Link. */
  public static void write(OMPoint point, Link link, LinkProperties props) throws IOException {

    props.setProperty(LinkPoint.LPC_POINT_OVAL, point.isOval() ? "true" : "false");
    switch (point.getRenderType()) {
      case OMPoint.RENDERTYPE_LATLON:
        LinkPoint.write(
            (float) point.getLat(), (float) point.getLon(), point.getRadius(), props, link.dos);
        break;
      case OMPoint.RENDERTYPE_XY:
        LinkPoint.write(point.getX(), point.getY(), point.getRadius(), props, link.dos);
        break;
      case OMPoint.RENDERTYPE_OFFSET:
        LinkPoint.write(
            (float) point.getLat(),
            (float) point.getLon(),
            point.getX(),
            point.getY(),
            point.getRadius(),
            props,
            link.dos);
        break;
      default:
        Debug.error("LinkPoint.write: point rendertype unknown.");
    }
  }
예제 #4
0
  public void actionPerformed(ActionEvent ae) {
    if (map != null) {
      Proj proj = (Proj) map.getProjection();
      DataBounds bounds = provider.getDataBounds();

      if (bounds != null) {
        java.awt.geom.Point2D center = bounds.getCenter();
        if (center != null) {
          proj.setCenter((float) center.getY(), (float) center.getX());
          LatLonPoint llp1 = new LatLonPoint(bounds.getMax().getY(), bounds.getMin().getX());

          LatLonPoint llp2 = new LatLonPoint(bounds.getMin().getY(), bounds.getMax().getX());

          // 1.1 buffers the edges for viewing a little, a
          // little zommed out.
          proj.setScale(ProjMath.getScale(llp1, llp2, proj) * 1.1f);
          map.setProjection(proj);
        }
      } else {
        String complaint =
            "Can't move map over data: " + provider.getName() + " isn't ready.  Add to map?";
        if (infoDelegator != null) {
          infoDelegator.displayMessage("Go Over Data", complaint);
        } else {
          Debug.error(complaint);
        }
      }
    }
  }
예제 #5
0
  /** Get all the graphics from the shapefile, colored appropriately. */
  public OMGraphicList getGraphics() {
    if (omgraphics == null) {
      omgraphics = new OMGraphicList();
      try {
        spatialIndex.getOMGraphics(
            -180, -90, 180, 90, omgraphics, drawingAttributes, (Projection) null, coordTransform);

        updateDrawingParameters(omgraphics);

      } catch (IOException ioe) {
        Debug.error(ioe.getMessage());
      } catch (FormatException fe) {
        Debug.error(fe.getMessage());
      }
    }
    return omgraphics;
  }
예제 #6
0
 /**
  * OK, we can't assume that we are assigning a string as a key, you might want to key in on a
  * specific attribute that is a number, like the country coloring code that ESRI has in the
  * country file. We're going to assume that if the number has an integer value, it shouldn't have
  * decimal places. That is, a 1.0 will be truncated to 1, because that makes more sense in a data
  * file where you are using a key as a factor. If the double value doesn't match the integer
  * value, though, we'll assume that's what was meant and leave it alone.
  *
  * <p>
  */
 protected String createStringFromKeyObject(Object keyObj) {
   String key = null;
   if (keyObj instanceof String) {
     key = ((String) keyObj).toUpperCase().intern();
   } else if (keyObj instanceof Number) {
     Number keyNum = (Number) keyObj;
     if (keyNum.doubleValue() == (double) keyNum.intValue()) {
       // Strips off empty decimal places, for sure
       key = Integer.toString(keyNum.intValue()).intern();
     } else {
       key = Double.toString(keyNum.doubleValue()).intern();
     }
   } else {
     try {
       key = keyObj.toString().toUpperCase().intern();
     } catch (Exception e) {
       Debug.error("AreaHandler.createStringFromKeyObject: bad key object:" + keyObj);
     }
   }
   return key;
 }
예제 #7
0
  /**
   * Find a PoliticalArea named by the search key. If the shapefile is large, the first query will
   * take a little extra time on the first query to read in the files.
   *
   * @param area_key the lookup key, of which the index for the column was designated in the
   *     properties file.
   */
  public PoliticalArea findPoliticalArea(String area_key) {

    // Right now, this method gathers all the graphics in the
    // shape file, groups them, and then returns the PoliticalArea
    // for the key. In the future, it would be nice to have the
    // option to actually search through the data file, find the
    // indexes of the graphics that go to the area, and assemble a
    // temporary list to pass back.

    if (politicalAreas == null) {
      Debug.message("areas", "AreaHandler: initializing graphic attributes");
      initialize(originalPrefix, originalProperties);

      if (omgraphics == null) {
        omgraphics = getGraphics();
        if (dbfModel != null) loadDbfModelIntoGraphics(omgraphics);
        else infoFile.loadIntoGraphics(omgraphics);
      }

      politicalAreas = determinePoliticalAreas(omgraphics);
      Debug.message("areas", "AreaHandler: completed initialization");
    }

    if (politicalAreas != null) {
      String key = area_key.toUpperCase().intern(); // Just to
      // be sure.

      return (PoliticalArea) politicalAreas.get(key);
    } else {
      Debug.error(
          "AreaHandler: initialization failed for "
              + originalPrefix
              + "\n\tNo data will be displayed");
      return null;
    }
  }
예제 #8
0
  /**
   * Prepare the spline for rendering.
   *
   * @see com.bbn.openmap.omGraphics.OMGeometry#generate(Projection)
   * @param proj Projection
   * @return true if generate was successful
   */
  public boolean generate(Projection proj) {

    setNeedToRegenerate(true);

    if (proj == null) {
      Debug.message("omspline", "OMSpline: null projection in generate!");
      return false;
    }

    NatCubicSpline spline = isGeometryClosed() ? natCubicClosed : natCubic;
    // HACK : should use something else than nsegs
    spline.setSteps(nsegs);

    float[][] splinePoints;

    switch (renderType) {
      case RENDERTYPE_XY:
        if (xs == null) {
          Debug.message("omspline", "OMSpline x/y rendertype null coordinates");
          setNeedToRegenerate(true);
          return false;
        }

        splinePoints = spline.calc(xs, ys);
        xpoints = new float[1][0];
        xpoints[0] = splinePoints[0];
        ypoints = new float[1][0];
        ypoints[0] = splinePoints[1];

        break;

      case RENDERTYPE_OFFSET:
        if (xs == null) {
          Debug.message("omspline", "OMSpline offset rendertype null coordinates");
          setNeedToRegenerate(true);
          return false;
        }

        int npts = xs.length;
        float[] _x = new float[npts];
        float[] _y = new float[npts];

        // forward project the radian point
        Point origin = new Point();
        if (proj instanceof GeoProj) {
          ((GeoProj) proj).forward(lat, lon, origin, true); // radians
        } else {
          proj.forward(Math.toDegrees(lat), Math.toDegrees(lon), origin);
        }

        if (coordMode == COORDMODE_ORIGIN) {
          for (int i = 0; i < npts; i++) {
            _x[i] = (float) (xs[i] + origin.getX());
            _y[i] = (float) (ys[i] + origin.getY());
          }
        } else { // CModePrevious offset deltas
          _x[0] = xs[0] + origin.x;
          _y[0] = ys[0] + origin.y;

          for (int i = 1; i < npts; i++) {
            _x[i] = xs[i] + _x[i - 1];
            _y[i] = ys[i] + _y[i - 1];
          }
        }

        splinePoints = spline.calc(_x, _y);

        xpoints = new float[1][0];
        xpoints[0] = splinePoints[0];
        ypoints = new float[1][0];
        ypoints[0] = splinePoints[1];

        break;

      case RENDERTYPE_LATLON:
        if (rawllpts == null) {
          Debug.message("omspline", "OMSpline latlon rendertype null coordinates");
          setNeedToRegenerate(true);
          return false;
        }

        // spline creation ; precision 1e-8 rad = 0.002"
        double[] splinellpts = spline.calc(rawllpts, 1e-8f);

        // polygon/polyline project the polygon/polyline.
        // Vertices should already be in radians.
        ArrayList<float[]> vector;
        if (proj instanceof GeoProj) {
          vector = ((GeoProj) proj).forwardPoly(splinellpts, lineType, nsegs, isPolygon);
        } else {
          vector = proj.forwardPoly(rawllpts, isPolygon);
        }
        int size = vector.size();

        xpoints = new float[(int) (size / 2)][0];
        ypoints = new float[xpoints.length][0];

        for (int i = 0, j = 0; i < size; i += 2, j++) {
          xpoints[j] = vector.get(i);
          ypoints[j] = vector.get(i + 1);
        }

        if (!doShapes && size > 1) {
          setNeedToRegenerate(false);
          initLabelingDuringGenerate();
          setLabelLocation(xpoints[0], ypoints[0]);
          return true;
        }

        break;

      case RENDERTYPE_UNKNOWN:
        Debug.error("OMSpline.generate: invalid RenderType");
        return false;
    }

    setNeedToRegenerate(false);
    setShape(createShape());
    setLabelLocation(getShape(), proj);
    return true;
  }
예제 #9
0
  /**
   * DeterminePoliticalAreas goes over a list of omgraphics, and spits out a hashtable that holds
   * PoliticalArea objects for every area key. When an ID is found in the graphics, it is checked in
   * the hashtable for like graphics, and added to that PoliticalArea if found. If not found, a new
   * PoliticalArea is created and placed in the Hashtable. This will duplicate graphics if you call
   * it more than once for the same graphic list.
   *
   * @param graphicList the list of graphics. The top level graphic entries on the list represent
   *     areas.
   */
  public Hashtable determinePoliticalAreas(OMGraphicList graphicList, Hashtable poli_areas) {

    // Simple case. No graphics means an empty list of regions.
    String name = null;
    String key = null;

    if (graphicList != null) {
      int size = graphicList.size();
      for (int i = 0; i < size; i++) {
        OMGraphic graphic = graphicList.getOMGraphicAt(i);
        // below should be a vector like [ "Massachusetts",
        // "MA" ];

        Object obj = graphic.getAttribute(ShapeConstants.SHAPE_DBF_INFO_ATTRIBUTE);
        if (obj == null) {
          if (Debug.debugging("areas")) {
            Debug.error("AreaHandler: No attributes for graphic #" + i);
          }
          continue;
        }

        if (obj instanceof Vector) {
          Vector pair = (Vector) obj;

          name = (String) pair.elementAt(nameIndex);
          key = ((String) pair.elementAt(keyIndex)).toUpperCase().intern();
          if (Debug.debugging("areas")) {
            Debug.output("AreaHandler: looking at " + name + ", " + key);
          }
        } else if (obj instanceof String) {
          // Assume that the key is stored here, I guess.
          key = (String) obj;
          if (Debug.debugging("areas")) {
            Debug.output("AreaHandler: String app object, looking at " + key);
          }
        } else {
          if (Debug.debugging("areas")) {
            Debug.output("AreaHandler: Unidentified app object type " + obj);
          }
        }

        // Get the political area object for this keyiation.
        PoliticalArea area = (PoliticalArea) poli_areas.get(key);

        if (area == null) { // key is not in table
          area = new PoliticalArea(name, key);
          poli_areas.put(key, area); // add it to the table
          // AreaDrawParams adp =
          // (AreaDrawParams)drawingParams.get(key);
          // if (adp != null) {
          // area.setDrawingAttributes(adp.drawingAttributes);
          // }
        }

        // Add the graphic to the list for this political
        // area.
        area.addGraphic(graphic);
      }

      if (Debug.debugging("areas")) {
        Debug.output(
            "AreaHandler: Finished determinePoliticalAreas: "
                + poli_areas.size()
                + " areas defined.");
      }
    }

    return poli_areas;
  }
예제 #10
0
  /**
   * Go through the properties, loading the shapefile, information file and attributes files, and
   * resolve how everything should be drawn. Might take awhile if the files are large. Called from
   * getRectangle, which is called when the AreaShapeLayer is added to the map.
   *
   * @param prefix property file entry header name
   * @param props the properties to look through.
   */
  public void initialize(String prefix, Properties props) {

    if (props == null) {
      Debug.error(
          "AreaHandler: initialize received bad input:\n\tprefix: "
              + prefix
              + "\n\tproperties: "
              + (props == null ? "null" : "OK"));
      politicalAreas = null;
      return;
    }

    prefix = PropUtils.getScopedPropertyPrefix(prefix);

    politicalAreas = new Hashtable();

    // OK, Get the graphics. We are not expecting that all the
    // graphics in the file are not too much to handle. Also, we
    // test for the serialized graphics file first, and if it
    // isn't designated, then look for a shapefile and spatial
    // index file to create an OMGraphicsList.
    String cacheFile = props.getProperty(prefix + CacheFileProperty);

    // First find the resource, if not, then try as a file-URL...
    try {
      cacheURL = PropUtils.getResourceOrFileOrURL(this, cacheFile);

      if (cacheURL != null) {
        omgraphics = readCachedGraphics(cacheURL);
      } else {
        // We'll use the spatial index set from the
        // ShapeLayer.

        // Now, get the attribute file
        String dbfFile = props.getProperty(prefix + dbfFileProperty);
        URL dbfFileURL = null;
        if (dbfFile != null) {
          dbfFileURL = PropUtils.getResourceOrFileOrURL(this, dbfFile);
        }
        if (dbfFileURL != null) {
          InputStream is = dbfFileURL.openStream();
          dbfModel = new DbfTableModel(new DbfInputStream(is));
        }
        if (dbfModel == null) {
          String csvFile = props.getProperty(prefix + csvFileProperty);
          URL infofileURL = null;
          if (csvFile != null) {
            infofileURL = PropUtils.getResourceOrFileOrURL(this, csvFile);
          }

          // Read them in.
          if (infofileURL != null) {
            infoFile = new CSVShapeInfoFile(csvFile);
            infoFile.setHeadersExist(
                PropUtils.booleanFromProperties(props, prefix + csvHeaderProperty, true));
            infoFile.loadData(true);
          }
        }
      }
    } catch (java.net.MalformedURLException murle) {
      omgraphics = new OMGraphicList();
    } catch (java.io.IOException ioe) {
      omgraphics = new OMGraphicList();
    } catch (Exception exc) {
      omgraphics = new OMGraphicList();
    }

    // This is handled properly yet. The PoliticalArea should be
    // updated to handle URLs for area points, and have different
    // icons for different areas.
    // String defaultPointImageURLString =
    // props.getProperty(prefix + pointImageURLProperty);

    // Now, match the attributes to the graphics. Find the
    // indexes of the name and the search key. Also figure out
    // which areas have special coloring needs.
    keyIndex = PropUtils.intFromProperties(props, prefix + keyIndexProperty, keyIndex);
    nameIndex = PropUtils.intFromProperties(props, prefix + nameIndexProperty, nameIndex);
    String areas = props.getProperty(prefix + areasProperty);

    if (areas == null) areas = "";

    StringTokenizer tokenizer = new StringTokenizer(areas, " ");
    // All this uses the properties to set the individual colors
    // of any area
    String currentArea;

    while (tokenizer.hasMoreTokens()) {
      currentArea = tokenizer.nextToken();

      PoliticalArea newParams = new PoliticalArea(currentArea);

      if (Debug.debugging("areas")) {
        Debug.output("AreaHandler: setting SPECIALIZED attributes for \"" + newParams.id + "\"");
      }

      areasItems.addElement(currentArea);

      newParams.drawingAttributes =
          new DrawingAttributes(prefix + areasProperty + "." + currentArea, props);

      politicalAreas.put(newParams.id.toUpperCase().intern(), newParams);
    }

    if (Debug.debugging("areas")) {
      Debug.output("AreaHandler: finished initialization");
    }
  }
예제 #11
0
  /**
   * Prepares the graphics for the layer. This is where the getRectangle() method call is made on
   * the dted.
   *
   * <p>Occasionally it is necessary to abort a prepare call. When this happens, the map will set
   * the cancel bit in the LayerThread, (the thread that is running the prepare). If this Layer
   * needs to do any cleanups during the abort, it should do so, but return out of the prepare asap.
   */
  public synchronized OMGraphicList prepare() {

    if (isCancelled()) {
      Debug.message("dted", getName() + "|DTEDLayer.prepare(): aborted.");
      return null;
    }

    Projection projection = getProjection();

    if (projection == null) {
      Debug.error("DTED Layer needs to be added to the MapBean before it can draw images!");
      return new OMGraphicList();
    }

    DTEDCacheManager cache = getCache();

    if (!(projection instanceof EqualArc)) {
      // fireRequestInfoLine("DTED works faster with an Equal Arc projection (CADRG/LLXY).");
    }

    Debug.message("basic", getName() + "|DTEDLayer.prepare(): doing it");

    // Setting the OMGraphicsList for this layer. Remember, the
    // OMGraphicList is made up of OMGraphics, which are generated
    // (projected) when the graphics are added to the list. So,
    // after this call, the list is ready for painting.

    // call getRectangle();
    if (Debug.debugging("dted")) {
      Debug.output(
          getName()
              + "|DTEDLayer.prepare(): "
              + "calling getRectangle "
              + " with projection: "
              + projection
              + " ul = "
              + projection.getUpperLeft()
              + " lr = "
              + projection.getLowerRight());
    }

    OMGraphicList omGraphicList;

    if (projection.getScale() < maxScale) {
      omGraphicList = cache.getRectangle(projection);
    } else {
      fireRequestInfoLine("  The scale is too small for DTED viewing.");
      Debug.error(
          "DTEDLayer: scale (1:"
              + projection.getScale()
              + ") is smaller than minimum (1:"
              + maxScale
              + ") allowed.");
      omGraphicList = new OMGraphicList();
    }
    // ///////////////////
    // safe quit
    int size = 0;
    if (omGraphicList != null) {
      size = omGraphicList.size();
      Debug.message(
          "basic", getName() + "|DTEDLayer.prepare(): finished with " + size + " graphics");

      // // Don't forget to project them. Since they are only
      // // being recalled if the projection has changed, then we
      // // need to force a reprojection of all of them because the
      // // screen position has changed.
      // omGraphicList.project(projection, true);

    } else {
      Debug.message("basic", getName() + "|DTEDLayer.prepare(): finished with null graphics list");
    }

    return omGraphicList;
  }
예제 #12
0
  /**
   * Given a couple of points representing a bounding box, find out what the scale should be in
   * order to make those points appear at the corners of the projection.
   *
   * @param ll1 the upper left coordinates of the bounding box.
   * @param ll2 the lower right coordinates of the bounding box.
   * @param point1 a Point2D reflecting a pixel spot on the projection that matches the ll1
   *     coordinate, the upper left corner of the area of interest.
   * @param point2 a Point2D reflecting a pixel spot on the projection that matches the ll2
   *     coordinate, usually the lower right corner of the area of interest.
   * @param recursiveCount a protective count to keep this method from getting in a recursive death
   *     spiral.
   */
  private float getScale(
      Point2D ll1, Point2D ll2, Point2D point1, Point2D point2, int recursiveCount) {

    try {

      double deltaDegrees;
      double pixPerDegree;
      int deltaPix;
      double ret;
      double dx = Math.abs(point2.getX() - point1.getX());
      double dy = Math.abs(point2.getY() - point1.getY());

      double nCenterLat = Math.min(ll1.getY(), ll2.getY()) + Math.abs(ll1.getY() - ll2.getY()) / 2;
      double nCenterLon = Math.min(ll1.getX(), ll2.getX()) + Math.abs(ll1.getX() - ll2.getX()) / 2;

      if (dx < dy) {
        double dlat = Math.abs(ll1.getX() - ll2.getY());
        deltaDegrees = dlat;
        deltaPix = getHeight();
        pixPerDegree = getScale() * getYPixConstant() / 90;
      } else {
        double dlon;
        double lat1, lon1, lon2;

        // point1 is to the right of point2. switch the
        // LatLonPoints so that ll1 is west (left) of ll2.
        if (point1.getX() > point2.getX()) {
          lat1 = ll1.getY();
          lon1 = ll1.getX();
          ll1.setLocation(ll2);
          // Remember for setLocation the order of args is reversed
          ll2.setLocation(lon1, lat1);
        }

        lon1 = ll1.getX();
        lon2 = ll2.getX();

        // allow for crossing dateline
        if (lon1 > lon2) {
          dlon = (180 - lon1) + (180 + lon2);
        } else {
          dlon = lon2 - lon1;
        }

        deltaDegrees = dlon;
        deltaPix = getWidth();
        pixPerDegree = getPlanetPixelCircumference() / 360;
      }

      // The new scale...
      ret = pixPerDegree / (deltaPix / deltaDegrees);

      // OK, now given the new scale at the apparent new center
      // location, we need to test if the zone changes, because
      // if it does, the values don't work out right because the
      // pixel spacings are different. If the zones are
      // different, we need to recalculate the scale based on
      // the
      // new zone.
      CADRG newcadrg =
          new CADRG(
              new LatLonPoint.Double(nCenterLat, nCenterLon), (float) ret, getWidth(), getHeight());

      // Use the recursiveCount to prevent extended recalls. A
      // couple rounds should suffice.
      if (newcadrg.getZone() != zone && recursiveCount < 2) {
        ret =
            newcadrg.getScale(
                ll1, ll2, newcadrg.forward(ll1), newcadrg.forward(ll2), recursiveCount + 1);
      }

      return (float) ret;
    } catch (NullPointerException npe) {
      Debug.error("ProjMath.getScale(): caught null pointer exception.");
      return Float.MAX_VALUE;
    }
  }
예제 #13
0
  public void actionPerformed(ActionEvent ae) {
    Debug.message("saveimage", "SaveAsImageMenuItem: actionPerformed");

    if (mapHandler == null) {
      Debug.output("SaveAsImageMenuItem: mapHandler = null, returning");
      return;
    }

    MapBean mb = (MapBean) mapHandler.get("com.bbn.openmap.MapBean");

    if (mb != null) {
      Debug.message("saveimage", "MapBean found, creating image");
      try {

        while (true) {
          SaveAsImageFileChooser chooser =
              new SaveAsImageFileChooser(mb.getWidth(), mb.getHeight());

          int returnVal = chooser.showSaveDialog(getParent());
          if (returnVal == JFileChooser.APPROVE_OPTION) {
            String filename = chooser.getSelectedFile().getAbsolutePath();
            if (formatter == null) {
              break;
            }

            filename = checkFileName(filename, formatter.getFormatLabel().toLowerCase());
            if (filename == null) {
              // This is the reason for the while
              // loop, the name didn't really pass
              // muster, so we'll try again.
              continue;
            }

            int imageHeight = chooser.getImageHeight();
            int imageWidth = chooser.getImageWidth();

            byte[] imageBytes = formatter.getImageFromMapBean(mb, imageWidth, imageHeight);
            FileOutputStream binFile = new FileOutputStream(filename);
            binFile.write(imageBytes);
            binFile.close();
            if (Debug.debugging("saveimage")) {
              com.bbn.openmap.proj.Projection proj = mb.getProjection();
              Debug.output(
                  "Created image at "
                      + filename
                      + "where projection covers "
                      + proj.getUpperLeft()
                      + " to "
                      + proj.getLowerRight());
            }
            break;
          } else if (returnVal == JFileChooser.CANCEL_OPTION) {
            break;
          }
        }
      } catch (IOException e) {
        Debug.error("SaveAsImageMenuItem: " + e);
      }
    }
    return;
  }