Logo Search packages:      
Sourcecode: cdk version File versions

AbstractController2D.java

/*  $Revision: 8753 $ $Author: shk3 $ $Date: 2007-08-28 23:40:30 +0200 (Tue, 28 Aug 2007) $
 *
 *  Copyright (C) 2005-2007  Christoph Steinbeck <steinbeck@users.sf.net>
 *
 *  Contact: cdk-devel@lists.sourceforge.net
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.
 *  All I ask is that proper credit is given for my work, which includes
 *  - but is not limited to - adding the above copyright notice to the beginning
 *  of your source code files, and to any copyright notice that you may distribute
 *  with programs based on this work.
 *
 *  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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.openscience.cdk.controller;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.undo.UndoableEdit;
import javax.vecmath.Point2d;
import javax.vecmath.Vector2d;

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.applications.undoredo.AddAtomsAndBondsEdit;
import org.openscience.cdk.applications.undoredo.AddFuncGroupEdit;
import org.openscience.cdk.applications.undoredo.AdjustBondOrdersEdit;
import org.openscience.cdk.applications.undoredo.ChangeAtomSymbolEdit;
import org.openscience.cdk.applications.undoredo.ChangeChargeEdit;
import org.openscience.cdk.applications.undoredo.IUndoRedoHandler;
import org.openscience.cdk.applications.undoredo.MergeMoleculesEdit;
import org.openscience.cdk.applications.undoredo.MoveAtomEdit;
import org.openscience.cdk.applications.undoredo.RemoveAtomsAndBondsEdit;
import org.openscience.cdk.config.IsotopeFactory;
import org.openscience.cdk.event.ICDKChangeListener;
import org.openscience.cdk.geometry.BondTools;
import org.openscience.cdk.geometry.GeometryTools;
import org.openscience.cdk.graph.ConnectivityChecker;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IChemObject;
import org.openscience.cdk.interfaces.IElectronContainer;
import org.openscience.cdk.interfaces.IIsotope;
import org.openscience.cdk.interfaces.IMapping;
import org.openscience.cdk.interfaces.IMolecule;
import org.openscience.cdk.interfaces.IMoleculeSet;
import org.openscience.cdk.interfaces.IReaction;
import org.openscience.cdk.interfaces.IRing;
import org.openscience.cdk.layout.AtomPlacer;
import org.openscience.cdk.layout.RingPlacer;
import org.openscience.cdk.renderer.Renderer2DModel;
import org.openscience.cdk.tools.HydrogenAdder;
import org.openscience.cdk.tools.LoggingTool;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
import org.openscience.cdk.tools.manipulator.ChemModelManipulator;

/**
 * Class that acts on MouseEvents and KeyEvents.
 *
 * @author         steinbeck
 * @author         egonw
 * @cdk.created    2005-05-02
 * @cdk.keyword    mouse events
 * @cdk.require    java1.4+
 * @cdk.module     control
 * @cdk.bug        1562511
 */
00111 abstract class AbstractController2D implements MouseMotionListener, MouseListener, KeyListener
{

      private final static int DRAG_UNSET = 0;
      private final static int DRAG_MOVING_SELECTED = 1;
      private final static int DRAG_DRAWING_PROPOSED_BOND = 2;
      private final static int DRAG_DRAWING_PROPOSED_RING = 3;
      private final static int DRAG_MAKING_SQUARE_SELECTION = 4;
      private final static int DRAG_MAKING_LASSO_SELECTION = 5;
      private final static int DRAG_DRAWING_PROPOSED_ATOMATOMMAP = 6;
      private final static int DRAG_ROTATE = 7;
      
      protected Vector lastAction=null;
      protected JButton moveButton=null;
      
      protected IChemModel chemModel;
      
      Renderer2DModel r2dm;
      Controller2DModel c2dm;
      boolean wasDragged = false;
      boolean isUndoableChange = false;

      private Vector listeners = new Vector();

      private LoggingTool logger;

      private int prevDragCoordX = 0;
      private int prevDragCoordY = 0;
      private boolean draggingSelected = true;

      private int dragMode = DRAG_UNSET;

      private Vector commonElements;
      private HashMap currentCommonElement = new HashMap();
      IAtom lastAtomInRange = null;
      private double shiftX = 0;
      private double shiftY = 0;
      double moveoldX;
      double moveoldY;
      private IUndoRedoHandler undoRedoHandler;
      
      private HashMap funcgroupsmap=new HashMap();
      

      // Helper classes
      HydrogenAdder hydrogenAdder = new HydrogenAdder("org.openscience.cdk.tools.ValencyChecker");


      AbstractController2D()
      {
            logger = new LoggingTool(this);

      }

      AbstractController2D(Controller2DModel c2dm)
      {
            this();
            this.c2dm = c2dm;
            commonElements = new Vector();
            String[] elements = c2dm.getCommonElements();
            for (int i = 0; i < elements.length; i++)
            {
                  commonElements.add(elements[i]);
            }

      }

      AbstractController2D(Renderer2DModel r2dm, Controller2DModel c2dm)
      {
            
            this(c2dm);
            this.r2dm = r2dm;
      }

      
      
      /**
       *  Gets the controller2DModel attribute of the Controller2D object
       *
       *@return    The controller2DModel value
       */
00192       public Controller2DModel getController2DModel()
      {
            return c2dm;
      }


      /**
       *  Gets the undoableChange attribute of the Controller2D object
       *
       *@return    The undoableChange value
       */
00203       public boolean isUndoableChange()
      {
            return isUndoableChange;
      }


      /**
       *  Sets the undoableChange attribute of the Controller2D object
       *
       *@param  isUndoable  The new undoableChange value
       */
00214       public void setUndoableChange(boolean isUndoable)
      {
            this.isUndoableChange = isUndoable;
      }


      /**
       *  Sets the controller2DModel attribute of the Controller2D object
       *
       *@param  model  The new controller2DModel value
       */
00225       public void setController2DModel(Controller2DModel model)
      {
            this.c2dm = model;
      }


      /**
       *  Manages all actions that will be invoked when the mouse is moved.
       *
       *@param  event  MouseEvent object
       */
00236       public void mouseMoved(MouseEvent event)
      {
            int[] screenCoords = {event.getX(), event.getY()};
            int[] mouseCoords = getWorldCoordinates(screenCoords);
            int mouseX = mouseCoords[0];
            int mouseY = mouseCoords[1];
            highlightNearestChemObject(mouseX, mouseY);
            //this is the rotate feature
            if(c2dm.isMovingAllowed() && r2dm.getSelectedPart()!=null && r2dm.getHighlightedAtom()==null && r2dm.getHighlightedBond()==null && c2dm.getDrawMode() == Controller2DModel.LASSO){
                  double xmin=Double.MAX_VALUE;
                  double xmax=Double.MIN_VALUE;
                  double ymin=Double.MAX_VALUE;
                  double ymax=Double.MIN_VALUE;
                  for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++){
                        if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x>xmax)
                              xmax=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x;
                        if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y>ymax)
                              ymax=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y;
                        if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x<xmin)
                              xmin=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x;
                        if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y<ymin)
                              ymin=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y;
                  }
                  if(mouseCoords[0]>xmin && mouseCoords[0]<xmax && mouseCoords[1]>ymin && mouseCoords[1]<ymax){
                        //ok, we want to rotate
                        r2dm.setRotateCenter(xmin+(xmax-xmin)/2,ymin+(ymax-ymin)/2);
                        r2dm.setRotateRadius(Math.min((xmax-xmin)/4,(ymax-ymin)/4));
                  }
            }else{
                  //no rotation
                  r2dm.setRotateRadius(0);
            }
      }


      /**
       *  Manages all actions that will be invoked when the mouse is dragged.
       *
       *@param  event  MouseEvent object
       */
00276       public void mouseDragged(MouseEvent event)
      {
            isUndoableChange = false;
            logger.debug("MouseDragged Event Props: mode=", c2dm.getDrawModeString());
            if (logger.isDebugEnabled())
            {
                  logger.debug("   trigger=" + event.isPopupTrigger() +
                  /*
                   *  ", Button number: " + event.getButton() +
                   */
                              ", Click count: " + event.getClickCount());
            }

            int[] screenCoords = {event.getX(), event.getY()};
            int[] mouseCoords = getWorldCoordinates(screenCoords);
            int mouseX = mouseCoords[0];
            int mouseY = mouseCoords[1];

            if (!wasDragged)
            {
                  prevDragCoordX = mouseX;
                  prevDragCoordY = mouseY;
                  wasDragged = true;
            }

            if (dragMode == DRAG_DRAWING_PROPOSED_BOND)
            {
                  int startX = r2dm.getPointerVectorStart().x;
                  int startY = r2dm.getPointerVectorStart().y;
                  highlightNearestChemObject(mouseX, mouseY);
                  drawProposedBond(startX, startY, mouseX, mouseY);
            } else if (dragMode == DRAG_MAKING_SQUARE_SELECTION)
            {
                  int startX = r2dm.getPointerVectorStart().x;
                  int startY = r2dm.getPointerVectorStart().y;
                  selectRectangularArea(startX, startY, mouseX, mouseY);
            } else if (dragMode == DRAG_DRAWING_PROPOSED_RING)
            {
                  int endX = 0;
                  int endY = 0;
                  double angle = 0;
                  double pointerVectorLength = c2dm.getRingPointerLength();
                  Point2d center = GeometryTools.get2DCenter(getHighlighted(),r2dm.getRenderingCoordinates());
                  r2dm.setPointerVectorStart(new Point((int) center.x, (int) center.y));
                  angle = GeometryTools.getAngle(center.x - mouseX, center.y - mouseY);
                  endX = (int) center.x - (int) (Math.cos(angle) * pointerVectorLength);
                  endY = (int) center.y - (int) (Math.sin(angle) * pointerVectorLength);
                  r2dm.setPointerVectorEnd(new Point(endX, endY));
            } else if (dragMode == DRAG_MAKING_LASSO_SELECTION)
            {
                  /*
                   *  Draw polygon in screencoordinates, convert them
                   *  to world coordinates when mouse released
                   */
                  r2dm.addLassoPoint(new Point(event.getX(), event.getY()));
            } else if (dragMode == DRAG_MOVING_SELECTED)
            {
                  // all these are in model coordinates
                  logger.debug("Dragging selected atoms");
                  int deltaX = mouseX - prevDragCoordX;
                  int deltaY = mouseY - prevDragCoordY;
                  moveSelectedAtomsWith(deltaX, deltaY);
                  IAtomContainer selected=r2dm.getSelectedPart();
                  r2dm.getMerge().clear();
                  for(int i=0;i<selected.getAtomCount();i++){
                        IAtom inrange=getAtomInRange((int)((Point2d)r2dm.getRenderingCoordinate(selected.getAtom(i))).x, (int)((Point2d)r2dm.getRenderingCoordinate(selected.getAtom(i))).y, selected.getAtom(i));
                        if(inrange!=null && inrange!=selected.getAtom(i)){
                              r2dm.getMerge().put(selected.getAtom(i),inrange);
                        }
                  }
                  /*
                   *  PRESERVE THIS. This notifies the
                   *  the listener responsible for
                   *  undo and redo storage that it
                   *  should not store this change
                   */
            isUndoableChange = false;
                  fireChange();
            } else if(dragMode==DRAG_ROTATE){
                  double angle=BondTools.giveAngleBothMethods(new Point2d(r2dm.getRotateCenter()[0],r2dm.getRotateCenter()[1]),new Point2d(prevDragCoordX,prevDragCoordY),new Point2d(mouseX, mouseY),true);
                  Polygon polygon=new Polygon();
                  for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++) {
                        polygon.addPoint((int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x*1000),(int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y*1000));
                  }
                  polygon.addPoint((int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x*1000),(int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y*1000));
                  AffineTransform at=AffineTransform.getRotateInstance(angle,r2dm.getRotateCenter()[0]*1000,r2dm.getRotateCenter()[1]*1000);
                  Shape transformedpolygon=at.createTransformedShape(polygon);
                  PathIterator pa=transformedpolygon.getPathIterator(null);
                  
                  for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++) {
                        double[] d=new double[6];
                        pa.currentSegment(d);
                        r2dm.setRenderingCoordinate(r2dm.getSelectedPart().getAtom(i),new Point2d(d[0]/1000,d[1]/1000));
                        pa.next();
                  }
                  fireChange();
            }

            // make note of current coordinates for next DraggedEvent
            prevDragCoordX = mouseX;
            prevDragCoordY = mouseY;
      }


      /**
       *  manages all actions that will be invoked when a mouse button is pressed
       *
       *@param  event  MouseEvent object
       */
00385       public void mousePressed(MouseEvent event)
      {
            isUndoableChange = false;
            int[] screenCoords = {event.getX(), event.getY()};
            int[] mouseCoords = getWorldCoordinates(screenCoords);
            int mouseX = mouseCoords[0];
            int mouseY = mouseCoords[1];

            logger.debug("MousePressed Event Props: mode=", c2dm.getDrawModeString());
            if (logger.isDebugEnabled())
            {
                  logger.debug("   trigger=" + event.isPopupTrigger() +
                  /*
                   *  ", Button number: " + event.getButton() +
                   */
                              ", Click count: " + event.getClickCount());
            }

            int startX = 0;
            int startY = 0;
            r2dm.setPointerVectorStart(null);
            r2dm.setPointerVectorEnd(null);
            IAtom atomInRange = getAtomInRange(mouseX, mouseY);
            IBond bondInRange = getBondInRange(mouseX, mouseY);
            if (atomInRange != null)
            {
                  startX = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).x;
                  startY = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).y;
                  r2dm.setPointerVectorStart(new Point(startX, startY));
            } else
            {
                  r2dm.setPointerVectorStart(new Point(mouseX, mouseY));
            }
            
            if(r2dm.getSelectedPart()!=null &&
               !((atomInRange == null) || (atomInRange == null)) &&
               !(r2dm.getSelectedPart().contains(atomInRange) ||
               r2dm.getSelectedPart().contains(bondInRange)) && 
               r2dm.getRotateRadius()==0){
                  r2dm.setSelectedPart(atomInRange.getBuilder().newAtomContainer());
            }
            
            if (c2dm.getDrawMode() == Controller2DModel.MOVE)
            {
                  selectNearestChemObjectIfNoneSelected(mouseX, mouseY);
                  dragMode = DRAG_MOVING_SELECTED;
            } else if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND || c2dm.getDrawMode() == Controller2DModel.DOWN_BOND || c2dm.getDrawMode() == Controller2DModel.UP_BOND)
            {
                  if (bondInRange != null && atomInRange == null)
                  {
                        // make sure we are not dragging a bond
                  } else
                  {
                        dragMode = DRAG_DRAWING_PROPOSED_BOND;
                        lastAtomInRange = atomInRange;
                  }
            } else if (c2dm.getDrawMode() == Controller2DModel.MAPATOMATOM)
            {
                  dragMode = DRAG_DRAWING_PROPOSED_ATOMATOMMAP;
            } else if (c2dm.getDrawMode() == Controller2DModel.SELECT)
            {
                  dragMode = DRAG_MAKING_SQUARE_SELECTION;
            } else if (c2dm.getDrawMode() == Controller2DModel.LASSO && r2dm.getRotateRadius()==0)
            {
                  if(c2dm.isMovingAllowed() && r2dm.getSelectedPart()!=null && (r2dm.getSelectedPart().contains(r2dm.getHighlightedAtom()) || r2dm.getSelectedPart().contains(r2dm.getHighlightedBond()))){
                        if(r2dm.getSelectedPart().getAtomCount()>0)
                              c2dm.setDrawMode(Controller2DModel.MOVE);
                        if(lastAction!=null){
                              ((JButton)lastAction.get(0)).setBackground(Color.LIGHT_GRAY);
                              lastAction.set(0,moveButton);
                              moveButton.setBackground(Color.GRAY);
                        }
                        dragMode = DRAG_MOVING_SELECTED;
                  }
                  else{
                        dragMode = DRAG_MAKING_LASSO_SELECTION;
                  }
            } else if (c2dm.getDrawMode() == Controller2DModel.RING ||
                        c2dm.getDrawMode() == Controller2DModel.BENZENERING)
            {
                  dragMode = DRAG_DRAWING_PROPOSED_RING;
            } else if(r2dm.getRotateRadius()!=0){
                  dragMode = DRAG_ROTATE;
            }
            
            if(dragMode==DRAG_MOVING_SELECTED){
                  if (r2dm.getSelectedPart() != null && r2dm.getSelectedPart().getAtom(0) != null) {
                        moveoldX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x;
                        moveoldY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y;
                  }
            }
      }


      /**
       *  manages all actions that will be invoked when a mouse button is released
       *
       *@param  event  MouseEvent object
       */
00484       public void mouseReleased(MouseEvent event)
      {
            isUndoableChange = false;
            logger.debug("MouseReleased Event Props: mode=", c2dm.getDrawModeString());
            if (logger.isDebugEnabled())
            {
                  logger.debug("   trigger=" + event.isPopupTrigger(),
                              ", Click count: " + event.getClickCount());
            }
            if ((event.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)
            {
                  int[] screenCoords = {event.getX(), event.getY()};
                  int[] mouseCoords = getWorldCoordinates(screenCoords);
                  int mouseX = mouseCoords[0];
                  int mouseY = mouseCoords[1];
                  if (c2dm.getDrawMode() == Controller2DModel.SYMBOL)
                  {
                        changeSymbol();
                  }
                  if (c2dm.getDrawMode() == Controller2DModel.ELEMENT)
                  {
                        changeElement();
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.INCCHARGE)
                  {
                        increaseCharge();
                  }
                  if (c2dm.getDrawMode() == Controller2DModel.ENTERELEMENT)
                  {
                        enterElement();
                  }
                  if (c2dm.getDrawMode() == Controller2DModel.DECCHARGE)
                  {
                        decreaseCharge();
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.MAPATOMATOM)
                  {
                        handleMapping(wasDragged, r2dm);
                  }
      
                  if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND || c2dm.getDrawMode() == Controller2DModel.DOWN_BOND || c2dm.getDrawMode() == Controller2DModel.UP_BOND)
                  {
                        drawBond(mouseX, mouseY);
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.SELECT && wasDragged)
                  {
                        logger.info("User asks to selected atoms");
                        IAtomContainer selectedPart = chemModel.getBuilder().newAtomContainer();
                        r2dm.setSelectedPart(selectedPart);
                        r2dm.setSelectedPart(getContainedAtoms(r2dm.getSelectRect()));
                        r2dm.setSelectRect(null);
                        logger.debug("selected stuff  ", selectedPart);
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.ERASER)
                  {
                        eraseSelection();
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.RING || c2dm.getDrawMode() == Controller2DModel.BENZENERING)
                  {
                        drawRing(mouseX, mouseY);
                  }

                  if (c2dm.getDrawMode() == Controller2DModel.LASSO && r2dm.getRotateRadius()==0)
                  {
                        // first deselect all atoms
                        r2dm.setSelectedPart(chemModel.getBuilder().newAtomContainer());
                        // now select new atoms
                        if (wasDragged)
                        {
                              lassoSelection();

                        } else
                        {
                              singleObjectSelected(mouseX, mouseY);
                        }
                        fireChange();
                  }

                  if (wasDragged)
                  {
                        prevDragCoordX = 0;
                        prevDragCoordY = 0;
                        wasDragged = false;
                  }
                  if (dragMode==DRAG_MOVING_SELECTED){
                        dragAndDropSelection();
                  }
                  
                  if (c2dm.getDrawMode() == Controller2DModel.MOVE)
                  {
                        if (draggingSelected == false)
                        {                             
                              // then it was dragging nearest Bond or Atom
                              r2dm.setSelectedPart(chemModel.getBuilder().newAtomContainer());
                        }
                        if(r2dm.getMerge().size()>0){
                              mergeMolecules();
                              this.updateMoleculeCoordinates();
                        }
                  } 
                  
                  dragMode = DRAG_UNSET;
                  r2dm.setPointerVectorStart(null);
                  r2dm.setPointerVectorEnd(null);
            }
            if (shiftX != 0 || shiftY != 0)
            {
                  shiftMolecule();
            }
            shiftX = 0;
            shiftY = 0;
      }


      private void shiftMolecule() {
            for (int i = 0; i < chemModel.getMoleculeSet().getMoleculeCount(); i++)
            {
                  IMolecule mol = chemModel.getMoleculeSet().getMolecule(i);
                  for (int k = 0; k < mol.getAtomCount(); k++)
                  {
                        ((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).x=((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).x -shiftX;
                        ((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).y=((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).y -shiftY;
                  }
            }
            r2dm.fireChange();
            fireChange();
      }

      private void dragAndDropSelection() {
            double deltaX=0;
            double deltaY=0;
            IAtomContainer undoredoContainer = chemModel.getBuilder().newAtomContainer();
            if(r2dm.getSelectedPart()!=null && r2dm.getSelectedPart().getAtomCount()>0){
                  undoredoContainer.add(r2dm.getSelectedPart());
                  deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x-moveoldX;
                  deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y-moveoldY;
                  
            }else if(r2dm.getHighlightedAtom()!=null){
                  deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedAtom())).x-moveoldX;
                  deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedAtom())).y-moveoldY;
                  undoredoContainer.addAtom(r2dm.getHighlightedAtom());
            }else if (r2dm.getHighlightedBond()!=null){
                  deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedBond().getAtom(0))).x-moveoldX;
                  deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedBond().getAtom(0))).y-moveoldY; 
            }
            UndoableEdit edit = new MoveAtomEdit(undoredoContainer, (int)deltaX, (int)deltaY, r2dm.getRenderingCoordinates());
            undoRedoHandler.postEdit(edit);
      }

      private void mergeMolecules() {
            Iterator it=r2dm.getMerge().keySet().iterator();
            IBond[] bondson2 = null;
            IAtom atom2 = null;
            IAtom atom1 = null;
            ArrayList undoredoContainer = new ArrayList();
            while(it.hasNext()){
                  Object[] undoObject = new Object[3];
                  atom1=(IAtom)it.next();
                  atom2=(IAtom)r2dm.getMerge().get(atom1);
                  undoObject[0] = atom1;
                  undoObject[1] = atom2;
                  IMoleculeSet som=chemModel.getMoleculeSet();
                  IAtomContainer container1 = ChemModelManipulator.getRelevantAtomContainer(chemModel, atom1);
                  IAtomContainer container2 = ChemModelManipulator.getRelevantAtomContainer(chemModel, atom2);
                  if (container1 != container2) {
                        container1.add(container2);
                        som.removeAtomContainer(container2);
                  }
                  bondson2=AtomContainerManipulator.getBondArray(container1.getConnectedBondsList(atom2));
                  undoObject[2] = bondson2;
                  undoredoContainer.add(undoObject);
                  for(int i=0;i<bondson2.length;i++){
                        if(bondson2[i].getAtom(0)==atom2)
                              bondson2[i].setAtom(atom1,0);
                        if(bondson2[i].getAtom(1)==atom2)
                              bondson2[i].setAtom(atom1,1);
                        if(bondson2[i].getAtom(0)==bondson2[i].getAtom(1)){
                              container1.removeBond(bondson2[i]);
                        }
                  }
                  container1.removeAtom(atom2);
            }
            UndoableEdit  edit = new MergeMoleculesEdit(chemModel, undoredoContainer, "Molecules merged");
            undoRedoHandler.postEdit(edit);
            r2dm.getMerge().clear();
      }

      private void singleObjectSelected(int mouseX, int mouseY) {
//           one atom clicked or one bond clicked
            IChemObject chemObj = getChemObjectInRange(mouseX, mouseY);
            IAtomContainer container = chemObj.getBuilder().newAtomContainer();
            if (chemObj instanceof IAtom)
            {
                  container.addAtom((IAtom) chemObj);
                  logger.debug("selected one atom in lasso mode");
                  r2dm.setSelectedPart(container);
            } else if (chemObj instanceof IBond)
            {
                  IBond bond = (IBond) chemObj;
                  container.addBond(bond);
                  logger.debug("selected one bond in lasso mode");
                  for (int i = 0; i < bond.getAtomCount(); i++)
                  {
                        container.addAtom(bond.getAtom(i));
                  }
                  r2dm.setSelectedPart(container);
            }
      }

      private void lassoSelection() {
            Vector lassoPoints = r2dm.getLassoPoints();
            r2dm.addLassoPoint(new Point((Point) lassoPoints.elementAt(0)));
            int number = lassoPoints.size();
            logger.debug("# lasso points: ", number);
            int[] screenLassoCoords = new int[number * 2];
            Point currentPoint;
            for (int i = 0; i < number; i++)
            {
                  currentPoint = (Point) lassoPoints.elementAt(i);
                  screenLassoCoords[i * 2] = currentPoint.x;
                  screenLassoCoords[i * 2 + 1] = currentPoint.y;
                  logger.debug("ScreenLasso.x = ", screenLassoCoords[i * 2]);
                  logger.debug("ScreenLasso.y = ", screenLassoCoords[i * 2 + 1]);
            }
            /*
             *  Convert points to world coordinates as they are
             *  in screen coordinates in the vector
             */
            int[] worldCoords = getWorldCoordinates(screenLassoCoords);
            logger.debug("Returned coords: ", worldCoords.length);
            logger.debug("       # points: ", number);
            int[] xPoints = new int[number];
            int[] yPoints = new int[number];
            for (int i = 0; i < number; i++)
            {
                  xPoints[i] = worldCoords[i * 2];
                  yPoints[i] = worldCoords[i * 2 + 1];
                  logger.debug("WorldCoords.x  = ", worldCoords[i * 2]);
                  logger.debug("WorldCoords.y  = ", worldCoords[i * 2 + 1]);
                  logger.debug("Polygon.x = ", xPoints[i]);
                  logger.debug("Polygon.y = ", yPoints[i]);
            }
            Polygon polygon = new Polygon(xPoints, yPoints, number);
            r2dm.setSelectedPart(getContainedAtoms(polygon));
            r2dm.getLassoPoints().removeAllElements();
            r2dm.fireChange();
      }

      private void drawRing(int mouseX, int mouseY) {
            this.updateMoleculeCoordinates();
            IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
            IRing newRing = null;
            Point2d sharedAtomsCenter;
            Vector2d ringCenterVector;
            double bondLength;
            int pointerMarkX;
            int pointerMarkY;

            double ringRadius;

            double angle;

            double xDiff;

            double yDiff;

            double distance1 = 0;

            double distance2 = 0;
            IAtom firstAtom;
            IAtom secondAtom;
            IAtom spiroAtom;
            Point2d conAtomsCenter = null;
            Point2d newPoint1;
            Point2d newPoint2;

            RingPlacer ringPlacer = new RingPlacer();
            int ringSize = c2dm.getRingSize();
            String symbol = c2dm.getDrawElement();
            IAtomContainer sharedAtoms = getHighlighted();

            if (sharedAtoms.getAtomCount() == 0)
            {
                  sharedAtoms = sharedAtoms.getBuilder().newAtomContainer();
                  newRing = sharedAtoms.getBuilder().newRing(ringSize, symbol);
                  if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
                  {
                        // make newRing a benzene ring
                        newRing.getBond(0).setOrder(2.0);
                        newRing.getBond(2).setOrder(2.0);
                        newRing.getBond(4).setOrder(2.0);
                        makeRingAromatic(newRing);
                  }
                  bondLength = r2dm.getBondLength();
                  ringRadius = (bondLength / 2) / Math.sin(Math.PI / c2dm.getRingSize());
                  sharedAtomsCenter = new Point2d(mouseX, mouseY - ringRadius);
                  firstAtom = newRing.getAtom(0);
                  firstAtom.setPoint2d(sharedAtomsCenter);
                  sharedAtoms.addAtom(firstAtom);
                  ringCenterVector = new Vector2d(new Point2d(mouseX, mouseY));
                  ringCenterVector.sub(sharedAtomsCenter);
                  ringPlacer.placeSpiroRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);
                  IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
                  atomCon.add(newRing);
                  undoRedoContainer.add(newRing);
            } else if (sharedAtoms.getAtomCount() == 1)     {
                  spiroAtom = sharedAtoms.getAtom(0);
                  sharedAtomsCenter = GeometryTools.get2DCenter(sharedAtoms,r2dm.getRenderingCoordinates());
                  newRing = createAttachRing(sharedAtoms, ringSize, symbol);
                  if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
                  {
                        // make newRing a benzene ring
                        newRing.getBond(0).setOrder(2.0);
                        newRing.getBond(2).setOrder(2.0);
                        newRing.getBond(4).setOrder(2.0);
                        makeRingAromatic(newRing);
                  }
                  bondLength = r2dm.getBondLength();
                  conAtomsCenter = getConnectedAtomsCenter(sharedAtoms);
                  if (conAtomsCenter.equals(((Point2d)r2dm.getRenderingCoordinate(spiroAtom))))
                  {
                        ringCenterVector = new Vector2d(0, 1);
                  } else
                  {
                        ringCenterVector = new Vector2d(sharedAtomsCenter);
                        ringCenterVector.sub(conAtomsCenter);
                  }
                  ringPlacer.placeSpiroRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);
                  // removes the highlighed atom from the ring to add only the new placed
                  // atoms to the AtomContainer.
                  try
                  {
                        newRing.removeAtom(spiroAtom);
                  } catch (Exception exc)
                  {
                        logger.error("Could not remove atom from ring");
                        logger.debug(exc);
                  }
                  IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, spiroAtom);
                  atomCon.add(newRing);
                  undoRedoContainer.add(newRing);
            } else if (sharedAtoms.getAtomCount() == 2)     {
                  sharedAtomsCenter = GeometryTools.get2DCenter(sharedAtoms,r2dm.getRenderingCoordinates());

                  // calculate two points that are perpendicular to the highlighted bond
                  // and have a certain distance from the bondcenter
                  firstAtom = sharedAtoms.getAtom(0);
                  secondAtom = sharedAtoms.getAtom(1);
                  xDiff = ((Point2d)r2dm.getRenderingCoordinate(secondAtom)).x - ((Point2d)r2dm.getRenderingCoordinate(firstAtom)).x;
                  yDiff = ((Point2d)r2dm.getRenderingCoordinate(secondAtom)).y - ((Point2d)r2dm.getRenderingCoordinate(firstAtom)).y;
                  bondLength = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2));
                  angle = GeometryTools.getAngle(xDiff, yDiff);
                  newPoint1 = new Point2d((Math.cos(angle + (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.x, (Math.sin(angle + (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.y);
                  newPoint2 = new Point2d((Math.cos(angle - (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.x, (Math.sin(angle - (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.y);

                  if (wasDragged)
                  {
                        // check which one of the two points is nearest to the endpoint of the pointer
                        // vector that was dragged to make the ringCenterVector point into the right direction.
                        pointerMarkX = r2dm.getPointerVectorEnd().x;
                        pointerMarkY = r2dm.getPointerVectorEnd().y;
                        distance1 = -1 * (Math.sqrt(Math.pow(newPoint1.x - pointerMarkX, 2) + Math.pow(newPoint1.y - pointerMarkY, 2)));
                        distance2 = -1 * (Math.sqrt(Math.pow(newPoint2.x - pointerMarkX, 2) + Math.pow(newPoint2.y - pointerMarkY, 2)));
                        r2dm.setPointerVectorStart(null);
                        r2dm.setPointerVectorEnd(null);
                  } else {
                        // check which one of the two points is nearest to the center of the
                        // connected atoms to make the ringCenterVector point into the right direction.
                        conAtomsCenter = getConnectedAtomsCenter(sharedAtoms);
                        distance1 = Math.sqrt(Math.pow(newPoint1.x - conAtomsCenter.x, 2) + Math.pow(newPoint1.y - conAtomsCenter.y, 2));
                        distance2 = Math.sqrt(Math.pow(newPoint2.x - conAtomsCenter.x, 2) + Math.pow(newPoint2.y - conAtomsCenter.y, 2));
                  }
                  ringCenterVector = new Vector2d(sharedAtomsCenter);
                  // no ring is attached if the two ditances are equal
                  //shk3: I removed this condition since it leads to npe and I cannot see why it is necessary.
                  //the npe is if you draw a single bond and want to attach a ring to it. Now the ring is in an arbitrary direction, but this is ok
                  /*if (distance1 == distance2)
                  {
                        logger.warn("don't know where to draw the new Ring");
                  } else*/
                  {
                        if (distance1 < distance2)
                        {
                              ringCenterVector.sub(newPoint1);
                        } else if (distance2 < distance1)
                        {
                              ringCenterVector.sub(newPoint2);
                        } else{
                              ringCenterVector.sub(newPoint2);
                        }

                        IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, firstAtom);

                        // construct a new Ring that contains the highlighted bond an its two atoms
                        newRing = createAttachRing(sharedAtoms, ringSize, symbol);
                        if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
                        {
                              // make newRing a benzene ring
                              IBond existingBond = atomCon.getBond(firstAtom, secondAtom);
                              if (existingBond.getOrder() == 1.0)
                              {
                                    if (existingBond.getFlag(CDKConstants.ISAROMATIC))
                                    {
                                          newRing.getBond(2).setOrder(2.0);
                                          newRing.getBond(4).setOrder(2.0);
                                    } else
                                    {
                                          newRing.getBond(1).setOrder(2.0);
                                          newRing.getBond(3).setOrder(2.0);
                                          newRing.getBond(5).setOrder(2.0);
                                    }
                              } else
                              {
                                    newRing.getBond(2).setOrder(2.0);
                                    newRing.getBond(4).setOrder(2.0);
                              }
                              makeRingAromatic(newRing);
                        }

                        // place the new atoms of the new ring to the right position
                        ringPlacer.placeFusedRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);

                        // removes the highlighed bond and its atoms from the ring to add only
                        // the new placed atoms to the AtomContainer.
                        try
                        {
                              newRing.remove(sharedAtoms);
                        } catch (Exception exc)
                        {
                              logger.error("Could not remove atom from ring");
                              logger.debug(exc);
                        }
                        atomCon.add(newRing);
                  }
            }
            double highlightRadius = r2dm.getHighlightRadius();
            for (int i = 0; i < newRing.getAtomCount(); i++)
            {
                  IAtom atom=newRing.getAtom(i);
                  r2dm.setRenderingCoordinate(atom,new Point2d(atom.getPoint2d()));
            }
            for (int i = 0; i < newRing.getAtomCount(); i++)
            {
                  IAtom atom=newRing.getAtom(i);
                  r2dm.setRenderingCoordinate(atom,new Point2d(atom.getPoint2d()));
                  centerAtom(atom,chemModel);
                  //We make sure atoms don't overlap
                  //Solution is a bit crude, we would need to find an unoccupied place (and even the bond display should be optimized)
                  IAtom inrange=getAtomInRange((int)((Point2d)r2dm.getRenderingCoordinate(atom)).x, (int)((Point2d)r2dm.getRenderingCoordinate(atom)).y, atom);
                  if(inrange!=null && Math.sqrt(Math.pow(((Point2d)r2dm.getRenderingCoordinate(inrange)).x - ((Point2d)r2dm.getRenderingCoordinate(atom)).x, 2) + Math.pow(((Point2d)r2dm.getRenderingCoordinate(inrange)).y - ((Point2d)r2dm.getRenderingCoordinate(atom)).y, 2)) < highlightRadius/4){
                        ((Point2d)r2dm.getRenderingCoordinate(atom)).x-=highlightRadius/4;
                        ((Point2d)r2dm.getRenderingCoordinate(atom)).y-=highlightRadius/4;
                  }
            }
            this.updateMoleculeCoordinates();
            this.updateAtoms(ChemModelManipulator.getRelevantAtomContainer(chemModel, newRing.getAtom(0)), sharedAtoms.atoms());
            this.updateAtoms(ChemModelManipulator.getRelevantAtomContainer(chemModel, newRing.getAtom(0)), newRing.atoms());
            undoRedoContainer.add(newRing);
            UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Added Ring",c2dm);
            undoRedoHandler.postEdit(edit);
            r2dm.fireChange();
            fireChange();
      }

      private void eraseSelection() {
            IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
            String type = null;
            IAtom highlightedAtom = r2dm.getHighlightedAtom();
            IBond highlightedBond = r2dm.getHighlightedBond();
            if (highlightedAtom != null && (r2dm.getSelectedPart()==null || !r2dm.getSelectedPart().contains(highlightedAtom)))
            {
                  logger.info("User asks to delete an Atom");
                  IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, highlightedAtom);
                  IElectronContainer[] eContainer = AtomContainerManipulator.getElectronContainerArray(container.getConnectedElectronContainersList(highlightedAtom));
                  for (int i=0; i<eContainer.length; i++) {
                        undoRedoContainer.addBond((IBond) eContainer[i]);
                  }
                  logger.debug("Atoms before delete: ", container.getAtomCount());
                  Iterator atoms = container.getConnectedAtomsList(highlightedAtom).iterator();
                  ChemModelManipulator.removeAtomAndConnectedElectronContainers(chemModel, highlightedAtom);
                  updateAtoms(container, atoms);
                  undoRedoContainer.addAtom(highlightedAtom);
                  if (type == null) {
                        type = "Remove Atom";
                  }
                  else {
                        type = "Remove Substructure";
                  }
                  logger.debug("Atoms before delete: ", container.getAtomCount());
            } else if (highlightedBond != null && (r2dm.getSelectedPart()==null || !r2dm.getSelectedPart().contains(highlightedBond))){
                  logger.info("User asks to delete a Bond");
                  ChemModelManipulator.removeElectronContainer(chemModel, highlightedBond);
                  undoRedoContainer.addBond(highlightedBond);
                  if (type == null) {
                        type = "Remove Bond";
                  }
                  else {
                        type = "Remove Substructure";
                  }
                  // update atoms
                  java.util.Iterator atoms = highlightedBond.atoms();
                  IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, highlightedBond.getAtom(0));
                  updateAtoms(container, atoms);
            } else if(r2dm.getSelectedPart()!=null && (r2dm.getSelectedPart().getAtomCount()>0 || r2dm.getSelectedPart().getBondCount()>0)){
                  logger.info("User asks to delete selected part");
                  IAtomContainer containerToUpdate = ChemModelManipulator.getRelevantAtomContainer(chemModel, r2dm.getSelectedPart().getAtom(0));
                  for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++){
                        undoRedoContainer.addAtom(r2dm.getSelectedPart().getAtom(i));
                        for(int k=0;k<ChemModelManipulator.getRelevantAtomContainer(chemModel,r2dm.getSelectedPart().getAtom(i)).getConnectedBondsCount(r2dm.getSelectedPart().getAtom(i));k++){
                              undoRedoContainer.addBond((IBond)ChemModelManipulator.getRelevantAtomContainer(chemModel,r2dm.getSelectedPart().getAtom(i)).getConnectedBondsList(r2dm.getSelectedPart().getAtom(i)).get(k));
                        }
                        ChemModelManipulator.removeAtomAndConnectedElectronContainers(chemModel,r2dm.getSelectedPart().getAtom(i));
                  }
                  type = "Remove Substructure";
                  // update atoms
                  updateAtoms(containerToUpdate, containerToUpdate.atoms());
            }else{
                  logger.warn("Cannot deleted if nothing is highlighted");
                  return;
            }
            /*
             *  PRESERVE THIS. This notifies the
             *  the listener responsible for
             *  undo and redo storage that it
             *  should store this change of an atom symbol
             */
            isUndoableChange = true;
            /*
             *  ---
             */
            UndoableEdit  edit = new RemoveAtomsAndBondsEdit(chemModel, undoRedoContainer, type);
            undoRedoHandler.postEdit(edit);
            r2dm.fireChange();
            fireChange();
      }

      private void drawBond(int mouseX, int mouseY) {
            this.updateMoleculeCoordinates();
            logger.debug("mouseReleased->drawbond");
            IAtom atomInRange;
            IAtom newAtom1 = null;
            IAtom newAtom2 = null;
            IBond newBond = null;
            int startX = r2dm.getPointerVectorStart().x;
            int startY = r2dm.getPointerVectorStart().y;
            IBond bondInRange = r2dm.getHighlightedBond();
            

            
            //atomInRange = r2dm.getHighlightedAtom();
            //Bond bondInRange = getBondInRange(mouseX, mouseY);
            /*
             *  IMPORTANT: I don't use getHighlighteAtom()
             *  here because of the special case of
             *  only one atom on the screen.
             *  In this case, this atom will not detected
             *  if the mouse hasn't moved after it's creation
             */
            atomInRange = getAtomInRange(mouseX, mouseY);
            if (bondInRange != null)
            {
//                update atoms
                  IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, bondInRange.getAtom(0));
                  updateAtoms(container, bondInRange.atoms());
                  HashMap changedBonds = new HashMap();
                  double formerBondOrder = bondInRange.getOrder();
                  if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND){
                        if(bondInRange.getStereo()!=CDKConstants.STEREO_BOND_NONE){
                              bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
                        }else{
                              // increase Bond order
                              double order = bondInRange.getOrder();
                              if (order >= CDKConstants.BONDORDER_TRIPLE)
                              {
                                    bondInRange.setOrder(CDKConstants.BONDORDER_SINGLE);
                              } else {
                                    bondInRange.setOrder(order + 1.0);
                                    // this is tricky as it depends on the fact that the
                                    // constants are unidistant, i.e. {1.0, 2.0, 3.0}.
                              }
                        }
                  }else if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND){
                  // toggle bond stereo
                  double stereo = bondInRange.getStereo();
                  if (stereo == CDKConstants.STEREO_BOND_DOWN)
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_DOWN_INV);
                  } else if (stereo == CDKConstants.STEREO_BOND_DOWN_INV)
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
                  } else
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_DOWN);
                  }
                  bondInRange.setOrder(1);
                  }else{
                  // toggle bond stereo
                  double stereo = bondInRange.getStereo();
                  if (stereo == CDKConstants.STEREO_BOND_UP)
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_UP_INV);
                  } else if (stereo == CDKConstants.STEREO_BOND_UP_INV)
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
                  } else
                  {
                    bondInRange.setStereo(CDKConstants.STEREO_BOND_UP);
                  }
                  bondInRange.setOrder(1);
                  }           
                  /*
                   *  PRESERVE THIS. This notifies the
                   *  the listener responsible for
                   *  undo and redo storage that it
                   *  should store this change of an atom symbol
                   */
                  if (bondInRange.getOrder() != formerBondOrder) {
                double[] bondOrders = new double[2];
                bondOrders[0] = bondInRange.getOrder();
                bondOrders[1] = formerBondOrder;
                changedBonds.put(bondInRange, bondOrders);
            }
                  isUndoableChange = true;
                  /*
                   *  ---
                   */
                  UndoableEdit  edit = new AdjustBondOrdersEdit(changedBonds);
                  undoRedoHandler.postEdit(edit);
                  updateAtoms(container, bondInRange.atoms());
            } else
            {
                  IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
                  if (atomInRange != null)
                  {
                        logger.debug("We had an atom in range");
                        newAtom1 = atomInRange;
                  } else if (!wasDragged)
                  {
                        // create a new molecule
                        logger.debug("We make a new molecule");
                        newAtom1 = undoRedoContainer.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(startX, startY));
                        IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
                        atomCon.addAtom(newAtom1);
                        r2dm.setRenderingCoordinate(newAtom1,new Point2d(startX, startY));
                        // update atoms
                        updateAtom(atomCon, newAtom1);
                        undoRedoContainer.add(atomCon);
                  }

                  if (wasDragged)
                  {
                        if (dragMode == DRAG_DRAWING_PROPOSED_BOND)
                        {
                              int endX = r2dm.getPointerVectorEnd().x;
                              int endY = r2dm.getPointerVectorEnd().y;
                              atomInRange = getAtomInRange(endX, endY);
                              // OK, there is some repartitioning done on atomCon later, so put everything in the first AC
                              IAtomContainer atomCon = null;
                              Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
                              while (atomCons.hasNext()) {
                                    if (atomCon == null) { 
                                          atomCon = (IAtomContainer)atomCons.next();
                                    } else {
                                          atomCon.add((IAtomContainer)atomCons.next());                                       
                                    }
                              }
                              if (atomCon == null) atomCon = chemModel.getBuilder().newAtomContainer();
                              if (atomInRange != null)
                              {
                                    logger.debug("*** atom in range");

                                    newAtom2 = atomInRange;
                                    logger.debug("atomCon.getAtomCount() " + atomCon.getAtomCount());
                              } else
                              {
                                    logger.debug("*** new atom");
                                    newAtom2 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(endX, endY));
                                    atomCon.addAtom(newAtom2);
                                    r2dm.setRenderingCoordinate(newAtom2,new Point2d(endX, endY));
                                    undoRedoContainer.addAtom(newAtom2);
                              }
                              newAtom1 = lastAtomInRange;
                              if (newAtom1 == null)
                              {
                                    newAtom1 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(r2dm.getPointerVectorStart().x, r2dm.getPointerVectorStart().y));
                                    undoRedoContainer.addAtom(newAtom1);
                              }
                              if (newAtom1 != newAtom2)
                              {
                                    newBond = atomCon.getBuilder().newBond(newAtom1, newAtom2, 1);
                                    if(c2dm.getDrawMode() == Controller2DModel.UP_BOND)
                                          newBond.setStereo(CDKConstants.STEREO_BOND_UP);
                                    if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND)
                                          newBond.setStereo(CDKConstants.STEREO_BOND_DOWN);
                                    logger.debug(newAtom1 + " - " + newAtom2);
                                    atomCon.addBond(newBond);
                                    undoRedoContainer.addBond(newBond);
                              }

                              try
                              {
                                    IMoleculeSet setOfMolecules = ConnectivityChecker.partitionIntoMolecules(atomCon);
                                    chemModel.setMoleculeSet(setOfMolecules);
                                    logger.debug("We have " + setOfMolecules.getAtomContainerCount() + " molecules on screen");
                              } catch (Exception exception)
                              {
                                    logger.warn("Could not partition molecule: ", exception.getMessage());
                                    logger.debug(exception);
                                    return;
                              }

                              // update atoms
                              updateAtom(atomCon, newAtom2);

                              /*
                               *  PRESERVE THIS. This notifies the
                               *  the listener responsible for
                               *  undo and redo storage that it
                               *  should store this change of an atom symbol
                               */
                              isUndoableChange = true;
                              /*
                               *  ---
                               */
                        }
                  } else if (atomInRange != null)
                  {
                        // add a new atom to the current atom in some random
                        // direction
                        IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                        newAtom2 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), ((Point2d)r2dm.getRenderingCoordinate(atomInRange)));

                        // now create 2D coords for new atom
                        double bondLength = r2dm.getBondLength();
                        java.util.List connectedAtoms = atomCon.getConnectedAtomsList(atomInRange);
                        logger.debug("connectedAtoms.length: " + connectedAtoms.size());
                        IAtomContainer placedAtoms = atomCon.getBuilder().newAtomContainer();
                        //placedAtoms.addAtom(atomInRange);
                        for (int i = 0; i < connectedAtoms.size(); i++)
                        {
                              placedAtoms.addAtom((IAtom)connectedAtoms.get(i));
                        }
                        IAtomContainer unplacedAtoms = atomCon.getBuilder().newAtomContainer();
                        unplacedAtoms.addAtom(newAtom2);
                        AtomPlacer atomPlacer = new AtomPlacer();
                        atomPlacer.setMolecule(atomCon.getBuilder().newMolecule(atomCon));
                        Point2d center2D = GeometryTools.get2DCenter(placedAtoms,r2dm.getRenderingCoordinates());
                        logger.debug("placedAtoms.getAtomCount(): " + placedAtoms.getAtomCount());
                        logger.debug("unplacedAtoms.getAtomCount(): " + unplacedAtoms.getAtomCount());
                        if (placedAtoms.getAtomCount() == 1)
                        {
                              Vector2d bondVector = atomPlacer.getNextBondVector(
                                          atomInRange, placedAtoms.getAtom(0), 
                                          GeometryTools.get2DCenter(atomCon.getBuilder().newMolecule(atomCon),r2dm.getRenderingCoordinates()),
                                          true // FIXME: is this correct? (see SF bug #1367002)
                              );
                              Point2d atomPoint = new Point2d(((Point2d)r2dm.getRenderingCoordinate(atomInRange)));
                              bondVector.normalize();
                              bondVector.scale(bondLength);
                              atomPoint.add(bondVector);
                              newAtom2.setPoint2d(atomPoint);
                              r2dm.setRenderingCoordinate(newAtom2,atomPoint);

                        } else
                        {
                              atomPlacer.distributePartners(atomInRange, placedAtoms, center2D,
                                          unplacedAtoms, bondLength);
                        }

                        // now add the new atom
                        atomCon.addAtom(newAtom2);
                        undoRedoContainer.addAtom(newAtom2);
                        r2dm.setRenderingCoordinate(newAtom2,new Point2d(newAtom2.getPoint2d()));
                        newBond= undoRedoContainer.getBuilder().newBond(atomInRange, newAtom2, 1.0);
                        atomCon.addBond(newBond);
                        undoRedoContainer.addBond(newBond);
                        if(c2dm.getDrawMode() == Controller2DModel.UP_BOND)
                              newBond.setStereo(CDKConstants.STEREO_BOND_UP);
                        if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND)
                              newBond.setStereo(CDKConstants.STEREO_BOND_DOWN);
                        // update atoms
                        updateAtom(atomCon, atomInRange);
                        updateAtom(atomCon, newAtom2);
                  }
                  UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Add Bond",c2dm);
                  undoRedoHandler.postEdit(edit);
            }
            r2dm.fireChange();
            fireChange();
            if(newAtom1!=null && r2dm.getRenderingCoordinate(newAtom1)==null)
                  r2dm.setRenderingCoordinate(newAtom1,new Point2d(newAtom1.getPoint2d()));
            if(newAtom2!=null)
                  r2dm.setRenderingCoordinate(newAtom2,new Point2d(newAtom2.getPoint2d()));
            centerAtom(newAtom1,chemModel);
            centerAtom(newAtom2,chemModel);
            this.updateMoleculeCoordinates();
      }

      private void decreaseCharge() {
            IAtom atomInRange = r2dm.getHighlightedAtom();
            if (atomInRange != null)
            {
                  int formerCharge = atomInRange.getFormalCharge();
                  atomInRange.setFormalCharge(atomInRange.getFormalCharge() - 1);
                  // update atom
                  IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                  updateAtom(container, atomInRange);
                  //undoredo support
            UndoableEdit  edit = new ChangeChargeEdit(atomInRange, formerCharge, atomInRange.getFormalCharge());
                  undoRedoHandler.postEdit(edit);
                  r2dm.fireChange();
                  fireChange();
            }
      }

      private void enterElement() {
            IAtom atomInRange = r2dm.getHighlightedAtom();
            if (atomInRange != null)
            {
                  String[] funcGroupsKeys=new String[funcgroupsmap.keySet().size()+1];
              Iterator it=funcgroupsmap.keySet().iterator();
              int h=1;
              funcGroupsKeys[0]="";
              while(it.hasNext()){
                  funcGroupsKeys[h]=(String)it.next();
                  h++;
              }
                  String x=EnterElementOrGroupDialog.showDialog(null,null, "Enter an element symbol or choose/enter a functional group abbrivation:", "Enter element", funcGroupsKeys, "","");
                  try{
                        IAtomContainer ac=(IAtomContainer)funcgroupsmap.get(x.toLowerCase());
                        //this means a functional group was entered
                        //TODO undo-redo
                        if(ac!=null && !x.equals("")){
                              ac=(IAtomContainer)((IAtomContainer)funcgroupsmap.get(x)).clone();
                              IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                              IAtom lastplaced=null;
                              int counter=0;
                              //this is the starting point for placing
                              ac.getAtom(0).setPoint2d((Point2d)r2dm.getRenderingCoordinate(atomInRange));
                              r2dm.setRenderingCoordinate(ac.getAtom(0), (Point2d)r2dm.getRenderingCoordinate(atomInRange));
                              lastplaced=ac.getAtom(0);
                              counter=1;
                              container.add(ac);
                              List connbonds=container.getConnectedBondsList(atomInRange);
                              //this is needed for undo redo
                              IAtomContainer undoredocontainer=ac.getBuilder().newAtomContainer();
                              undoredocontainer.addAtom(atomInRange);
                              for(int i=0;i<connbonds.size();i++){
                                    IBond bond=(IBond)connbonds.get(i);
                                    if(bond.getAtom(0)==atomInRange){
                                          bond.setAtom(ac.getAtom(0), 0);
                                          undoredocontainer.addBond(bond);
                                    }else{
                                          bond.setAtom(ac.getAtom(0), 1);
                                          undoredocontainer.addBond(bond);
                                    }
                              }
                              container.removeAtomAndConnectedElectronContainers(atomInRange);
                              AtomPlacer ap=new AtomPlacer();
                              while(lastplaced!=null){
                                    IAtomContainer placedNeighbours=container.getBuilder().newAtomContainer();
                                    IAtomContainer unplacedNeighbours=container.getBuilder().newAtomContainer();
                                    List l=container.getConnectedAtomsList(lastplaced);
                                    for(int i=0;i<l.size();i++){
                                          if(r2dm.getRenderingCoordinate((IAtom)l.get(i))!=null)
                                                placedNeighbours.addAtom((IAtom)l.get(i));
                                          else
                                                unplacedNeighbours.addAtom((IAtom)l.get(i));
                                    }
                                    ap.distributePartners(lastplaced, placedNeighbours, GeometryTools.get2DCenter(placedNeighbours,r2dm.getRenderingCoordinates()), unplacedNeighbours, r2dm.getBondLength(), r2dm.getRenderingCoordinates());
                                    lastplaced=ac.getAtom(counter);
                                    counter++;
                                    if(counter==ac.getAtomCount())
                                          lastplaced=null;
                              }
                              it=container.atoms();
                              while(it.hasNext()){
                                    IAtom atom=(IAtom)it.next();
                                    if(r2dm.getRenderingCoordinate(atom)==null)
                                          r2dm.setRenderingCoordinate(atom, atom.getPoint2d());
                              }
                              /*
                               *  PRESERVE THIS. This notifies the
                               *  the listener responsible for
                               *  undo and redo storage that it
                               *  should store this change of an atom symbol
                               */
                              isUndoableChange = true;
                              /*
                               *  ---
                               */
                              // undoredo support
                              UndoableEdit  edit = new AddFuncGroupEdit(chemModel, undoredocontainer ,ac, "add "+x);
                              undoRedoHandler.postEdit(edit);
                              //undoRedoHandler.postEdit(edit);
                              r2dm.fireChange();
                              fireChange();
                        }else if(x!=null && x.length()>0){
                              String formerSymbol="";
                              if(Character.isLowerCase(x.toCharArray()[0]))
                                    x=Character.toUpperCase(x.charAt(0))+x.substring(1);
                              IsotopeFactory ifa=IsotopeFactory.getInstance(r2dm.getHighlightedAtom().getBuilder());
                              IIsotope iso=ifa.getMajorIsotope(x);
                              formerSymbol=r2dm.getHighlightedAtom().getSymbol();
                              if(iso!=null)
                                    r2dm.getHighlightedAtom().setSymbol(x);
                              // update atom
                              IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                              updateAtom(container, atomInRange);
                              /*
                               *  PRESERVE THIS. This notifies the
                               *  the listener responsible for
                               *  undo and redo storage that it
                               *  should store this change of an atom symbol
                               */
                              isUndoableChange = true;
                              /*
                               *  ---
                               */
                              // undoredo support
                              UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, x);
                              undoRedoHandler.postEdit(edit);
                              r2dm.fireChange();
                              fireChange();
                        }
                  }catch(Exception ex){
                        ex.printStackTrace();
                        logger.debug(ex.getMessage()+" in SELECTELEMENT");
                  }
            }
      }

      private void increaseCharge() {
            IAtom atomInRange = r2dm.getHighlightedAtom();
            if (atomInRange != null)
            {
                  int formerCharge = atomInRange.getFormalCharge();
                  atomInRange.setFormalCharge(atomInRange.getFormalCharge() + 1);

                  // update atom
                  IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                  updateAtom(container, atomInRange);
                  //undoredo support
            UndoableEdit  edit = new ChangeChargeEdit(atomInRange, formerCharge, atomInRange.getFormalCharge());
                  undoRedoHandler.postEdit(edit);
                  r2dm.fireChange();
                  fireChange();
            }
      }

      private void changeElement() {
            IAtom atomInRange = r2dm.getHighlightedAtom();
            if (atomInRange != null)
            {
                  String symbol = c2dm.getDrawElement();
                  if (!(atomInRange.getSymbol().equals(symbol)))
                  {
                        // only change symbol if needed
                        String formerSymbol = atomInRange.getSymbol();
                        atomInRange.setSymbol(symbol);
                        // configure the atom, so that the atomic number matches the symbol
                        try
                        {
                              IsotopeFactory.getInstance(atomInRange.getBuilder()).configure(atomInRange);
                        } catch (Exception exception)
                        {
                              logger.error("Error while configuring atom");
                              logger.debug(exception);
                        }
                        // update atom
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                        updateAtom(container, atomInRange);
                        
                        /*
                         *  PRESERVE THIS. This notifies the
                         *  the listener responsible for
                         *  undo and redo storage that it
                         *  should store this change of an atom symbol
                         */
//                      isUndoableChange = true;
                        /*
                         *  ---
                         */
                        // undoredo support
                        UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, symbol);
                        undoRedoHandler.postEdit(edit);
                        r2dm.fireChange();
                        fireChange();
                  }
            }else{
                  int startX = r2dm.getPointerVectorStart().x;
                  int startY = r2dm.getPointerVectorStart().y;
                  IAtom newAtom1 = chemModel.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(startX, startY));
                  r2dm.setRenderingCoordinate(newAtom1,new Point2d(startX, startY));
                  IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
                  atomCon.addAtom(newAtom1);
                  // update atoms
                  updateAtom(atomCon, newAtom1);
                  chemModel.getMoleculeSet().addAtomContainer(atomCon);
                  //FIXME undoredo
                  IAtomContainer undoRedoContainer= chemModel.getBuilder().newAtomContainer();
                  undoRedoContainer.addAtom(newAtom1);
                  UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Add Atom",c2dm);
                  undoRedoHandler.postEdit(edit);
                  this.updateMoleculeCoordinates();
                  r2dm.fireChange();
                  fireChange();
            }
      }

      private void changeSymbol() {
            IAtom atomInRange = r2dm.getHighlightedAtom();
            if (atomInRange != null)
            {
                  if (currentCommonElement.get(atomInRange) == null)
                  {
                        currentCommonElement.put(atomInRange, new Integer(1));
                  }
                  int oldCommonElement = ((Integer) currentCommonElement.get(atomInRange)).intValue();
                  String symbol = (String) commonElements.elementAt(oldCommonElement);
                  if (!(atomInRange.getSymbol().equals(symbol)))
                  {
                        // only change symbol if needed
                String formerSymbol = atomInRange.getSymbol();
                        atomInRange.setSymbol(symbol);
                        // configure the atom, so that the atomic number matches the symbol
                        try
                        {
                              IsotopeFactory.getInstance(atomInRange.getBuilder()).configure(atomInRange);
                        } catch (Exception exception)
                        {
                              logger.error("Error while configuring atom");
                              logger.debug(exception);
                        }
                        // update atom
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
                        updateAtom(container, atomInRange);

                        /*
                         *  PRESERVE THIS. This notifies the
                         *  the listener responsible for
                         *  undo and redo storage that it
                         *  should store this change of an atom symbol
                         */
                        isUndoableChange = true;
                        /*
                         *  ---
                         */
                UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, symbol);
                undoRedoHandler.postEdit(edit);
                        r2dm.fireChange();
                        fireChange();
                  }
                  oldCommonElement++;
                  if (oldCommonElement == commonElements.size())
                  {
                        oldCommonElement = 0;
                  }
                  currentCommonElement.put(atomInRange, new Integer(oldCommonElement));
            }
      }

      /**
       *  Makes a ring aromatic
       *
       *@param  ring  The ring to be made aromatic
       */
01556       private void makeRingAromatic(IRing ring)
      {
            Iterator atoms = ring.atoms();
            while (atoms.hasNext()) {
                  ((IAtom)atoms.next()).setFlag(CDKConstants.ISAROMATIC, true);
            }
            Iterator bonds = ring.bonds();
            while (bonds.hasNext()) {
                  ((IBond)bonds.next()).setFlag(CDKConstants.ISAROMATIC, true);
            }
      }


      /**
       *  manages all actions that will be invoked when a mouse button is clicked
       *
       *@param  e  MouseEvent object
       */
01574       public void mouseClicked(MouseEvent e)
      {
            // logger.debug("Mouse clicked");
      }


      /**
       *  manages all actions that will be invoked when a mouse enters a component
       *
       *@param  e  MouseEvent object
       */
01585       public void mouseEntered(MouseEvent e)
      {
            // logger.debug("Mouse entered");
      }


      /**
       *  manages all actions that will be invoked when a mouse exits a component
       *
       *@param  e  MouseEvent object
       */
01596       public void mouseExited(MouseEvent e)
      {
            // logger.debug("Mouse exited");
      }


      /**
       *  manages all actions that will be invoked when a key is released
       *
       *@param  e  MouseEvent object
       */
01607       public void keyReleased(KeyEvent e)
      {
            logger.debug("Key released");
      }


      /**
       *  manages all actions that will be invoked when a key is typed
       *
       *@param  e  MouseEvent object
       */
01618       public void keyTyped(KeyEvent e)
      {
            try{
                  logger.debug("Key typed");
                  if(r2dm.getHighlightedAtom()!=null){
                        IsotopeFactory ifa=IsotopeFactory.getInstance(r2dm.getHighlightedAtom().getBuilder());
                        IIsotope iso=ifa.getMajorIsotope(e.getKeyChar());
                        if(iso!=null)
                              r2dm.getHighlightedAtom().setSymbol(e.getKeyChar()+"");
                  }
            }catch(Exception ex){
                  logger.debug("Exception "+ex.getMessage()+" in keyPressed in AbstractController");
            }
      }


      /**
       *  manages all actions that will be invoked when a key is pressed
       *
       *@param  e  MouseEvent object
       */
01639       public void keyPressed(KeyEvent e)
      {
            logger.debug("Key pressed");
      }


      /*
       *  Start of private methods
       */
      /**
       *  Updates an array of atoms with respect to its hydrogen count
       *
       *@param  container  The AtomContainer to work on
       *@param  atoms       The Atoms to update
       */
01654       private void updateAtoms(IAtomContainer container, java.util.Iterator atoms)
      {
            while (atoms.hasNext())
            {
                  updateAtom(container, (IAtom)atoms.next());
            }
      }


      /**
       *  Updates an atom with respect to its hydrogen count
       *
       *@param  container  The AtomContainer to work on
       *@param  atom       The Atom to update
       */
01669       public void updateAtom(IAtomContainer container, IAtom atom)
      {
            if (c2dm.getAutoUpdateImplicitHydrogens())
            {
                  atom.setHydrogenCount(0);
                  try
                  {
                        hydrogenAdder.addImplicitHydrogensToSatisfyValency(container, atom);
                  } catch (Exception exception)
                  {
                        logger.error(exception.getMessage());
                        logger.debug(exception);
                  }
            }
      }


      /**
       *  No idea what this does
       *
       *@param  angle  Some kind of angle
       *@return        Don't know what
       */
01692       private double snapAngle(double angle)
      {
            double div = (Math.PI / 180) * c2dm.getSnapAngle();
            return (Math.rint(angle / div)) * div;
      }


      /**
       *  Gets the chemObjectInRange attribute of the Controller2D object
       *
       *@param  X  Current mouse x
       *@param  Y  Current mouse x
       *@return    The chemObjectInRange value
       */
01706       public IChemObject getChemObjectInRange(int X, int Y)
      {
            IChemObject objectInRange = getAtomInRange(X, Y);
            if (objectInRange != null)
            {
                  // logger.debug("Returning nearest Atom: " + objectInRange);
                  return objectInRange;
            }
            objectInRange = getBondInRange(X, Y);
            if (objectInRange != null)
            {
                  // logger.debug("Returning nearest Bond: " + objectInRange);
                  return objectInRange;
            }
            objectInRange = getReactionInRange(X, Y);
            if (objectInRange != null)
            {
                  // logger.debug("Returning nearest Reaction: " + objectInRange);
                  return objectInRange;
            }
            /*
             *  chemModel covers whole of editing window, and if nothing
             *  more interesting is near, then them model is in range.
             */
            // logger.debug("Returning nearest ChemModel: " + chemModel);
            return chemModel;
      }


      /**
       *  Returns an Atom if it is in a certain range of the given point. Used to
       *  highlight an atom that is near the cursor. <p>
       *
       *  <b>Important: the coordinates must be given in world coordinates and not in
       *  screen coordinates!
       *
       *@param  X  The x world coordinate of the point
       *@param  Y  The y world coordinate of the point
       *@return    An Atom if it is in a certain range of the given point
       */
01746       private IAtom getAtomInRange(int X, int Y)
      {
            return getAtomInRange(X,Y,null);
      }
      
      
      /**
       *  Returns an Atom if it is in a certain range of the given point. Used to
       *  highlight an atom that is near the cursor. <p>
       *
       *  <b>Important: the coordinates must be given in world coordinates and not in
       *  screen coordinates!
       *
       *@param  X  The x world coordinate of the point
       *@param  Y  The y world coordinate of the point
       *@return    An Atom if it is in a certain range of the given point
       */
01763       private IAtom getAtomInRange(int X, int Y, IAtom ignore)
      {
            double highlightRadius = r2dm.getHighlightRadius();
            IAtom closestAtom = GeometryTools.getClosestAtom(X, Y, chemModel, ignore, r2dm.getRenderingCoordinates());
            if (closestAtom != null)
            {
                  //logger.debug("getAtomInRange(): An atom is near");
                  if (!(Math.sqrt(Math.pow(r2dm.getRenderingCoordinate(closestAtom).x - X, 2) +
                              Math.pow(r2dm.getRenderingCoordinate(closestAtom).y - Y, 2)) < highlightRadius))
                  {
                        closestAtom = null;
                  } else {
                        // we got a winner!
                        // set the associated AtomContainer, for use by JCP's Molecule Properties action
                // COMMENTED OUT: causes cloning trouble
/*                      closestAtom.setProperty(
                              SimpleController2D.MATCHING_ATOMCONTAINER,
                              ChemModelManipulator.getRelevantAtomContainer(chemModel, closestAtom)
                        );*/
                  }
            }
            return closestAtom;
      }

      private IAtomContainer getBondInRangeTemporaryAtomContainer = null;

      /**
       *  Returns a Bond if it is in a certain range of the given point. Used to
       *  highlight a bond that is near the cursor. <p>
       *
       *  <b>Important: the coordinates must be given in world coordinates and not in
       *  screen coordinates!
       *
       *@param  X  The x world coordinate of the point
       *@param  Y  The y world coordinate of the point
       *@return    An Atom if it is in a certain range of the given point
       */
01800       private IBond getBondInRange(int X, int Y) {
            if (getBondInRangeTemporaryAtomContainer == null) {
                  getBondInRangeTemporaryAtomContainer = chemModel.getBuilder().newAtomContainer();
            } else {
                  getBondInRangeTemporaryAtomContainer.removeAllElements();
            }
        double highlightRadius = r2dm.getHighlightRadius();
            Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
            while (atomCons.hasNext()) {
                  getBondInRangeTemporaryAtomContainer.add((IAtomContainer)atomCons.next());
            }
        if (getBondInRangeTemporaryAtomContainer.getBondCount() != 0) {
            IBond closestBond = GeometryTools.getClosestBond(X, Y, getBondInRangeTemporaryAtomContainer,r2dm.getRenderingCoordinates());
            if (closestBond == null)
            {
                  return null;
            }
            // logger.debug("closestBond  "+ closestBond);
            int[] coords = GeometryTools.distanceCalculator(
                        GeometryTools.getBondCoordinates(closestBond, r2dm.getRenderingCoordinates()), highlightRadius);
            int[] xCoords = {coords[0], coords[2], coords[4], coords[6]};
            int[] yCoords = {coords[1], coords[3], coords[5], coords[7]};
            if ((new Polygon(xCoords, yCoords, 4)).contains(new Point(X, Y)))
            {
                  return closestBond;
            }
        }
            return null;
      }

      abstract IReaction getReactionInRange(int X, int Y);

      /**
       *  Returns an AtomContainer that contains the atom or the the bond with its
       *  two atoms that are highlighted at the moment.
       *
       *@return    An AtomContainer containig the highlighted atom\atoms\bond
       */
01838        IAtomContainer getHighlighted()
      {
            IAtomContainer highlighted = chemModel.getBuilder().newAtomContainer();
            IAtom highlightedAtom = r2dm.getHighlightedAtom();
            IBond highlightedBond = r2dm.getHighlightedBond();
            if (highlightedAtom != null)
            {
                  highlighted.addAtom(highlightedAtom);
            } else if (highlightedBond != null)
            {
                  highlighted.addBond(highlightedBond);
                  for (int i = 0; i < highlightedBond.getAtomCount(); i++)
                  {
                        highlighted.addAtom(highlightedBond.getAtom(i));
                  }
            }
            logger.debug("sharedAtoms  ", highlighted);
            return highlighted;
      }


      /**
       *  Constructs a new Ring of a certain size that contains all the atoms and
       *  bonds of the given AtomContainer and is filled up with new Atoms and Bonds.
       *
       *@param  sharedAtoms  The AtomContainer containing the Atoms and bonds for the
       *      new Ring
       *@param  ringSize     The size (number of Atoms) the Ring will have
       *@param  symbol       The element symbol the new atoms will have
       *@return              The constructed Ring
       */
01869        IRing createAttachRing(IAtomContainer sharedAtoms, int ringSize, String symbol)
      {
            IRing newRing = sharedAtoms.getBuilder().newRing(ringSize);
            IAtom[] ringAtoms = new IAtom[ringSize];
            for (int i = 0; i < sharedAtoms.getAtomCount(); i++)
            {
                  ringAtoms[i] = sharedAtoms.getAtom(i);
            }
            for (int i = sharedAtoms.getAtomCount(); i < ringSize; i++)
            {
                  ringAtoms[i] = sharedAtoms.getBuilder().newAtom(symbol);
            }
            Iterator bonds = sharedAtoms.bonds();
            while (bonds.hasNext())
            {
                  newRing.addBond((IBond)bonds.next());
            }
            for (int i = sharedAtoms.getBondCount(); i < ringSize - 1; i++)
            {
                  newRing.addBond(sharedAtoms.getBuilder().newBond(ringAtoms[i], ringAtoms[i + 1], 1));
            }
            newRing.addBond(sharedAtoms.getBuilder().newBond(ringAtoms[ringSize - 1], ringAtoms[0], 1));
            newRing.setAtoms(ringAtoms);
            return newRing;
      }


      /**
       *  Searches all the atoms attached to the Atoms in the given AtomContainer and
       *  calculates the center point of them.
       *
       *@param  sharedAtoms  The Atoms the attached partners are searched of
       *@return              The Center Point of all the atoms found
       */
01903        Point2d getConnectedAtomsCenter(IAtomContainer sharedAtoms)
      {
            IAtom currentAtom;
            //IAtom[] conAtomsArray;
            IAtomContainer conAtoms = sharedAtoms.getBuilder().newAtomContainer();
            for (int i = 0; i < sharedAtoms.getAtomCount(); i++)
            {
                  currentAtom = sharedAtoms.getAtom(i);
                  conAtoms.addAtom(currentAtom);
                  IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, currentAtom);
                  java.util.Iterator atoms = atomCon.getConnectedAtomsList(currentAtom).iterator();
                  while (atoms.hasNext())
                  {
                        conAtoms.addAtom((IAtom)atoms.next());
                  }
            }
            return GeometryTools.get2DCenter(conAtoms,r2dm.getRenderingCoordinates());
      }


      /**
       *  Returns an AtomContainer with all the atoms and bonds that are inside a
       *  given polygon.
       *
       *@param  polygon  The given Polygon
       *@return          AtomContainer with all atoms and bonds inside the polygon
       */
01930        IAtomContainer getContainedAtoms(Polygon polygon)
      {
            IAtom currentAtom;
            IBond currentBond;
            IAtomContainer selectedPart = chemModel.getBuilder().newAtomContainer();
            Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
            while (atomCons.hasNext()) {
                  IAtomContainer atomCon = (IAtomContainer)atomCons.next();
                  for (int i = 0; i < atomCon.getAtomCount(); i++)
                  {
                        currentAtom = atomCon.getAtom(i);
                        logger.debug("Atom: ", currentAtom);
                        if (polygon.contains(new Point((int) ((Point2d)r2dm.getRenderingCoordinate(currentAtom)).x, (int) ((Point2d)r2dm.getRenderingCoordinate(currentAtom)).y)))
                        {
                              selectedPart.addAtom(currentAtom);
                        }
                  }
                  Iterator bonds = atomCon.bonds();
                  while (bonds.hasNext())
                  {
                        currentBond = (IBond)bonds.next();
                        for (int j = 0; j < selectedPart.getAtomCount(); j++)
                        {
                              currentAtom = selectedPart.getAtom(j);
                              if (selectedPart.contains(currentBond.getConnectedAtom(currentAtom)))
                              {
                                    selectedPart.addBond(currentBond);
                                    break;
                              }
                        }
                  }
            }
            return selectedPart;
      }


      /**
       *  This methods corrects for the zoom factor, and thus transforms screen
       *  coordinates back into world coordinates. IMPORTANT: even coords are taken
       *  as y coordinates, uneven as x coordinates.
       *
       *@param  coords  the array of coordinates to be used
       *@return         The worldCoordinates value
       */
01974       public int[] getWorldCoordinates(int[] coords)
      {
            int[] worldCoords = new int[coords.length];
            int coordCount = coords.length / 2;
            //logger.debug("coord.length: ", coords.length);
            int height = (int) (r2dm.getBackgroundDimension()).getHeight();
            for (int i = 0; i < coordCount; i++)
            {
                  worldCoords[i * 2] = (int) ((double) coords[i * 2] / r2dm.getZoomFactor());
                  worldCoords[i * 2 + 1] = (int) ((double) (height - coords[i * 2 + 1]) / r2dm.getZoomFactor());
                  if (logger.isDebugEnabled())
                  {
                        //logger.debug("getWorldCoord: " + coords[i * 2] + " -> " + worldCoords[i * 2]);
                        //logger.debug("getWorldCoord: " + coords[i * 2 + 1] + " -> " + worldCoords[i * 2 + 1]);
                  }
            }
            return worldCoords;
      }


      /**
       *  Adds a change listener to the list of listeners
       *
       *@param  listener  The listener added to the list
       */

02000       public void addCDKChangeListener(ICDKChangeListener listener)
      {
            listeners.add(listener);
      }


      /**
       *  Removes a change listener from the list of listeners
       *
       *@param  listener  The listener removed from the list
       */
02011       public void removeCDKChangeListener(ICDKChangeListener listener)
      {
            listeners.remove(listener);
      }


      /**
       *  Notifies registered listeners of certain changes that have occurred in this
       *  model.
       */
02021       public void fireChange()
      {
            EventObject event = new EventObject(this);
            for (int i = 0; i < listeners.size(); i++)
            {
                  ((ICDKChangeListener) listeners.get(i)).stateChanged(event);
            }
      }


      // ------------ CHEMICAL OPERATIONS -------------- //

      /**
       *  Highlight the nearest Atom or Bond. <p>
       *
       *  FIXME: this needs to be extended for other ChemObjects.
       *
       *@param  mouseX  x coordinate in world coordinates (not screen coordinates)
       *@param  mouseY  y coordinate in world coordinates (not screen coordinates)
       */
02041        void highlightNearestChemObject(int mouseX, int mouseY)
      {
            IChemObject objectInRange = getChemObjectInRange(mouseX, mouseY);
            if (objectInRange instanceof IAtom)
            {
                  r2dm.setHighlightedAtom((IAtom) objectInRange);
                  r2dm.setHighlightedBond(null);
            } else if (objectInRange instanceof IBond)
            {
                  r2dm.setHighlightedBond((IBond) objectInRange);
                  r2dm.setHighlightedAtom(null);
            } else
            {
                  r2dm.setHighlightedBond(null);
                  r2dm.setHighlightedAtom(null);
            }
      }


      /**
       *  Create a new bond. Possibly connecting the end point to the nearest Atom.
       *  <p>
       *
       *  All coordinates are world coordinates.
       *
       *@param  startX  Start X coordinate of the new bond
       *@param  startY  Start Y coordinate of the new bond
       *@param  endX  End X coordinate of the new bond
       *@param  endY  End Y coordinate of the new bond
       */
02071        void createNewBond(int startX, int startY, int endX, int endY)
      {

      }


      /**
       *  Draws a proposed bond, i.e. shows the bond direction
       *  during dragging of the mouse
       *
       *@param  startX  Start X coordinate of the proposed bond
       *@param  startY  Start Y coordinate of the proposed bond
       *@param  mouseX  Current X mouse coordinate
       *@param  mouseY  Current Y mouse coordinate
       */
02086        void drawProposedBond(int startX, int startY, int mouseX, int mouseY)
      {
            logger.debug("Drawing proposed bond...");
            int endX = 0;
            int endY = 0;
            double pointerVectorLength = c2dm.getBondPointerLength();
            double angle = 0;
            IAtom atomInRange;

            angle = GeometryTools.getAngle(startX - mouseX, startY - mouseY);
            if (c2dm.getSnapToGridAngle())
            {
                  angle = snapAngle(angle);
            }
            atomInRange = getAtomInRange(mouseX, mouseY);
            if (atomInRange != null)
            {
                  endX = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).x;
                  endY = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).y;
            } else
            {
                  endX = startX - (int) (Math.cos(angle) * pointerVectorLength);
                  endY = startY - (int) (Math.sin(angle) * pointerVectorLength);
            }
            logger.debug("End point: " + endX + ", " + endY);
            logger.debug("Start point: " + startX + ", " + startY);
            r2dm.setPointerVectorEnd(new Point(endX, endY));
      }


      /**
       *  Selects a rectangular area on the screen 
       *
       *@param  startX  Start x coordinate
       *@param  startY  Start y coordinate
       *@param  mouseX  Current x mouse position
       *@param  mouseY  Current y mouse position
       */
02124        void selectRectangularArea(int startX, int startY, int mouseX, int mouseY)
      {
            int[] xPoints = {startX, startX, mouseX, mouseX};
            int[] yPoints = {startY, mouseY, mouseY, startY};
            r2dm.setSelectRect(new Polygon(xPoints, yPoints, 4));
      }


      /**
       *  Move an Atom by the specified change in coordinates.
       *
       *@param  deltaX  change in x direction
       *@param  deltaY  change in y direction
       */
02138        void moveSelectedAtomsWith(int deltaX, int deltaY)
      {
            IAtomContainer container = r2dm.getSelectedPart();
            if (container != null)
            {
                  // only move selected atoms if count > 0
                  java.util.Iterator atoms = container.atoms();
                  while (atoms.hasNext())
                  {
                        IAtom atom = (IAtom)atoms.next();
                        atom.setNotification(false);
                        atom.getPoint2d().x += deltaX;
                        atom.getPoint2d().y += deltaY;
                        atom.setNotification(true);
                        ((Point2d)r2dm.getRenderingCoordinate(atom)).x+=deltaX;
                        ((Point2d)r2dm.getRenderingCoordinate(atom)).y+=deltaY;
                  }
                  r2dm.getSelectedPart().notifyChanged();
            }
      }
       
       /**
       * This updates the coordinates in the point2ds of the atoms with the renderingcoordinates in r2dm. This should be called
       * after a change of the structure (e. g. adding atoms), since we cannot and do not need to preserve original coordinates after this.
       */
02163       private void updateMoleculeCoordinates(){
            Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
            while (atomCons.hasNext()) {
                  IAtomContainer atomCon = (IAtomContainer)atomCons.next();
                  for (int i = 0; i < atomCon.getAtomCount(); i++)
                  {
                        IAtom currentAtom = atomCon.getAtom(i);
                        if(r2dm.getRenderingCoordinate(currentAtom)!=null){
                              currentAtom.setPoint2d(new Point2d((Point2d)r2dm.getRenderingCoordinate(currentAtom)));
                        }
                  }
            }
       }


      /**
       *  Selects the nearest item on the screen next to the 
       *  mouse pointer, if none is selected yet
       *
       *  @param  mouseX  The current X coordinate of the mouse
       *  @param  mouseY  The current Y coordinate of the mouse
       */
02185        void selectNearestChemObjectIfNoneSelected(int mouseX, int mouseY)
      {
            IAtomContainer container = r2dm.getSelectedPart();
            if (container == null || (container.getAtomCount() == 0))
            {
                  // if no atoms are selected, then temporarily select nearest
                  // to make sure to original state is reached again when the
                  // mouse is released, the draggingSelected boolean is set
                  logger.warn("No atoms selected: temporarily selecting nearest atom/bond");
                  draggingSelected = false;
                  IAtomContainer selected = chemModel.getBuilder().newAtomContainer();
                  IAtom atomInRange = getAtomInRange(mouseX, mouseY);
                  if (atomInRange != null)
                  {
                        selected.addAtom(atomInRange);
                        r2dm.setSelectedPart(selected);
                  } else
                  {
                        IBond bondInRange = getBondInRange(mouseX, mouseY);
                        // because only atoms are dragged, select the atoms
                        // in the bond, instead of the bond itself
                        if (bondInRange != null)
                        {
                              java.util.Iterator atoms = bondInRange.atoms();
                              while (atoms.hasNext())
                              {
                                    selected.addAtom((IAtom)atoms.next());
                              }
                              r2dm.setSelectedPart(selected);
                        }
                  }
                  logger.debug("Selected: ", selected);
                  fireChange();
            }
      }


      /**
       * Centers an atom on a given background dimension
       *
       * @param  atom  The Atom to be centered
       */
02227        void centerAtom(IAtom atom, IChemModel chemModel)
      {
             double smallestx=Integer.MAX_VALUE;
             double largestx=Integer.MIN_VALUE;
             double smallesty=Integer.MAX_VALUE;
             double largesty=Integer.MIN_VALUE;
             Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
             while (atomCons.hasNext()) {
                   IAtomContainer atomCon = (IAtomContainer)atomCons.next();
                   for(int i=0;i<atomCon.getAtomCount();i++){
                         if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x<smallestx)
                               smallestx=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x;
                         if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y<smallesty)
                               smallesty=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y;
                         if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x>largestx)
                               largestx=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x;
                         if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y>largesty)
                               largesty=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y;
                   }
             }
             int xstretch=((int)(largestx-smallestx))+20;
             int ystretch=((int)(largesty-smallesty))+20;
             if(xstretch<r2dm.getBackgroundDimension().width)
                   xstretch=r2dm.getBackgroundDimension().width;
             if(ystretch<r2dm.getBackgroundDimension().height)
                   ystretch=r2dm.getBackgroundDimension().height;
             r2dm.setBackgroundDimension(new Dimension(xstretch,ystretch));
            if (atom == null)
            {
                  return;
            }
            if (((Point2d)r2dm.getRenderingCoordinate(atom)).x < 0 && shiftX > ((Point2d)r2dm.getRenderingCoordinate(atom)).x - 10)
            {
                  shiftX = ((Point2d)r2dm.getRenderingCoordinate(atom)).x - 10;
            }
            if (((Point2d)r2dm.getRenderingCoordinate(atom)).x > r2dm.getBackgroundDimension().getWidth() && shiftX < ((Point2d)r2dm.getRenderingCoordinate(atom)).x - r2dm.getBackgroundDimension().getWidth() + 10)
            {
                  shiftX = ((Point2d)r2dm.getRenderingCoordinate(atom)).x - r2dm.getBackgroundDimension().getWidth() + 10;
            }
            if (((Point2d)r2dm.getRenderingCoordinate(atom)).y < 0 && shiftY > ((Point2d)r2dm.getRenderingCoordinate(atom)).y - 10)
            {
                  shiftY = ((Point2d)r2dm.getRenderingCoordinate(atom)).y - 10;
            }
            if (((Point2d)r2dm.getRenderingCoordinate(atom)).y > r2dm.getBackgroundDimension().getHeight() && shiftY < ((Point2d)r2dm.getRenderingCoordinate(atom)).y - r2dm.getBackgroundDimension().getHeight() + 10)
            {
                  shiftY = ((Point2d)r2dm.getRenderingCoordinate(atom)).y - r2dm.getBackgroundDimension().getHeight() + 10;
            }
      }
      

      void handleMapping(boolean wasDragged, Renderer2DModel r2dm)
      {
            logger.debug("Should make new mapping...");
            if (wasDragged)
            {
                  int endX = r2dm.getPointerVectorEnd().x;
                  int endY = r2dm.getPointerVectorEnd().y;
                  IAtom mappedToAtom = getAtomInRange(endX, endY);
                  if (mappedToAtom != null)
                  {
                        int startX = r2dm.getPointerVectorStart().x;
                        int startY = r2dm.getPointerVectorStart().y;
                        IAtom mappedFromAtom = getAtomInRange(startX, startY);
                        if (mappedFromAtom != null)
                        {
                              IMapping mapping = mappedFromAtom.getBuilder().newMapping(mappedFromAtom, mappedToAtom);
                              logger.debug("Created mapping: ", mapping);
                              logger.debug("  between ", mappedFromAtom);
                              logger.debug("  and ", mappedToAtom);
                              // ok, now figure out if they are in one reaction
                              IReaction reaction1 = ChemModelManipulator.getRelevantReaction(chemModel, mappedFromAtom);
                              IReaction reaction2 = ChemModelManipulator.getRelevantReaction(chemModel, mappedToAtom);
                              if (reaction1 != null && reaction2 != null && reaction1 == reaction2)
                              {
                                    logger.debug("Adding mapping to reaction: ", reaction1.getID());
                                    ((IReaction)reaction1).addMapping(mapping);
                              } else
                              {
                                    logger.warn("Reactions do not match, or one or both are reactions are null");
                              }
                        } else
                        {
                              logger.debug("Dragging did not start in atom...");
                        }
                  } else
                  {
                        logger.debug("Dragging did not end in atom...");
                  }
            } else
            {
                  logger.debug("Not dragged in mapping mode");
            }
      }
      
      abstract IReaction getRelevantReaction(IChemModel model, IAtom atom);


      public IChemModel getChemModel() {
            return chemModel;
      }

      public void setChemModel(IChemModel chemModel) {
            this.chemModel = chemModel;
      }

      public void setUndoRedoHandler(IUndoRedoHandler undoRedoHandler) {
            this.undoRedoHandler = undoRedoHandler;
      }

      public HashMap getFuncgroupsmap() {
            return funcgroupsmap;
      }

      public void setFuncgroupsmap(HashMap funcgroupsmap) {
            this.funcgroupsmap = funcgroupsmap;
      }
      
      static class EnterElementOrGroupDialog extends JDialog implements ActionListener {
            
          private static EnterElementOrGroupDialog dialog;
          private static String value = "";
          private JComboBox list;

          /**
           * Set up and show the dialog.  The first Component argument
           * determines which frame the dialog depends on; it should be
           * a component in the dialog's controlling frame. The second
           * Component argument should be null if you want the dialog
           * to come up with its left corner in the center of the screen;
           * otherwise, it should be the component on top of which the
           * dialog should appear.
           */
          public static String showDialog(Component frameComp,
                                          Component locationComp,
                                          String labelText,
                                          String title,
                                          String[] possibleValues,
                                          String initialValue,
                                          String longValue) {
              Frame frame = JOptionPane.getFrameForComponent(frameComp);
              dialog = new EnterElementOrGroupDialog(frame,
                                      locationComp,
                                      labelText,
                                      title,
                                      possibleValues,
                                      initialValue,
                                      longValue);
              dialog.setVisible(true);
              return value;
          }

          private EnterElementOrGroupDialog(Frame frame,
                             Component locationComp,
                             String labelText,
                             String title,
                             Object[] data,
                             String initialValue,
                             String longValue) {
              super(frame, title, true);

              //Create and initialize the buttons.
              JButton cancelButton = new JButton("Cancel");
              cancelButton.addActionListener(this);
              //
              final JButton setButton = new JButton("Ok");
              setButton.setActionCommand("Set");
              setButton.addActionListener(this);
              getRootPane().setDefaultButton(setButton);

              //main part of the dialog
              list = new JComboBox(data);
              list.setEditable(true);
              JPanel listPane = new JPanel();
              listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
              JLabel label = new JLabel(labelText);
              label.setLabelFor(list);
              listPane.add(label);
              listPane.add(Box.createRigidArea(new Dimension(0,5)));
              listPane.add(list);
              listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

              //Lay out the buttons from left to right.
              JPanel buttonPane = new JPanel();
              buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
              buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
              buttonPane.add(Box.createHorizontalGlue());
              buttonPane.add(cancelButton);
              buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
              buttonPane.add(setButton);

              //Put everything together, using the content pane's BorderLayout.
              Container contentPane = getContentPane();
              contentPane.add(listPane, BorderLayout.CENTER);
              contentPane.add(buttonPane, BorderLayout.PAGE_END);

              //Initialize values.
              pack();
              setLocationRelativeTo(locationComp);
          }

          //Handle clicks on the Set and Cancel buttons.
          public void actionPerformed(ActionEvent e) {
              if ("Set".equals(e.getActionCommand())) {
                  EnterElementOrGroupDialog.value = (String)(list.getSelectedItem());
              }
              if(e.getActionCommand().equals("Cancel")){
                  EnterElementOrGroupDialog.value="";
              }
              EnterElementOrGroupDialog.dialog.setVisible(false);
          }
      }

}


Generated by  Doxygen 1.6.0   Back to index