/**
   * Store this Projection in the data table
   *
   * @param proj the Projection to store
   */
  public void saveProjection(ProjectionImpl proj) {
    // setVisible(true);  how to make this work? seperate Thread ?

    // force new name
    ProjectionImpl newProj = (ProjectionImpl) proj.constructCopy();
    newProj.setName("");
    setWorkingProjection(newProj);

    // start up edit Dialog
    getEditor().setProjection(current);
    getEditor().setVisible(true);
  }
    /**
     * Set the projection from the dialog properties
     *
     * @param projClass projection class
     * @param proj projection
     */
    private void setProjFromDialog(ProjectionClass projClass, ProjectionImpl proj) {
      proj.setName(nameTF.getText().trim());

      for (int i = 0; i < projClass.paramList.size(); i++) {
        ProjectionParam pp = (ProjectionParam) projClass.paramList.get(i);
        // fetch the value from the projection object
        try {
          String valstr = pp.getTextField().getText();
          Double valdub = new Double(valstr);
          Object[] args = {valdub};
          if (debugBeans) {
            System.out.println("Projection setProjFromDialog invoke writer on " + pp);
          }
          pp.writer.invoke(proj, args);
        } catch (Exception ee) {
          System.err.println(
              "ProjectionManager: setProjParams failed "
                  + " invoking write "
                  + pp.name
                  + " class "
                  + projClass);
          continue;
        }
      }
    }
 /** Accept a change. */
 public void accept() {
   ProjectionRect bb = mapViewPanel.getMapArea();
   if ((bb == null) || (current == null)) {
     return;
   }
   current.setDefaultMapArea(new ProjectionRect(bb));
   lm.sendEvent(new java.beans.PropertyChangeEvent(this, PROPERTY_CHANGE, null, current));
 }
 /**
  * Make the default projections from the internal list of classes.
  *
  * @return list of default projections
  */
 public static List makeDefaultProjections() {
   List defaults = new ArrayList();
   List classNames = getDefaultProjections();
   for (int i = 0; i < classNames.size(); i++) {
     String className = (String) classNames.get(i);
     try {
       Class projClass = Misc.findClass(className);
       ProjectionImpl pi = (ProjectionImpl) projClass.newInstance();
       pi.setName("Default " + pi.getProjectionTypeLabel());
       defaults.add(pi);
     } catch (Exception ee) {
       System.err.println("Error creating default projection: " + className);
       ee.printStackTrace();
     }
   }
   return defaults;
 }
  /**
   * Set the working projection.
   *
   * @param proj projection to use
   */
  private void setWorkingProjection(ProjectionImpl proj) {
    if (proj == null) {
      return;
    }
    if (debug) {
      System.out.println("ProjManager.setWorkingProjection " + proj);
    }
    current = (ProjectionImpl) proj.constructCopy();
    if (debug) {
      System.out.println(
          "ProjManager.setWorkingProjection map area = " + current.getDefaultMapArea());
    }

    if (current != null) {
      mapLabel.setText(current.getName());
    }
    npViewControl.setProjectionImpl(current);
  }
  /**
   * Edit a projection. Used to change an existing projection or add a new one.
   *
   * @param isNew true if this is a new projection.
   */
  public void edit(boolean isNew) {

    String name = (isNew || (current == null)) ? "" : current.getName().trim();
    getEditor().setDoingNewProjection(isNew, name);
    if (isNew) {
      getEditor().setDefaultProjection();
    } else {
      getEditor().setProjection(current);
    }
    getEditor().setVisible(true);
  }
  /** Export a list of user selected projections */
  public void doExport() {
    List projections = getProjections();

    Vector<String> projectionNames = new Vector<>(projections.size());
    for (int i = 0; i < projections.size(); i++) {
      ProjectionImpl projection = (ProjectionImpl) projections.get(i);
      projectionNames.add(projection.getName());
    }

    JList<String> jlist = new JList<>(projectionNames);
    JPanel contents =
        GuiUtils.topCenter(
            GuiUtils.cLabel("Please select the projections you want to export"),
            GuiUtils.makeScrollPane(jlist, 200, 400));

    if (!GuiUtils.showOkCancelDialog(null, "Export Projections", contents, null)) {
      return;
    }

    int[] indices = jlist.getSelectedIndices();
    if ((indices == null) || (indices.length == 0)) {
      return;
    }
    List<ProjectionImpl> selected = new ArrayList<>(indices.length);
    for (int i = 0; i < indices.length; i++) {
      selected.add((ProjectionImpl) projections.get(indices[i]));
    }
    String xml = (new XmlEncoder()).toXml(selected);
    String filename = FileManager.getWriteFile(FileManager.FILTER_XML, FileManager.SUFFIX_XML);
    if (filename == null) {
      return;
    }
    try {
      IOUtil.writeFile(filename, xml);
    } catch (Exception exc) {
      LogUtil.logException("Writing projection file: " + filename, exc);
    }
  }
    /**
     * Set the projection for this editor
     *
     * @param proj projection to use
     */
    public void setProjection(ProjectionImpl proj) {
      ProjectionClass pc = findProjectionClass(proj);
      if (pc == null) {
        System.out.println("Projection Manager: cant find Class for " + proj);
        return;
      }
      if (debug) {
        System.out.println(" NPDialog set projection " + proj);
      }

      setProjectionClass(pc, proj);
      npEditControl.setProjectionImpl(proj);
      startingName = new String(proj.getName());
    }
    /** user has hit the "accept/save" button */
    private void accept() {
      ProjectionClass projClass = findProjectionClass(editProjection);
      if (null == projClass) {
        System.out.println(
            "Projection Manager accept: findProjectionClass failed" + editProjection);
        return;
      }
      setProjFromDialog(projClass, editProjection);
      ProjectionRect mapArea = mapEditPanel.getSelectedRegion();
      if (mapArea == null) {
        mapArea = mapEditPanel.getMapArea();
      }
      editProjection.setDefaultMapArea(mapArea);

      if (debug) {
        System.out.println("Projection Manager accept bb =" + editProjection.getDefaultMapArea());
      }
      ProjectionImpl newProj = (ProjectionImpl) editProjection.constructCopy(); // use a copy

      if (viewDialog != null) {
        //                if ( !viewDialog.checkSaveOK(startingName,
        //                                             newProj.getName())) {
        //                    return;
        //                }
      }

      if (ProjectionManager.this.contains(newProj.getName())) {
        projTable.replaceProjection(newProj);
      } else {
        projTable.addProjection(newProj);
      }

      // set new projection to working projection and exit this Dialog
      setWorkingProjection(newProj);
      NewProjectionDialog.this.setVisible(false);
    }
    /**
     * Set the projection class for a projection
     *
     * @param pc ProjectionClass
     * @param proj projection to set
     */
    private void setProjectionClass(ProjectionClass pc, ProjectionImpl proj) {
      if ((null == proj) || (null == pc)) {
        return;
      }

      if (debug) {
        System.out.println("Projection setProjectionClass= " + proj);
      }

      setFieldsWithClassParams(pc);
      editProjection = (ProjectionImpl) proj.constructCopy();
      putProjInDialog(pc, editProjection);

      if (debug) {
        System.out.println("Projection setProjectionClass ok ");
      }

      invalidate(); // force new layout
      validate();
    }
  /**
   * Create a new ProjectionManager.
   *
   * @param parent JFrame (application) or JApplet (applet)
   * @param projections list of initial projections
   * @param makeDialog true to make this a dialog
   * @param helpId help id if dialog
   * @param maps List of MapData
   */
  public ProjectionManager(
      RootPaneContainer parent, List projections, boolean makeDialog, String helpId, List maps) {

    this.helpId = helpId;
    this.maps = maps;
    this.parent = parent;

    // manage NewProjectionListeners
    lm =
        new ListenerManager(
            "java.beans.PropertyChangeListener",
            "java.beans.PropertyChangeEvent",
            "propertyChange");

    // here's where the map will be drawn: but cant be changed/edited
    npViewControl = new NPController();
    if (maps == null) {
      maps = getDefaultMaps(); // we use the system default
    }
    for (int mapIdx = 0; mapIdx < maps.size(); mapIdx++) {
      MapData mapData = (MapData) maps.get(mapIdx);
      if (mapData.getVisible()) {
        npViewControl.addMap(mapData.getSource(), mapData.getColor());
      }
    }
    mapViewPanel = npViewControl.getNavigatedPanel();
    mapViewPanel.setPreferredSize(new Dimension(250, 250));
    mapViewPanel.setToolTipText("Shows the default zoom of the current projection");
    mapViewPanel.setChangeable(false);

    if ((projections == null) || (projections.size() == 0)) {
      projections = makeDefaultProjections();
    }

    // the actual list is a JTable subclass
    projTable = new JTableProjection(this, projections);

    JComponent listContents = new JScrollPane(projTable);

    JComponent buttons =
        GuiUtils.hbox(
            GuiUtils.makeButton("Edit", this, "doEdit"),
            GuiUtils.makeButton("New", this, "doNew"),
            GuiUtils.makeButton("Export", this, "doExport"),
            GuiUtils.makeButton("Delete", this, "doDelete"));

    mapLabel = new JLabel(" ");
    JComponent leftPanel = GuiUtils.inset(GuiUtils.topCenter(mapLabel, mapViewPanel), 5);

    JComponent rightPanel = GuiUtils.topCenter(buttons, listContents);
    rightPanel = GuiUtils.inset(rightPanel, 5);
    contents = GuiUtils.inset(GuiUtils.hbox(leftPanel, rightPanel), 5);

    // default current and working projection
    if (null != (current = projTable.getSelected())) {
      setWorkingProjection(current);
      projTable.setCurrentProjection(current);
      mapLabel.setText(current.getName());
    }

    /* listen for new working Projections from projTable */
    projTable.addNewProjectionListener(
        new NewProjectionListener() {
          public void actionPerformed(NewProjectionEvent e) {
            if (e.getProjection() != null) {
              setWorkingProjection(e.getProjection());
            }
          }
        });

    eventsOK = true;

    // put it together in the viewDialog
    if (makeDialog) {
      Container buttPanel = GuiUtils.makeApplyOkHelpCancelButtons(this);
      contents = GuiUtils.centerBottom(contents, buttPanel);
      viewDialog =
          GuiUtils.createDialog(GuiUtils.getApplicationTitle() + "Projection Manager", false);
      viewDialog.getContentPane().add(contents);
      viewDialog.pack();
      ucar.unidata.util.Msg.translateTree(viewDialog);
      viewDialog.setLocation(100, 100);
    }
  }