~ubuntu-branches/ubuntu/maverick/cdk/maverick

« back to all changes in this revision

Viewing changes to src/org/openscience/cdk/controller/AbstractController2D.java

  • Committer: Bazaar Package Importer
  • Author(s): Paul Cager
  • Date: 2008-04-09 21:17:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080409211753-46lmjw5z8mx5pd8d
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $Revision: 8753 $ $Author: shk3 $ $Date: 2007-08-28 23:40:30 +0200 (Tue, 28 Aug 2007) $
 
2
 *
 
3
 *  Copyright (C) 2005-2007  Christoph Steinbeck <steinbeck@users.sf.net>
 
4
 *
 
5
 *  Contact: cdk-devel@lists.sourceforge.net
 
6
 *
 
7
 *  This program is free software; you can redistribute it and/or
 
8
 *  modify it under the terms of the GNU Lesser General Public License
 
9
 *  as published by the Free Software Foundation; either version 2.1
 
10
 *  of the License, or (at your option) any later version.
 
11
 *  All I ask is that proper credit is given for my work, which includes
 
12
 *  - but is not limited to - adding the above copyright notice to the beginning
 
13
 *  of your source code files, and to any copyright notice that you may distribute
 
14
 *  with programs based on this work.
 
15
 *
 
16
 *  This program is distributed in the hope that it will be useful,
 
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 *  GNU Lesser General Public License for more details.
 
20
 *
 
21
 *  You should have received a copy of the GNU Lesser General Public License
 
22
 *  along with this program; if not, write to the Free Software
 
23
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
24
 */
 
25
package org.openscience.cdk.controller;
 
26
 
 
27
import java.awt.BorderLayout;
 
28
import java.awt.Color;
 
29
import java.awt.Component;
 
30
import java.awt.Container;
 
31
import java.awt.Dimension;
 
32
import java.awt.Frame;
 
33
import java.awt.Point;
 
34
import java.awt.Polygon;
 
35
import java.awt.Shape;
 
36
import java.awt.event.ActionEvent;
 
37
import java.awt.event.ActionListener;
 
38
import java.awt.event.KeyEvent;
 
39
import java.awt.event.KeyListener;
 
40
import java.awt.event.MouseEvent;
 
41
import java.awt.event.MouseListener;
 
42
import java.awt.event.MouseMotionListener;
 
43
import java.awt.geom.AffineTransform;
 
44
import java.awt.geom.PathIterator;
 
45
import java.util.ArrayList;
 
46
import java.util.EventObject;
 
47
import java.util.HashMap;
 
48
import java.util.Iterator;
 
49
import java.util.List;
 
50
import java.util.Vector;
 
51
 
 
52
import javax.swing.BorderFactory;
 
53
import javax.swing.Box;
 
54
import javax.swing.BoxLayout;
 
55
import javax.swing.JButton;
 
56
import javax.swing.JComboBox;
 
57
import javax.swing.JDialog;
 
58
import javax.swing.JLabel;
 
59
import javax.swing.JOptionPane;
 
60
import javax.swing.JPanel;
 
61
import javax.swing.undo.UndoableEdit;
 
62
import javax.vecmath.Point2d;
 
63
import javax.vecmath.Vector2d;
 
64
 
 
65
import org.openscience.cdk.CDKConstants;
 
66
import org.openscience.cdk.applications.undoredo.AddAtomsAndBondsEdit;
 
67
import org.openscience.cdk.applications.undoredo.AddFuncGroupEdit;
 
68
import org.openscience.cdk.applications.undoredo.AdjustBondOrdersEdit;
 
69
import org.openscience.cdk.applications.undoredo.ChangeAtomSymbolEdit;
 
70
import org.openscience.cdk.applications.undoredo.ChangeChargeEdit;
 
71
import org.openscience.cdk.applications.undoredo.IUndoRedoHandler;
 
72
import org.openscience.cdk.applications.undoredo.MergeMoleculesEdit;
 
73
import org.openscience.cdk.applications.undoredo.MoveAtomEdit;
 
74
import org.openscience.cdk.applications.undoredo.RemoveAtomsAndBondsEdit;
 
75
import org.openscience.cdk.config.IsotopeFactory;
 
76
import org.openscience.cdk.event.ICDKChangeListener;
 
77
import org.openscience.cdk.geometry.BondTools;
 
78
import org.openscience.cdk.geometry.GeometryTools;
 
79
import org.openscience.cdk.graph.ConnectivityChecker;
 
80
import org.openscience.cdk.interfaces.IAtom;
 
81
import org.openscience.cdk.interfaces.IAtomContainer;
 
82
import org.openscience.cdk.interfaces.IBond;
 
83
import org.openscience.cdk.interfaces.IChemModel;
 
84
import org.openscience.cdk.interfaces.IChemObject;
 
85
import org.openscience.cdk.interfaces.IElectronContainer;
 
86
import org.openscience.cdk.interfaces.IIsotope;
 
87
import org.openscience.cdk.interfaces.IMapping;
 
88
import org.openscience.cdk.interfaces.IMolecule;
 
89
import org.openscience.cdk.interfaces.IMoleculeSet;
 
90
import org.openscience.cdk.interfaces.IReaction;
 
91
import org.openscience.cdk.interfaces.IRing;
 
92
import org.openscience.cdk.layout.AtomPlacer;
 
93
import org.openscience.cdk.layout.RingPlacer;
 
94
import org.openscience.cdk.renderer.Renderer2DModel;
 
95
import org.openscience.cdk.tools.HydrogenAdder;
 
96
import org.openscience.cdk.tools.LoggingTool;
 
97
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
 
98
import org.openscience.cdk.tools.manipulator.ChemModelManipulator;
 
99
 
 
100
/**
 
101
 * Class that acts on MouseEvents and KeyEvents.
 
102
 *
 
103
 * @author         steinbeck
 
104
 * @author         egonw
 
105
 * @cdk.created    2005-05-02
 
106
 * @cdk.keyword    mouse events
 
107
 * @cdk.require    java1.4+
 
108
 * @cdk.module     control
 
109
 * @cdk.bug        1562511
 
110
 */
 
111
abstract class AbstractController2D implements MouseMotionListener, MouseListener, KeyListener
 
112
{
 
113
 
 
114
        private final static int DRAG_UNSET = 0;
 
115
        private final static int DRAG_MOVING_SELECTED = 1;
 
116
        private final static int DRAG_DRAWING_PROPOSED_BOND = 2;
 
117
        private final static int DRAG_DRAWING_PROPOSED_RING = 3;
 
118
        private final static int DRAG_MAKING_SQUARE_SELECTION = 4;
 
119
        private final static int DRAG_MAKING_LASSO_SELECTION = 5;
 
120
        private final static int DRAG_DRAWING_PROPOSED_ATOMATOMMAP = 6;
 
121
        private final static int DRAG_ROTATE = 7;
 
122
        
 
123
        protected Vector lastAction=null;
 
124
        protected JButton moveButton=null;
 
125
        
 
126
        protected IChemModel chemModel;
 
127
        
 
128
        Renderer2DModel r2dm;
 
129
        Controller2DModel c2dm;
 
130
        boolean wasDragged = false;
 
131
        boolean isUndoableChange = false;
 
132
 
 
133
        private Vector listeners = new Vector();
 
134
 
 
135
        private LoggingTool logger;
 
136
 
 
137
        private int prevDragCoordX = 0;
 
138
        private int prevDragCoordY = 0;
 
139
        private boolean draggingSelected = true;
 
140
 
 
141
        private int dragMode = DRAG_UNSET;
 
142
 
 
143
        private Vector commonElements;
 
144
        private HashMap currentCommonElement = new HashMap();
 
145
        IAtom lastAtomInRange = null;
 
146
        private double shiftX = 0;
 
147
        private double shiftY = 0;
 
148
        double moveoldX;
 
149
        double moveoldY;
 
150
        private IUndoRedoHandler undoRedoHandler;
 
151
        
 
152
        private HashMap funcgroupsmap=new HashMap();
 
153
        
 
154
 
 
155
        // Helper classes
 
156
        HydrogenAdder hydrogenAdder = new HydrogenAdder("org.openscience.cdk.tools.ValencyChecker");
 
157
 
 
158
 
 
159
        AbstractController2D()
 
160
        {
 
161
                logger = new LoggingTool(this);
 
162
 
 
163
        }
 
164
 
 
165
        AbstractController2D(Controller2DModel c2dm)
 
166
        {
 
167
                this();
 
168
                this.c2dm = c2dm;
 
169
                commonElements = new Vector();
 
170
                String[] elements = c2dm.getCommonElements();
 
171
                for (int i = 0; i < elements.length; i++)
 
172
                {
 
173
                        commonElements.add(elements[i]);
 
174
                }
 
175
 
 
176
        }
 
177
 
 
178
        AbstractController2D(Renderer2DModel r2dm, Controller2DModel c2dm)
 
179
        {
 
180
                
 
181
                this(c2dm);
 
182
                this.r2dm = r2dm;
 
183
        }
 
184
 
 
185
        
 
186
        
 
187
        /**
 
188
         *  Gets the controller2DModel attribute of the Controller2D object
 
189
         *
 
190
         *@return    The controller2DModel value
 
191
         */
 
192
        public Controller2DModel getController2DModel()
 
193
        {
 
194
                return c2dm;
 
195
        }
 
196
 
 
197
 
 
198
        /**
 
199
         *  Gets the undoableChange attribute of the Controller2D object
 
200
         *
 
201
         *@return    The undoableChange value
 
202
         */
 
203
        public boolean isUndoableChange()
 
204
        {
 
205
                return isUndoableChange;
 
206
        }
 
207
 
 
208
 
 
209
        /**
 
210
         *  Sets the undoableChange attribute of the Controller2D object
 
211
         *
 
212
         *@param  isUndoable  The new undoableChange value
 
213
         */
 
214
        public void setUndoableChange(boolean isUndoable)
 
215
        {
 
216
                this.isUndoableChange = isUndoable;
 
217
        }
 
218
 
 
219
 
 
220
        /**
 
221
         *  Sets the controller2DModel attribute of the Controller2D object
 
222
         *
 
223
         *@param  model  The new controller2DModel value
 
224
         */
 
225
        public void setController2DModel(Controller2DModel model)
 
226
        {
 
227
                this.c2dm = model;
 
228
        }
 
229
 
 
230
 
 
231
        /**
 
232
         *  Manages all actions that will be invoked when the mouse is moved.
 
233
         *
 
234
         *@param  event  MouseEvent object
 
235
         */
 
236
        public void mouseMoved(MouseEvent event)
 
237
        {
 
238
                int[] screenCoords = {event.getX(), event.getY()};
 
239
                int[] mouseCoords = getWorldCoordinates(screenCoords);
 
240
                int mouseX = mouseCoords[0];
 
241
                int mouseY = mouseCoords[1];
 
242
                highlightNearestChemObject(mouseX, mouseY);
 
243
                //this is the rotate feature
 
244
                if(c2dm.isMovingAllowed() && r2dm.getSelectedPart()!=null && r2dm.getHighlightedAtom()==null && r2dm.getHighlightedBond()==null && c2dm.getDrawMode() == Controller2DModel.LASSO){
 
245
                        double xmin=Double.MAX_VALUE;
 
246
                        double xmax=Double.MIN_VALUE;
 
247
                        double ymin=Double.MAX_VALUE;
 
248
                        double ymax=Double.MIN_VALUE;
 
249
                        for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++){
 
250
                                if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x>xmax)
 
251
                                        xmax=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x;
 
252
                                if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y>ymax)
 
253
                                        ymax=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y;
 
254
                                if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x<xmin)
 
255
                                        xmin=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x;
 
256
                                if(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y<ymin)
 
257
                                        ymin=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y;
 
258
                        }
 
259
                        if(mouseCoords[0]>xmin && mouseCoords[0]<xmax && mouseCoords[1]>ymin && mouseCoords[1]<ymax){
 
260
                                //ok, we want to rotate
 
261
                                r2dm.setRotateCenter(xmin+(xmax-xmin)/2,ymin+(ymax-ymin)/2);
 
262
                                r2dm.setRotateRadius(Math.min((xmax-xmin)/4,(ymax-ymin)/4));
 
263
                        }
 
264
                }else{
 
265
                        //no rotation
 
266
                        r2dm.setRotateRadius(0);
 
267
                }
 
268
        }
 
269
 
 
270
 
 
271
        /**
 
272
         *  Manages all actions that will be invoked when the mouse is dragged.
 
273
         *
 
274
         *@param  event  MouseEvent object
 
275
         */
 
276
        public void mouseDragged(MouseEvent event)
 
277
        {
 
278
                isUndoableChange = false;
 
279
                logger.debug("MouseDragged Event Props: mode=", c2dm.getDrawModeString());
 
280
                if (logger.isDebugEnabled())
 
281
                {
 
282
                        logger.debug("   trigger=" + event.isPopupTrigger() +
 
283
                        /*
 
284
                         *  ", Button number: " + event.getButton() +
 
285
                         */
 
286
                                        ", Click count: " + event.getClickCount());
 
287
                }
 
288
 
 
289
                int[] screenCoords = {event.getX(), event.getY()};
 
290
                int[] mouseCoords = getWorldCoordinates(screenCoords);
 
291
                int mouseX = mouseCoords[0];
 
292
                int mouseY = mouseCoords[1];
 
293
 
 
294
                if (!wasDragged)
 
295
                {
 
296
                        prevDragCoordX = mouseX;
 
297
                        prevDragCoordY = mouseY;
 
298
                        wasDragged = true;
 
299
                }
 
300
 
 
301
                if (dragMode == DRAG_DRAWING_PROPOSED_BOND)
 
302
                {
 
303
                        int startX = r2dm.getPointerVectorStart().x;
 
304
                        int startY = r2dm.getPointerVectorStart().y;
 
305
                        highlightNearestChemObject(mouseX, mouseY);
 
306
                        drawProposedBond(startX, startY, mouseX, mouseY);
 
307
                } else if (dragMode == DRAG_MAKING_SQUARE_SELECTION)
 
308
                {
 
309
                        int startX = r2dm.getPointerVectorStart().x;
 
310
                        int startY = r2dm.getPointerVectorStart().y;
 
311
                        selectRectangularArea(startX, startY, mouseX, mouseY);
 
312
                } else if (dragMode == DRAG_DRAWING_PROPOSED_RING)
 
313
                {
 
314
                        int endX = 0;
 
315
                        int endY = 0;
 
316
                        double angle = 0;
 
317
                        double pointerVectorLength = c2dm.getRingPointerLength();
 
318
                        Point2d center = GeometryTools.get2DCenter(getHighlighted(),r2dm.getRenderingCoordinates());
 
319
                        r2dm.setPointerVectorStart(new Point((int) center.x, (int) center.y));
 
320
                        angle = GeometryTools.getAngle(center.x - mouseX, center.y - mouseY);
 
321
                        endX = (int) center.x - (int) (Math.cos(angle) * pointerVectorLength);
 
322
                        endY = (int) center.y - (int) (Math.sin(angle) * pointerVectorLength);
 
323
                        r2dm.setPointerVectorEnd(new Point(endX, endY));
 
324
                } else if (dragMode == DRAG_MAKING_LASSO_SELECTION)
 
325
                {
 
326
                        /*
 
327
                         *  Draw polygon in screencoordinates, convert them
 
328
                         *  to world coordinates when mouse released
 
329
                         */
 
330
                        r2dm.addLassoPoint(new Point(event.getX(), event.getY()));
 
331
                } else if (dragMode == DRAG_MOVING_SELECTED)
 
332
                {
 
333
                        // all these are in model coordinates
 
334
                        logger.debug("Dragging selected atoms");
 
335
                        int deltaX = mouseX - prevDragCoordX;
 
336
                        int deltaY = mouseY - prevDragCoordY;
 
337
                        moveSelectedAtomsWith(deltaX, deltaY);
 
338
                        IAtomContainer selected=r2dm.getSelectedPart();
 
339
                        r2dm.getMerge().clear();
 
340
                        for(int i=0;i<selected.getAtomCount();i++){
 
341
                                IAtom inrange=getAtomInRange((int)((Point2d)r2dm.getRenderingCoordinate(selected.getAtom(i))).x, (int)((Point2d)r2dm.getRenderingCoordinate(selected.getAtom(i))).y, selected.getAtom(i));
 
342
                                if(inrange!=null && inrange!=selected.getAtom(i)){
 
343
                                        r2dm.getMerge().put(selected.getAtom(i),inrange);
 
344
                                }
 
345
                        }
 
346
                        /*
 
347
                         *  PRESERVE THIS. This notifies the
 
348
                         *  the listener responsible for
 
349
                         *  undo and redo storage that it
 
350
                         *  should not store this change
 
351
                         */
 
352
            isUndoableChange = false;
 
353
                        fireChange();
 
354
                } else if(dragMode==DRAG_ROTATE){
 
355
                        double angle=BondTools.giveAngleBothMethods(new Point2d(r2dm.getRotateCenter()[0],r2dm.getRotateCenter()[1]),new Point2d(prevDragCoordX,prevDragCoordY),new Point2d(mouseX, mouseY),true);
 
356
                        Polygon polygon=new Polygon();
 
357
                        for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++) {
 
358
                                polygon.addPoint((int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).x*1000),(int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(i))).y*1000));
 
359
                        }
 
360
                        polygon.addPoint((int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x*1000),(int)(((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y*1000));
 
361
                        AffineTransform at=AffineTransform.getRotateInstance(angle,r2dm.getRotateCenter()[0]*1000,r2dm.getRotateCenter()[1]*1000);
 
362
                        Shape transformedpolygon=at.createTransformedShape(polygon);
 
363
                        PathIterator pa=transformedpolygon.getPathIterator(null);
 
364
                        
 
365
                        for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++) {
 
366
                                double[] d=new double[6];
 
367
                                pa.currentSegment(d);
 
368
                                r2dm.setRenderingCoordinate(r2dm.getSelectedPart().getAtom(i),new Point2d(d[0]/1000,d[1]/1000));
 
369
                                pa.next();
 
370
                        }
 
371
                        fireChange();
 
372
                }
 
373
 
 
374
                // make note of current coordinates for next DraggedEvent
 
375
                prevDragCoordX = mouseX;
 
376
                prevDragCoordY = mouseY;
 
377
        }
 
378
 
 
379
 
 
380
        /**
 
381
         *  manages all actions that will be invoked when a mouse button is pressed
 
382
         *
 
383
         *@param  event  MouseEvent object
 
384
         */
 
385
        public void mousePressed(MouseEvent event)
 
386
        {
 
387
                isUndoableChange = false;
 
388
                int[] screenCoords = {event.getX(), event.getY()};
 
389
                int[] mouseCoords = getWorldCoordinates(screenCoords);
 
390
                int mouseX = mouseCoords[0];
 
391
                int mouseY = mouseCoords[1];
 
392
 
 
393
                logger.debug("MousePressed Event Props: mode=", c2dm.getDrawModeString());
 
394
                if (logger.isDebugEnabled())
 
395
                {
 
396
                        logger.debug("   trigger=" + event.isPopupTrigger() +
 
397
                        /*
 
398
                         *  ", Button number: " + event.getButton() +
 
399
                         */
 
400
                                        ", Click count: " + event.getClickCount());
 
401
                }
 
402
 
 
403
                int startX = 0;
 
404
                int startY = 0;
 
405
                r2dm.setPointerVectorStart(null);
 
406
                r2dm.setPointerVectorEnd(null);
 
407
                IAtom atomInRange = getAtomInRange(mouseX, mouseY);
 
408
                IBond bondInRange = getBondInRange(mouseX, mouseY);
 
409
                if (atomInRange != null)
 
410
                {
 
411
                        startX = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).x;
 
412
                        startY = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).y;
 
413
                        r2dm.setPointerVectorStart(new Point(startX, startY));
 
414
                } else
 
415
                {
 
416
                        r2dm.setPointerVectorStart(new Point(mouseX, mouseY));
 
417
                }
 
418
                
 
419
                if(r2dm.getSelectedPart()!=null &&
 
420
                   !((atomInRange == null) || (atomInRange == null)) &&
 
421
                   !(r2dm.getSelectedPart().contains(atomInRange) ||
 
422
                   r2dm.getSelectedPart().contains(bondInRange)) && 
 
423
                   r2dm.getRotateRadius()==0){
 
424
                        r2dm.setSelectedPart(atomInRange.getBuilder().newAtomContainer());
 
425
                }
 
426
                
 
427
                if (c2dm.getDrawMode() == Controller2DModel.MOVE)
 
428
                {
 
429
                        selectNearestChemObjectIfNoneSelected(mouseX, mouseY);
 
430
                        dragMode = DRAG_MOVING_SELECTED;
 
431
                } else if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND || c2dm.getDrawMode() == Controller2DModel.DOWN_BOND || c2dm.getDrawMode() == Controller2DModel.UP_BOND)
 
432
                {
 
433
                        if (bondInRange != null && atomInRange == null)
 
434
                        {
 
435
                                // make sure we are not dragging a bond
 
436
                        } else
 
437
                        {
 
438
                                dragMode = DRAG_DRAWING_PROPOSED_BOND;
 
439
                                lastAtomInRange = atomInRange;
 
440
                        }
 
441
                } else if (c2dm.getDrawMode() == Controller2DModel.MAPATOMATOM)
 
442
                {
 
443
                        dragMode = DRAG_DRAWING_PROPOSED_ATOMATOMMAP;
 
444
                } else if (c2dm.getDrawMode() == Controller2DModel.SELECT)
 
445
                {
 
446
                        dragMode = DRAG_MAKING_SQUARE_SELECTION;
 
447
                } else if (c2dm.getDrawMode() == Controller2DModel.LASSO && r2dm.getRotateRadius()==0)
 
448
                {
 
449
                        if(c2dm.isMovingAllowed() && r2dm.getSelectedPart()!=null && (r2dm.getSelectedPart().contains(r2dm.getHighlightedAtom()) || r2dm.getSelectedPart().contains(r2dm.getHighlightedBond()))){
 
450
                                if(r2dm.getSelectedPart().getAtomCount()>0)
 
451
                                        c2dm.setDrawMode(Controller2DModel.MOVE);
 
452
                                if(lastAction!=null){
 
453
                                        ((JButton)lastAction.get(0)).setBackground(Color.LIGHT_GRAY);
 
454
                                        lastAction.set(0,moveButton);
 
455
                                        moveButton.setBackground(Color.GRAY);
 
456
                                }
 
457
                                dragMode = DRAG_MOVING_SELECTED;
 
458
                        }
 
459
                        else{
 
460
                                dragMode = DRAG_MAKING_LASSO_SELECTION;
 
461
                        }
 
462
                } else if (c2dm.getDrawMode() == Controller2DModel.RING ||
 
463
                                c2dm.getDrawMode() == Controller2DModel.BENZENERING)
 
464
                {
 
465
                        dragMode = DRAG_DRAWING_PROPOSED_RING;
 
466
                } else if(r2dm.getRotateRadius()!=0){
 
467
                        dragMode = DRAG_ROTATE;
 
468
                }
 
469
                
 
470
                if(dragMode==DRAG_MOVING_SELECTED){
 
471
                        if (r2dm.getSelectedPart() != null && r2dm.getSelectedPart().getAtom(0) != null) {
 
472
                                moveoldX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x;
 
473
                                moveoldY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y;
 
474
                        }
 
475
                }
 
476
        }
 
477
 
 
478
 
 
479
        /**
 
480
         *  manages all actions that will be invoked when a mouse button is released
 
481
         *
 
482
         *@param  event  MouseEvent object
 
483
         */
 
484
        public void mouseReleased(MouseEvent event)
 
485
        {
 
486
                isUndoableChange = false;
 
487
                logger.debug("MouseReleased Event Props: mode=", c2dm.getDrawModeString());
 
488
                if (logger.isDebugEnabled())
 
489
                {
 
490
                        logger.debug("   trigger=" + event.isPopupTrigger(),
 
491
                                        ", Click count: " + event.getClickCount());
 
492
                }
 
493
                if ((event.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)
 
494
                {
 
495
                        int[] screenCoords = {event.getX(), event.getY()};
 
496
                        int[] mouseCoords = getWorldCoordinates(screenCoords);
 
497
                        int mouseX = mouseCoords[0];
 
498
                        int mouseY = mouseCoords[1];
 
499
                        if (c2dm.getDrawMode() == Controller2DModel.SYMBOL)
 
500
                        {
 
501
                                changeSymbol();
 
502
                        }
 
503
                        if (c2dm.getDrawMode() == Controller2DModel.ELEMENT)
 
504
                        {
 
505
                                changeElement();
 
506
                        }
 
507
 
 
508
                        if (c2dm.getDrawMode() == Controller2DModel.INCCHARGE)
 
509
                        {
 
510
                                increaseCharge();
 
511
                        }
 
512
                        if (c2dm.getDrawMode() == Controller2DModel.ENTERELEMENT)
 
513
                        {
 
514
                                enterElement();
 
515
                        }
 
516
                        if (c2dm.getDrawMode() == Controller2DModel.DECCHARGE)
 
517
                        {
 
518
                                decreaseCharge();
 
519
                        }
 
520
 
 
521
                        if (c2dm.getDrawMode() == Controller2DModel.MAPATOMATOM)
 
522
                        {
 
523
                                handleMapping(wasDragged, r2dm);
 
524
                        }
 
525
      
 
526
                        if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND || c2dm.getDrawMode() == Controller2DModel.DOWN_BOND || c2dm.getDrawMode() == Controller2DModel.UP_BOND)
 
527
                        {
 
528
                                drawBond(mouseX, mouseY);
 
529
                        }
 
530
 
 
531
                        if (c2dm.getDrawMode() == Controller2DModel.SELECT && wasDragged)
 
532
                        {
 
533
                                logger.info("User asks to selected atoms");
 
534
                                IAtomContainer selectedPart = chemModel.getBuilder().newAtomContainer();
 
535
                                r2dm.setSelectedPart(selectedPart);
 
536
                                r2dm.setSelectedPart(getContainedAtoms(r2dm.getSelectRect()));
 
537
                                r2dm.setSelectRect(null);
 
538
                                logger.debug("selected stuff  ", selectedPart);
 
539
                        }
 
540
 
 
541
                        if (c2dm.getDrawMode() == Controller2DModel.ERASER)
 
542
                        {
 
543
                                eraseSelection();
 
544
                        }
 
545
 
 
546
                        if (c2dm.getDrawMode() == Controller2DModel.RING || c2dm.getDrawMode() == Controller2DModel.BENZENERING)
 
547
                        {
 
548
                                drawRing(mouseX, mouseY);
 
549
                        }
 
550
 
 
551
                        if (c2dm.getDrawMode() == Controller2DModel.LASSO && r2dm.getRotateRadius()==0)
 
552
                        {
 
553
                                // first deselect all atoms
 
554
                                r2dm.setSelectedPart(chemModel.getBuilder().newAtomContainer());
 
555
                                // now select new atoms
 
556
                                if (wasDragged)
 
557
                                {
 
558
                                        lassoSelection();
 
559
 
 
560
                                } else
 
561
                                {
 
562
                                        singleObjectSelected(mouseX, mouseY);
 
563
                                }
 
564
                                fireChange();
 
565
                        }
 
566
 
 
567
                        if (wasDragged)
 
568
                        {
 
569
                                prevDragCoordX = 0;
 
570
                                prevDragCoordY = 0;
 
571
                                wasDragged = false;
 
572
                        }
 
573
                        if (dragMode==DRAG_MOVING_SELECTED){
 
574
                                dragAndDropSelection();
 
575
                        }
 
576
                        
 
577
                        if (c2dm.getDrawMode() == Controller2DModel.MOVE)
 
578
                        {
 
579
                                if (draggingSelected == false)
 
580
                                {                                       
 
581
                                        // then it was dragging nearest Bond or Atom
 
582
                                        r2dm.setSelectedPart(chemModel.getBuilder().newAtomContainer());
 
583
                                }
 
584
                                if(r2dm.getMerge().size()>0){
 
585
                                        mergeMolecules();
 
586
                                        this.updateMoleculeCoordinates();
 
587
                                }
 
588
                        } 
 
589
                        
 
590
                        dragMode = DRAG_UNSET;
 
591
                        r2dm.setPointerVectorStart(null);
 
592
                        r2dm.setPointerVectorEnd(null);
 
593
                }
 
594
                if (shiftX != 0 || shiftY != 0)
 
595
                {
 
596
                        shiftMolecule();
 
597
                }
 
598
                shiftX = 0;
 
599
                shiftY = 0;
 
600
        }
 
601
 
 
602
 
 
603
        private void shiftMolecule() {
 
604
                for (int i = 0; i < chemModel.getMoleculeSet().getMoleculeCount(); i++)
 
605
                {
 
606
                        IMolecule mol = chemModel.getMoleculeSet().getMolecule(i);
 
607
                        for (int k = 0; k < mol.getAtomCount(); k++)
 
608
                        {
 
609
                                ((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).x=((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).x -shiftX;
 
610
                                ((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).y=((Point2d)r2dm.getRenderingCoordinate(mol.getAtom(k))).y -shiftY;
 
611
                        }
 
612
                }
 
613
                r2dm.fireChange();
 
614
                fireChange();
 
615
        }
 
616
 
 
617
        private void dragAndDropSelection() {
 
618
                double deltaX=0;
 
619
                double deltaY=0;
 
620
                IAtomContainer undoredoContainer = chemModel.getBuilder().newAtomContainer();
 
621
                if(r2dm.getSelectedPart()!=null && r2dm.getSelectedPart().getAtomCount()>0){
 
622
                        undoredoContainer.add(r2dm.getSelectedPart());
 
623
                        deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).x-moveoldX;
 
624
                        deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getSelectedPart().getAtom(0))).y-moveoldY;
 
625
                        
 
626
                }else if(r2dm.getHighlightedAtom()!=null){
 
627
                        deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedAtom())).x-moveoldX;
 
628
                        deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedAtom())).y-moveoldY;
 
629
                        undoredoContainer.addAtom(r2dm.getHighlightedAtom());
 
630
                }else if (r2dm.getHighlightedBond()!=null){
 
631
                        deltaX=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedBond().getAtom(0))).x-moveoldX;
 
632
                        deltaY=((Point2d)r2dm.getRenderingCoordinate(r2dm.getHighlightedBond().getAtom(0))).y-moveoldY; 
 
633
                }
 
634
                UndoableEdit edit = new MoveAtomEdit(undoredoContainer, (int)deltaX, (int)deltaY, r2dm.getRenderingCoordinates());
 
635
                undoRedoHandler.postEdit(edit);
 
636
        }
 
637
 
 
638
        private void mergeMolecules() {
 
639
                Iterator it=r2dm.getMerge().keySet().iterator();
 
640
                IBond[] bondson2 = null;
 
641
                IAtom atom2 = null;
 
642
                IAtom atom1 = null;
 
643
                ArrayList undoredoContainer = new ArrayList();
 
644
                while(it.hasNext()){
 
645
                        Object[] undoObject = new Object[3];
 
646
                        atom1=(IAtom)it.next();
 
647
                        atom2=(IAtom)r2dm.getMerge().get(atom1);
 
648
                        undoObject[0] = atom1;
 
649
                        undoObject[1] = atom2;
 
650
                        IMoleculeSet som=chemModel.getMoleculeSet();
 
651
                        IAtomContainer container1 = ChemModelManipulator.getRelevantAtomContainer(chemModel, atom1);
 
652
                        IAtomContainer container2 = ChemModelManipulator.getRelevantAtomContainer(chemModel, atom2);
 
653
                        if (container1 != container2) {
 
654
                                container1.add(container2);
 
655
                                som.removeAtomContainer(container2);
 
656
                        }
 
657
                        bondson2=AtomContainerManipulator.getBondArray(container1.getConnectedBondsList(atom2));
 
658
                        undoObject[2] = bondson2;
 
659
                        undoredoContainer.add(undoObject);
 
660
                        for(int i=0;i<bondson2.length;i++){
 
661
                                if(bondson2[i].getAtom(0)==atom2)
 
662
                                        bondson2[i].setAtom(atom1,0);
 
663
                                if(bondson2[i].getAtom(1)==atom2)
 
664
                                        bondson2[i].setAtom(atom1,1);
 
665
                                if(bondson2[i].getAtom(0)==bondson2[i].getAtom(1)){
 
666
                                        container1.removeBond(bondson2[i]);
 
667
                                }
 
668
                        }
 
669
                        container1.removeAtom(atom2);
 
670
                }
 
671
                UndoableEdit  edit = new MergeMoleculesEdit(chemModel, undoredoContainer, "Molecules merged");
 
672
                undoRedoHandler.postEdit(edit);
 
673
                r2dm.getMerge().clear();
 
674
        }
 
675
 
 
676
        private void singleObjectSelected(int mouseX, int mouseY) {
 
677
//               one atom clicked or one bond clicked
 
678
                IChemObject chemObj = getChemObjectInRange(mouseX, mouseY);
 
679
                IAtomContainer container = chemObj.getBuilder().newAtomContainer();
 
680
                if (chemObj instanceof IAtom)
 
681
                {
 
682
                        container.addAtom((IAtom) chemObj);
 
683
                        logger.debug("selected one atom in lasso mode");
 
684
                        r2dm.setSelectedPart(container);
 
685
                } else if (chemObj instanceof IBond)
 
686
                {
 
687
                        IBond bond = (IBond) chemObj;
 
688
                        container.addBond(bond);
 
689
                        logger.debug("selected one bond in lasso mode");
 
690
                        for (int i = 0; i < bond.getAtomCount(); i++)
 
691
                        {
 
692
                                container.addAtom(bond.getAtom(i));
 
693
                        }
 
694
                        r2dm.setSelectedPart(container);
 
695
                }
 
696
        }
 
697
 
 
698
        private void lassoSelection() {
 
699
                Vector lassoPoints = r2dm.getLassoPoints();
 
700
                r2dm.addLassoPoint(new Point((Point) lassoPoints.elementAt(0)));
 
701
                int number = lassoPoints.size();
 
702
                logger.debug("# lasso points: ", number);
 
703
                int[] screenLassoCoords = new int[number * 2];
 
704
                Point currentPoint;
 
705
                for (int i = 0; i < number; i++)
 
706
                {
 
707
                        currentPoint = (Point) lassoPoints.elementAt(i);
 
708
                        screenLassoCoords[i * 2] = currentPoint.x;
 
709
                        screenLassoCoords[i * 2 + 1] = currentPoint.y;
 
710
                        logger.debug("ScreenLasso.x = ", screenLassoCoords[i * 2]);
 
711
                        logger.debug("ScreenLasso.y = ", screenLassoCoords[i * 2 + 1]);
 
712
                }
 
713
                /*
 
714
                 *  Convert points to world coordinates as they are
 
715
                 *  in screen coordinates in the vector
 
716
                 */
 
717
                int[] worldCoords = getWorldCoordinates(screenLassoCoords);
 
718
                logger.debug("Returned coords: ", worldCoords.length);
 
719
                logger.debug("       # points: ", number);
 
720
                int[] xPoints = new int[number];
 
721
                int[] yPoints = new int[number];
 
722
                for (int i = 0; i < number; i++)
 
723
                {
 
724
                        xPoints[i] = worldCoords[i * 2];
 
725
                        yPoints[i] = worldCoords[i * 2 + 1];
 
726
                        logger.debug("WorldCoords.x  = ", worldCoords[i * 2]);
 
727
                        logger.debug("WorldCoords.y  = ", worldCoords[i * 2 + 1]);
 
728
                        logger.debug("Polygon.x = ", xPoints[i]);
 
729
                        logger.debug("Polygon.y = ", yPoints[i]);
 
730
                }
 
731
                Polygon polygon = new Polygon(xPoints, yPoints, number);
 
732
                r2dm.setSelectedPart(getContainedAtoms(polygon));
 
733
                r2dm.getLassoPoints().removeAllElements();
 
734
                r2dm.fireChange();
 
735
        }
 
736
 
 
737
        private void drawRing(int mouseX, int mouseY) {
 
738
                this.updateMoleculeCoordinates();
 
739
                IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
 
740
                IRing newRing = null;
 
741
                Point2d sharedAtomsCenter;
 
742
                Vector2d ringCenterVector;
 
743
                double bondLength;
 
744
                int pointerMarkX;
 
745
                int pointerMarkY;
 
746
 
 
747
                double ringRadius;
 
748
 
 
749
                double angle;
 
750
 
 
751
                double xDiff;
 
752
 
 
753
                double yDiff;
 
754
 
 
755
                double distance1 = 0;
 
756
 
 
757
                double distance2 = 0;
 
758
                IAtom firstAtom;
 
759
                IAtom secondAtom;
 
760
                IAtom spiroAtom;
 
761
                Point2d conAtomsCenter = null;
 
762
                Point2d newPoint1;
 
763
                Point2d newPoint2;
 
764
 
 
765
                RingPlacer ringPlacer = new RingPlacer();
 
766
                int ringSize = c2dm.getRingSize();
 
767
                String symbol = c2dm.getDrawElement();
 
768
                IAtomContainer sharedAtoms = getHighlighted();
 
769
 
 
770
                if (sharedAtoms.getAtomCount() == 0)
 
771
                {
 
772
                        sharedAtoms = sharedAtoms.getBuilder().newAtomContainer();
 
773
                        newRing = sharedAtoms.getBuilder().newRing(ringSize, symbol);
 
774
                        if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
 
775
                        {
 
776
                                // make newRing a benzene ring
 
777
                                newRing.getBond(0).setOrder(2.0);
 
778
                                newRing.getBond(2).setOrder(2.0);
 
779
                                newRing.getBond(4).setOrder(2.0);
 
780
                                makeRingAromatic(newRing);
 
781
                        }
 
782
                        bondLength = r2dm.getBondLength();
 
783
                        ringRadius = (bondLength / 2) / Math.sin(Math.PI / c2dm.getRingSize());
 
784
                        sharedAtomsCenter = new Point2d(mouseX, mouseY - ringRadius);
 
785
                        firstAtom = newRing.getAtom(0);
 
786
                        firstAtom.setPoint2d(sharedAtomsCenter);
 
787
                        sharedAtoms.addAtom(firstAtom);
 
788
                        ringCenterVector = new Vector2d(new Point2d(mouseX, mouseY));
 
789
                        ringCenterVector.sub(sharedAtomsCenter);
 
790
                        ringPlacer.placeSpiroRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);
 
791
                        IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
 
792
                        atomCon.add(newRing);
 
793
                        undoRedoContainer.add(newRing);
 
794
                } else if (sharedAtoms.getAtomCount() == 1)     {
 
795
                        spiroAtom = sharedAtoms.getAtom(0);
 
796
                        sharedAtomsCenter = GeometryTools.get2DCenter(sharedAtoms,r2dm.getRenderingCoordinates());
 
797
                        newRing = createAttachRing(sharedAtoms, ringSize, symbol);
 
798
                        if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
 
799
                        {
 
800
                                // make newRing a benzene ring
 
801
                                newRing.getBond(0).setOrder(2.0);
 
802
                                newRing.getBond(2).setOrder(2.0);
 
803
                                newRing.getBond(4).setOrder(2.0);
 
804
                                makeRingAromatic(newRing);
 
805
                        }
 
806
                        bondLength = r2dm.getBondLength();
 
807
                        conAtomsCenter = getConnectedAtomsCenter(sharedAtoms);
 
808
                        if (conAtomsCenter.equals(((Point2d)r2dm.getRenderingCoordinate(spiroAtom))))
 
809
                        {
 
810
                                ringCenterVector = new Vector2d(0, 1);
 
811
                        } else
 
812
                        {
 
813
                                ringCenterVector = new Vector2d(sharedAtomsCenter);
 
814
                                ringCenterVector.sub(conAtomsCenter);
 
815
                        }
 
816
                        ringPlacer.placeSpiroRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);
 
817
                        // removes the highlighed atom from the ring to add only the new placed
 
818
                        // atoms to the AtomContainer.
 
819
                        try
 
820
                        {
 
821
                                newRing.removeAtom(spiroAtom);
 
822
                        } catch (Exception exc)
 
823
                        {
 
824
                                logger.error("Could not remove atom from ring");
 
825
                                logger.debug(exc);
 
826
                        }
 
827
                        IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, spiroAtom);
 
828
                        atomCon.add(newRing);
 
829
                        undoRedoContainer.add(newRing);
 
830
                } else if (sharedAtoms.getAtomCount() == 2)     {
 
831
                        sharedAtomsCenter = GeometryTools.get2DCenter(sharedAtoms,r2dm.getRenderingCoordinates());
 
832
 
 
833
                        // calculate two points that are perpendicular to the highlighted bond
 
834
                        // and have a certain distance from the bondcenter
 
835
                        firstAtom = sharedAtoms.getAtom(0);
 
836
                        secondAtom = sharedAtoms.getAtom(1);
 
837
                        xDiff = ((Point2d)r2dm.getRenderingCoordinate(secondAtom)).x - ((Point2d)r2dm.getRenderingCoordinate(firstAtom)).x;
 
838
                        yDiff = ((Point2d)r2dm.getRenderingCoordinate(secondAtom)).y - ((Point2d)r2dm.getRenderingCoordinate(firstAtom)).y;
 
839
                        bondLength = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2));
 
840
                        angle = GeometryTools.getAngle(xDiff, yDiff);
 
841
                        newPoint1 = new Point2d((Math.cos(angle + (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.x, (Math.sin(angle + (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.y);
 
842
                        newPoint2 = new Point2d((Math.cos(angle - (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.x, (Math.sin(angle - (Math.PI / 2)) * bondLength / 4) + sharedAtomsCenter.y);
 
843
 
 
844
                        if (wasDragged)
 
845
                        {
 
846
                                // check which one of the two points is nearest to the endpoint of the pointer
 
847
                                // vector that was dragged to make the ringCenterVector point into the right direction.
 
848
                                pointerMarkX = r2dm.getPointerVectorEnd().x;
 
849
                                pointerMarkY = r2dm.getPointerVectorEnd().y;
 
850
                                distance1 = -1 * (Math.sqrt(Math.pow(newPoint1.x - pointerMarkX, 2) + Math.pow(newPoint1.y - pointerMarkY, 2)));
 
851
                                distance2 = -1 * (Math.sqrt(Math.pow(newPoint2.x - pointerMarkX, 2) + Math.pow(newPoint2.y - pointerMarkY, 2)));
 
852
                                r2dm.setPointerVectorStart(null);
 
853
                                r2dm.setPointerVectorEnd(null);
 
854
                        } else {
 
855
                                // check which one of the two points is nearest to the center of the
 
856
                                // connected atoms to make the ringCenterVector point into the right direction.
 
857
                                conAtomsCenter = getConnectedAtomsCenter(sharedAtoms);
 
858
                                distance1 = Math.sqrt(Math.pow(newPoint1.x - conAtomsCenter.x, 2) + Math.pow(newPoint1.y - conAtomsCenter.y, 2));
 
859
                                distance2 = Math.sqrt(Math.pow(newPoint2.x - conAtomsCenter.x, 2) + Math.pow(newPoint2.y - conAtomsCenter.y, 2));
 
860
                        }
 
861
                        ringCenterVector = new Vector2d(sharedAtomsCenter);
 
862
                        // no ring is attached if the two ditances are equal
 
863
                        //shk3: I removed this condition since it leads to npe and I cannot see why it is necessary.
 
864
                        //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
 
865
                        /*if (distance1 == distance2)
 
866
                        {
 
867
                                logger.warn("don't know where to draw the new Ring");
 
868
                        } else*/
 
869
                        {
 
870
                                if (distance1 < distance2)
 
871
                                {
 
872
                                        ringCenterVector.sub(newPoint1);
 
873
                                } else if (distance2 < distance1)
 
874
                                {
 
875
                                        ringCenterVector.sub(newPoint2);
 
876
                                } else{
 
877
                                        ringCenterVector.sub(newPoint2);
 
878
                                }
 
879
 
 
880
                                IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, firstAtom);
 
881
 
 
882
                                // construct a new Ring that contains the highlighted bond an its two atoms
 
883
                                newRing = createAttachRing(sharedAtoms, ringSize, symbol);
 
884
                                if (c2dm.getDrawMode() == Controller2DModel.BENZENERING)
 
885
                                {
 
886
                                        // make newRing a benzene ring
 
887
                                        IBond existingBond = atomCon.getBond(firstAtom, secondAtom);
 
888
                                        if (existingBond.getOrder() == 1.0)
 
889
                                        {
 
890
                                                if (existingBond.getFlag(CDKConstants.ISAROMATIC))
 
891
                                                {
 
892
                                                        newRing.getBond(2).setOrder(2.0);
 
893
                                                        newRing.getBond(4).setOrder(2.0);
 
894
                                                } else
 
895
                                                {
 
896
                                                        newRing.getBond(1).setOrder(2.0);
 
897
                                                        newRing.getBond(3).setOrder(2.0);
 
898
                                                        newRing.getBond(5).setOrder(2.0);
 
899
                                                }
 
900
                                        } else
 
901
                                        {
 
902
                                                newRing.getBond(2).setOrder(2.0);
 
903
                                                newRing.getBond(4).setOrder(2.0);
 
904
                                        }
 
905
                                        makeRingAromatic(newRing);
 
906
                                }
 
907
 
 
908
                                // place the new atoms of the new ring to the right position
 
909
                                ringPlacer.placeFusedRing(newRing, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength);
 
910
 
 
911
                                // removes the highlighed bond and its atoms from the ring to add only
 
912
                                // the new placed atoms to the AtomContainer.
 
913
                                try
 
914
                                {
 
915
                                        newRing.remove(sharedAtoms);
 
916
                                } catch (Exception exc)
 
917
                                {
 
918
                                        logger.error("Could not remove atom from ring");
 
919
                                        logger.debug(exc);
 
920
                                }
 
921
                                atomCon.add(newRing);
 
922
                        }
 
923
                }
 
924
                double highlightRadius = r2dm.getHighlightRadius();
 
925
                for (int i = 0; i < newRing.getAtomCount(); i++)
 
926
                {
 
927
                        IAtom atom=newRing.getAtom(i);
 
928
                        r2dm.setRenderingCoordinate(atom,new Point2d(atom.getPoint2d()));
 
929
                }
 
930
                for (int i = 0; i < newRing.getAtomCount(); i++)
 
931
                {
 
932
                        IAtom atom=newRing.getAtom(i);
 
933
                        r2dm.setRenderingCoordinate(atom,new Point2d(atom.getPoint2d()));
 
934
                        centerAtom(atom,chemModel);
 
935
                        //We make sure atoms don't overlap
 
936
                        //Solution is a bit crude, we would need to find an unoccupied place (and even the bond display should be optimized)
 
937
                        IAtom inrange=getAtomInRange((int)((Point2d)r2dm.getRenderingCoordinate(atom)).x, (int)((Point2d)r2dm.getRenderingCoordinate(atom)).y, atom);
 
938
                        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){
 
939
                                ((Point2d)r2dm.getRenderingCoordinate(atom)).x-=highlightRadius/4;
 
940
                                ((Point2d)r2dm.getRenderingCoordinate(atom)).y-=highlightRadius/4;
 
941
                        }
 
942
                }
 
943
                this.updateMoleculeCoordinates();
 
944
                this.updateAtoms(ChemModelManipulator.getRelevantAtomContainer(chemModel, newRing.getAtom(0)), sharedAtoms.atoms());
 
945
                this.updateAtoms(ChemModelManipulator.getRelevantAtomContainer(chemModel, newRing.getAtom(0)), newRing.atoms());
 
946
                undoRedoContainer.add(newRing);
 
947
                UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Added Ring",c2dm);
 
948
                undoRedoHandler.postEdit(edit);
 
949
                r2dm.fireChange();
 
950
                fireChange();
 
951
        }
 
952
 
 
953
        private void eraseSelection() {
 
954
                IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
 
955
                String type = null;
 
956
                IAtom highlightedAtom = r2dm.getHighlightedAtom();
 
957
                IBond highlightedBond = r2dm.getHighlightedBond();
 
958
                if (highlightedAtom != null && (r2dm.getSelectedPart()==null || !r2dm.getSelectedPart().contains(highlightedAtom)))
 
959
                {
 
960
                        logger.info("User asks to delete an Atom");
 
961
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, highlightedAtom);
 
962
                        IElectronContainer[] eContainer = AtomContainerManipulator.getElectronContainerArray(container.getConnectedElectronContainersList(highlightedAtom));
 
963
                        for (int i=0; i<eContainer.length; i++) {
 
964
                                undoRedoContainer.addBond((IBond) eContainer[i]);
 
965
                        }
 
966
                        logger.debug("Atoms before delete: ", container.getAtomCount());
 
967
                        Iterator atoms = container.getConnectedAtomsList(highlightedAtom).iterator();
 
968
                        ChemModelManipulator.removeAtomAndConnectedElectronContainers(chemModel, highlightedAtom);
 
969
                        updateAtoms(container, atoms);
 
970
                        undoRedoContainer.addAtom(highlightedAtom);
 
971
                        if (type == null) {
 
972
                                type = "Remove Atom";
 
973
                        }
 
974
                        else {
 
975
                                type = "Remove Substructure";
 
976
                        }
 
977
                        logger.debug("Atoms before delete: ", container.getAtomCount());
 
978
                } else if (highlightedBond != null && (r2dm.getSelectedPart()==null || !r2dm.getSelectedPart().contains(highlightedBond))){
 
979
                        logger.info("User asks to delete a Bond");
 
980
                        ChemModelManipulator.removeElectronContainer(chemModel, highlightedBond);
 
981
                        undoRedoContainer.addBond(highlightedBond);
 
982
                        if (type == null) {
 
983
                                type = "Remove Bond";
 
984
                        }
 
985
                        else {
 
986
                                type = "Remove Substructure";
 
987
                        }
 
988
                        // update atoms
 
989
                        java.util.Iterator atoms = highlightedBond.atoms();
 
990
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, highlightedBond.getAtom(0));
 
991
                        updateAtoms(container, atoms);
 
992
                } else if(r2dm.getSelectedPart()!=null && (r2dm.getSelectedPart().getAtomCount()>0 || r2dm.getSelectedPart().getBondCount()>0)){
 
993
                        logger.info("User asks to delete selected part");
 
994
                        IAtomContainer containerToUpdate = ChemModelManipulator.getRelevantAtomContainer(chemModel, r2dm.getSelectedPart().getAtom(0));
 
995
                        for(int i=0;i<r2dm.getSelectedPart().getAtomCount();i++){
 
996
                                undoRedoContainer.addAtom(r2dm.getSelectedPart().getAtom(i));
 
997
                                for(int k=0;k<ChemModelManipulator.getRelevantAtomContainer(chemModel,r2dm.getSelectedPart().getAtom(i)).getConnectedBondsCount(r2dm.getSelectedPart().getAtom(i));k++){
 
998
                                        undoRedoContainer.addBond((IBond)ChemModelManipulator.getRelevantAtomContainer(chemModel,r2dm.getSelectedPart().getAtom(i)).getConnectedBondsList(r2dm.getSelectedPart().getAtom(i)).get(k));
 
999
                                }
 
1000
                                ChemModelManipulator.removeAtomAndConnectedElectronContainers(chemModel,r2dm.getSelectedPart().getAtom(i));
 
1001
                        }
 
1002
                        type = "Remove Substructure";
 
1003
                        // update atoms
 
1004
                        updateAtoms(containerToUpdate, containerToUpdate.atoms());
 
1005
                }else{
 
1006
                        logger.warn("Cannot deleted if nothing is highlighted");
 
1007
                        return;
 
1008
                }
 
1009
                /*
 
1010
                 *  PRESERVE THIS. This notifies the
 
1011
                 *  the listener responsible for
 
1012
                 *  undo and redo storage that it
 
1013
                 *  should store this change of an atom symbol
 
1014
                 */
 
1015
                isUndoableChange = true;
 
1016
                /*
 
1017
                 *  ---
 
1018
                 */
 
1019
                UndoableEdit  edit = new RemoveAtomsAndBondsEdit(chemModel, undoRedoContainer, type);
 
1020
                undoRedoHandler.postEdit(edit);
 
1021
                r2dm.fireChange();
 
1022
                fireChange();
 
1023
        }
 
1024
 
 
1025
        private void drawBond(int mouseX, int mouseY) {
 
1026
                this.updateMoleculeCoordinates();
 
1027
                logger.debug("mouseReleased->drawbond");
 
1028
                IAtom atomInRange;
 
1029
                IAtom newAtom1 = null;
 
1030
                IAtom newAtom2 = null;
 
1031
                IBond newBond = null;
 
1032
                int startX = r2dm.getPointerVectorStart().x;
 
1033
                int startY = r2dm.getPointerVectorStart().y;
 
1034
                IBond bondInRange = r2dm.getHighlightedBond();
 
1035
                
 
1036
 
 
1037
                
 
1038
                //atomInRange = r2dm.getHighlightedAtom();
 
1039
                //Bond bondInRange = getBondInRange(mouseX, mouseY);
 
1040
                /*
 
1041
                 *  IMPORTANT: I don't use getHighlighteAtom()
 
1042
                 *  here because of the special case of
 
1043
                 *  only one atom on the screen.
 
1044
                 *  In this case, this atom will not detected
 
1045
                 *  if the mouse hasn't moved after it's creation
 
1046
                 */
 
1047
                atomInRange = getAtomInRange(mouseX, mouseY);
 
1048
                if (bondInRange != null)
 
1049
                {
 
1050
//                      update atoms
 
1051
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, bondInRange.getAtom(0));
 
1052
                        updateAtoms(container, bondInRange.atoms());
 
1053
                        HashMap changedBonds = new HashMap();
 
1054
                        double formerBondOrder = bondInRange.getOrder();
 
1055
                        if (c2dm.getDrawMode() == Controller2DModel.DRAWBOND){
 
1056
                                if(bondInRange.getStereo()!=CDKConstants.STEREO_BOND_NONE){
 
1057
                                        bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
 
1058
                                }else{
 
1059
                                        // increase Bond order
 
1060
                                        double order = bondInRange.getOrder();
 
1061
                                        if (order >= CDKConstants.BONDORDER_TRIPLE)
 
1062
                                        {
 
1063
                                                bondInRange.setOrder(CDKConstants.BONDORDER_SINGLE);
 
1064
                                        } else {
 
1065
                                                bondInRange.setOrder(order + 1.0);
 
1066
                                                // this is tricky as it depends on the fact that the
 
1067
                                                // constants are unidistant, i.e. {1.0, 2.0, 3.0}.
 
1068
                                        }
 
1069
                                }
 
1070
                        }else if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND){
 
1071
                    // toggle bond stereo
 
1072
                    double stereo = bondInRange.getStereo();
 
1073
                    if (stereo == CDKConstants.STEREO_BOND_DOWN)
 
1074
                    {
 
1075
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_DOWN_INV);
 
1076
                    } else if (stereo == CDKConstants.STEREO_BOND_DOWN_INV)
 
1077
                    {
 
1078
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
 
1079
                    } else
 
1080
                    {
 
1081
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_DOWN);
 
1082
                    }
 
1083
                    bondInRange.setOrder(1);
 
1084
                        }else{
 
1085
                    // toggle bond stereo
 
1086
                    double stereo = bondInRange.getStereo();
 
1087
                    if (stereo == CDKConstants.STEREO_BOND_UP)
 
1088
                    {
 
1089
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_UP_INV);
 
1090
                    } else if (stereo == CDKConstants.STEREO_BOND_UP_INV)
 
1091
                    {
 
1092
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_NONE);
 
1093
                    } else
 
1094
                    {
 
1095
                      bondInRange.setStereo(CDKConstants.STEREO_BOND_UP);
 
1096
                    }
 
1097
                    bondInRange.setOrder(1);
 
1098
                        }           
 
1099
                        /*
 
1100
                         *  PRESERVE THIS. This notifies the
 
1101
                         *  the listener responsible for
 
1102
                         *  undo and redo storage that it
 
1103
                         *  should store this change of an atom symbol
 
1104
                         */
 
1105
                        if (bondInRange.getOrder() != formerBondOrder) {
 
1106
                double[] bondOrders = new double[2];
 
1107
                bondOrders[0] = bondInRange.getOrder();
 
1108
                bondOrders[1] = formerBondOrder;
 
1109
                changedBonds.put(bondInRange, bondOrders);
 
1110
            }
 
1111
                        isUndoableChange = true;
 
1112
                        /*
 
1113
                         *  ---
 
1114
                         */
 
1115
                        UndoableEdit  edit = new AdjustBondOrdersEdit(changedBonds);
 
1116
                        undoRedoHandler.postEdit(edit);
 
1117
                        updateAtoms(container, bondInRange.atoms());
 
1118
                } else
 
1119
                {
 
1120
                        IAtomContainer undoRedoContainer = chemModel.getBuilder().newAtomContainer();
 
1121
                        if (atomInRange != null)
 
1122
                        {
 
1123
                                logger.debug("We had an atom in range");
 
1124
                                newAtom1 = atomInRange;
 
1125
                        } else if (!wasDragged)
 
1126
                        {
 
1127
                                // create a new molecule
 
1128
                                logger.debug("We make a new molecule");
 
1129
                                newAtom1 = undoRedoContainer.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(startX, startY));
 
1130
                                IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
 
1131
                                atomCon.addAtom(newAtom1);
 
1132
                                r2dm.setRenderingCoordinate(newAtom1,new Point2d(startX, startY));
 
1133
                                // update atoms
 
1134
                                updateAtom(atomCon, newAtom1);
 
1135
                                undoRedoContainer.add(atomCon);
 
1136
                        }
 
1137
 
 
1138
                        if (wasDragged)
 
1139
                        {
 
1140
                                if (dragMode == DRAG_DRAWING_PROPOSED_BOND)
 
1141
                                {
 
1142
                                        int endX = r2dm.getPointerVectorEnd().x;
 
1143
                                        int endY = r2dm.getPointerVectorEnd().y;
 
1144
                                        atomInRange = getAtomInRange(endX, endY);
 
1145
                                        // OK, there is some repartitioning done on atomCon later, so put everything in the first AC
 
1146
                                        IAtomContainer atomCon = null;
 
1147
                                        Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
 
1148
                                        while (atomCons.hasNext()) {
 
1149
                                                if (atomCon == null) { 
 
1150
                                                        atomCon = (IAtomContainer)atomCons.next();
 
1151
                                                } else {
 
1152
                                                        atomCon.add((IAtomContainer)atomCons.next());                                                   
 
1153
                                                }
 
1154
                                        }
 
1155
                                        if (atomCon == null) atomCon = chemModel.getBuilder().newAtomContainer();
 
1156
                                        if (atomInRange != null)
 
1157
                                        {
 
1158
                                                logger.debug("*** atom in range");
 
1159
 
 
1160
                                                newAtom2 = atomInRange;
 
1161
                                                logger.debug("atomCon.getAtomCount() " + atomCon.getAtomCount());
 
1162
                                        } else
 
1163
                                        {
 
1164
                                                logger.debug("*** new atom");
 
1165
                                                newAtom2 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(endX, endY));
 
1166
                                                atomCon.addAtom(newAtom2);
 
1167
                                                r2dm.setRenderingCoordinate(newAtom2,new Point2d(endX, endY));
 
1168
                                                undoRedoContainer.addAtom(newAtom2);
 
1169
                                        }
 
1170
                                        newAtom1 = lastAtomInRange;
 
1171
                                        if (newAtom1 == null)
 
1172
                                        {
 
1173
                                                newAtom1 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(r2dm.getPointerVectorStart().x, r2dm.getPointerVectorStart().y));
 
1174
                                                undoRedoContainer.addAtom(newAtom1);
 
1175
                                        }
 
1176
                                        if (newAtom1 != newAtom2)
 
1177
                                        {
 
1178
                                                newBond = atomCon.getBuilder().newBond(newAtom1, newAtom2, 1);
 
1179
                                                if(c2dm.getDrawMode() == Controller2DModel.UP_BOND)
 
1180
                                                        newBond.setStereo(CDKConstants.STEREO_BOND_UP);
 
1181
                                                if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND)
 
1182
                                                        newBond.setStereo(CDKConstants.STEREO_BOND_DOWN);
 
1183
                                                logger.debug(newAtom1 + " - " + newAtom2);
 
1184
                                                atomCon.addBond(newBond);
 
1185
                                                undoRedoContainer.addBond(newBond);
 
1186
                                        }
 
1187
 
 
1188
                                        try
 
1189
                                        {
 
1190
                                                IMoleculeSet setOfMolecules = ConnectivityChecker.partitionIntoMolecules(atomCon);
 
1191
                                                chemModel.setMoleculeSet(setOfMolecules);
 
1192
                                                logger.debug("We have " + setOfMolecules.getAtomContainerCount() + " molecules on screen");
 
1193
                                        } catch (Exception exception)
 
1194
                                        {
 
1195
                                                logger.warn("Could not partition molecule: ", exception.getMessage());
 
1196
                                                logger.debug(exception);
 
1197
                                                return;
 
1198
                                        }
 
1199
 
 
1200
                                        // update atoms
 
1201
                                        updateAtom(atomCon, newAtom2);
 
1202
 
 
1203
                                        /*
 
1204
                                         *  PRESERVE THIS. This notifies the
 
1205
                                         *  the listener responsible for
 
1206
                                         *  undo and redo storage that it
 
1207
                                         *  should store this change of an atom symbol
 
1208
                                         */
 
1209
                                        isUndoableChange = true;
 
1210
                                        /*
 
1211
                                         *  ---
 
1212
                                         */
 
1213
                                }
 
1214
                        } else if (atomInRange != null)
 
1215
                        {
 
1216
                                // add a new atom to the current atom in some random
 
1217
                                // direction
 
1218
                                IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1219
                                newAtom2 = atomCon.getBuilder().newAtom(c2dm.getDrawElement(), ((Point2d)r2dm.getRenderingCoordinate(atomInRange)));
 
1220
 
 
1221
                                // now create 2D coords for new atom
 
1222
                                double bondLength = r2dm.getBondLength();
 
1223
                                java.util.List connectedAtoms = atomCon.getConnectedAtomsList(atomInRange);
 
1224
                                logger.debug("connectedAtoms.length: " + connectedAtoms.size());
 
1225
                                IAtomContainer placedAtoms = atomCon.getBuilder().newAtomContainer();
 
1226
                                //placedAtoms.addAtom(atomInRange);
 
1227
                                for (int i = 0; i < connectedAtoms.size(); i++)
 
1228
                                {
 
1229
                                        placedAtoms.addAtom((IAtom)connectedAtoms.get(i));
 
1230
                                }
 
1231
                                IAtomContainer unplacedAtoms = atomCon.getBuilder().newAtomContainer();
 
1232
                                unplacedAtoms.addAtom(newAtom2);
 
1233
                                AtomPlacer atomPlacer = new AtomPlacer();
 
1234
                                atomPlacer.setMolecule(atomCon.getBuilder().newMolecule(atomCon));
 
1235
                                Point2d center2D = GeometryTools.get2DCenter(placedAtoms,r2dm.getRenderingCoordinates());
 
1236
                                logger.debug("placedAtoms.getAtomCount(): " + placedAtoms.getAtomCount());
 
1237
                                logger.debug("unplacedAtoms.getAtomCount(): " + unplacedAtoms.getAtomCount());
 
1238
                                if (placedAtoms.getAtomCount() == 1)
 
1239
                                {
 
1240
                                        Vector2d bondVector = atomPlacer.getNextBondVector(
 
1241
                                                        atomInRange, placedAtoms.getAtom(0), 
 
1242
                                                        GeometryTools.get2DCenter(atomCon.getBuilder().newMolecule(atomCon),r2dm.getRenderingCoordinates()),
 
1243
                                                        true // FIXME: is this correct? (see SF bug #1367002)
 
1244
                                        );
 
1245
                                        Point2d atomPoint = new Point2d(((Point2d)r2dm.getRenderingCoordinate(atomInRange)));
 
1246
                                        bondVector.normalize();
 
1247
                                        bondVector.scale(bondLength);
 
1248
                                        atomPoint.add(bondVector);
 
1249
                                        newAtom2.setPoint2d(atomPoint);
 
1250
                                        r2dm.setRenderingCoordinate(newAtom2,atomPoint);
 
1251
 
 
1252
                                } else
 
1253
                                {
 
1254
                                        atomPlacer.distributePartners(atomInRange, placedAtoms, center2D,
 
1255
                                                        unplacedAtoms, bondLength);
 
1256
                                }
 
1257
 
 
1258
                                // now add the new atom
 
1259
                                atomCon.addAtom(newAtom2);
 
1260
                                undoRedoContainer.addAtom(newAtom2);
 
1261
                                r2dm.setRenderingCoordinate(newAtom2,new Point2d(newAtom2.getPoint2d()));
 
1262
                                newBond= undoRedoContainer.getBuilder().newBond(atomInRange, newAtom2, 1.0);
 
1263
                                atomCon.addBond(newBond);
 
1264
                                undoRedoContainer.addBond(newBond);
 
1265
                                if(c2dm.getDrawMode() == Controller2DModel.UP_BOND)
 
1266
                                        newBond.setStereo(CDKConstants.STEREO_BOND_UP);
 
1267
                                if(c2dm.getDrawMode() == Controller2DModel.DOWN_BOND)
 
1268
                                        newBond.setStereo(CDKConstants.STEREO_BOND_DOWN);
 
1269
                                // update atoms
 
1270
                                updateAtom(atomCon, atomInRange);
 
1271
                                updateAtom(atomCon, newAtom2);
 
1272
                        }
 
1273
                        UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Add Bond",c2dm);
 
1274
                        undoRedoHandler.postEdit(edit);
 
1275
                }
 
1276
                r2dm.fireChange();
 
1277
                fireChange();
 
1278
                if(newAtom1!=null && r2dm.getRenderingCoordinate(newAtom1)==null)
 
1279
                        r2dm.setRenderingCoordinate(newAtom1,new Point2d(newAtom1.getPoint2d()));
 
1280
                if(newAtom2!=null)
 
1281
                        r2dm.setRenderingCoordinate(newAtom2,new Point2d(newAtom2.getPoint2d()));
 
1282
                centerAtom(newAtom1,chemModel);
 
1283
                centerAtom(newAtom2,chemModel);
 
1284
                this.updateMoleculeCoordinates();
 
1285
        }
 
1286
 
 
1287
        private void decreaseCharge() {
 
1288
                IAtom atomInRange = r2dm.getHighlightedAtom();
 
1289
                if (atomInRange != null)
 
1290
                {
 
1291
                        int formerCharge = atomInRange.getFormalCharge();
 
1292
                        atomInRange.setFormalCharge(atomInRange.getFormalCharge() - 1);
 
1293
                        // update atom
 
1294
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1295
                        updateAtom(container, atomInRange);
 
1296
                        //undoredo support
 
1297
            UndoableEdit  edit = new ChangeChargeEdit(atomInRange, formerCharge, atomInRange.getFormalCharge());
 
1298
                        undoRedoHandler.postEdit(edit);
 
1299
                        r2dm.fireChange();
 
1300
                        fireChange();
 
1301
                }
 
1302
        }
 
1303
 
 
1304
        private void enterElement() {
 
1305
                IAtom atomInRange = r2dm.getHighlightedAtom();
 
1306
                if (atomInRange != null)
 
1307
                {
 
1308
                        String[] funcGroupsKeys=new String[funcgroupsmap.keySet().size()+1];
 
1309
                Iterator it=funcgroupsmap.keySet().iterator();
 
1310
                int h=1;
 
1311
                funcGroupsKeys[0]="";
 
1312
                while(it.hasNext()){
 
1313
                        funcGroupsKeys[h]=(String)it.next();
 
1314
                        h++;
 
1315
                }
 
1316
                        String x=EnterElementOrGroupDialog.showDialog(null,null, "Enter an element symbol or choose/enter a functional group abbrivation:", "Enter element", funcGroupsKeys, "","");
 
1317
                        try{
 
1318
                                IAtomContainer ac=(IAtomContainer)funcgroupsmap.get(x.toLowerCase());
 
1319
                                //this means a functional group was entered
 
1320
                                //TODO undo-redo
 
1321
                                if(ac!=null && !x.equals("")){
 
1322
                                        ac=(IAtomContainer)((IAtomContainer)funcgroupsmap.get(x)).clone();
 
1323
                                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1324
                                        IAtom lastplaced=null;
 
1325
                                        int counter=0;
 
1326
                                        //this is the starting point for placing
 
1327
                                        ac.getAtom(0).setPoint2d((Point2d)r2dm.getRenderingCoordinate(atomInRange));
 
1328
                                        r2dm.setRenderingCoordinate(ac.getAtom(0), (Point2d)r2dm.getRenderingCoordinate(atomInRange));
 
1329
                                        lastplaced=ac.getAtom(0);
 
1330
                                        counter=1;
 
1331
                                        container.add(ac);
 
1332
                                        List connbonds=container.getConnectedBondsList(atomInRange);
 
1333
                                        //this is needed for undo redo
 
1334
                                        IAtomContainer undoredocontainer=ac.getBuilder().newAtomContainer();
 
1335
                                        undoredocontainer.addAtom(atomInRange);
 
1336
                                        for(int i=0;i<connbonds.size();i++){
 
1337
                                                IBond bond=(IBond)connbonds.get(i);
 
1338
                                                if(bond.getAtom(0)==atomInRange){
 
1339
                                                        bond.setAtom(ac.getAtom(0), 0);
 
1340
                                                        undoredocontainer.addBond(bond);
 
1341
                                                }else{
 
1342
                                                        bond.setAtom(ac.getAtom(0), 1);
 
1343
                                                        undoredocontainer.addBond(bond);
 
1344
                                                }
 
1345
                                        }
 
1346
                                        container.removeAtomAndConnectedElectronContainers(atomInRange);
 
1347
                                        AtomPlacer ap=new AtomPlacer();
 
1348
                                        while(lastplaced!=null){
 
1349
                                                IAtomContainer placedNeighbours=container.getBuilder().newAtomContainer();
 
1350
                                                IAtomContainer unplacedNeighbours=container.getBuilder().newAtomContainer();
 
1351
                                                List l=container.getConnectedAtomsList(lastplaced);
 
1352
                                                for(int i=0;i<l.size();i++){
 
1353
                                                        if(r2dm.getRenderingCoordinate((IAtom)l.get(i))!=null)
 
1354
                                                                placedNeighbours.addAtom((IAtom)l.get(i));
 
1355
                                                        else
 
1356
                                                                unplacedNeighbours.addAtom((IAtom)l.get(i));
 
1357
                                                }
 
1358
                                                ap.distributePartners(lastplaced, placedNeighbours, GeometryTools.get2DCenter(placedNeighbours,r2dm.getRenderingCoordinates()), unplacedNeighbours, r2dm.getBondLength(), r2dm.getRenderingCoordinates());
 
1359
                                                lastplaced=ac.getAtom(counter);
 
1360
                                                counter++;
 
1361
                                                if(counter==ac.getAtomCount())
 
1362
                                                        lastplaced=null;
 
1363
                                        }
 
1364
                                        it=container.atoms();
 
1365
                                        while(it.hasNext()){
 
1366
                                                IAtom atom=(IAtom)it.next();
 
1367
                                                if(r2dm.getRenderingCoordinate(atom)==null)
 
1368
                                                        r2dm.setRenderingCoordinate(atom, atom.getPoint2d());
 
1369
                                        }
 
1370
                                        /*
 
1371
                                         *  PRESERVE THIS. This notifies the
 
1372
                                         *  the listener responsible for
 
1373
                                         *  undo and redo storage that it
 
1374
                                         *  should store this change of an atom symbol
 
1375
                                         */
 
1376
                                        isUndoableChange = true;
 
1377
                                        /*
 
1378
                                         *  ---
 
1379
                                         */
 
1380
                                        // undoredo support
 
1381
                                        UndoableEdit  edit = new AddFuncGroupEdit(chemModel, undoredocontainer ,ac, "add "+x);
 
1382
                                        undoRedoHandler.postEdit(edit);
 
1383
                                        //undoRedoHandler.postEdit(edit);
 
1384
                                        r2dm.fireChange();
 
1385
                                        fireChange();
 
1386
                                }else if(x!=null && x.length()>0){
 
1387
                                        String formerSymbol="";
 
1388
                                        if(Character.isLowerCase(x.toCharArray()[0]))
 
1389
                                                x=Character.toUpperCase(x.charAt(0))+x.substring(1);
 
1390
                                        IsotopeFactory ifa=IsotopeFactory.getInstance(r2dm.getHighlightedAtom().getBuilder());
 
1391
                                        IIsotope iso=ifa.getMajorIsotope(x);
 
1392
                                        formerSymbol=r2dm.getHighlightedAtom().getSymbol();
 
1393
                                        if(iso!=null)
 
1394
                                                r2dm.getHighlightedAtom().setSymbol(x);
 
1395
                                        // update atom
 
1396
                                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1397
                                        updateAtom(container, atomInRange);
 
1398
                                        /*
 
1399
                                         *  PRESERVE THIS. This notifies the
 
1400
                                         *  the listener responsible for
 
1401
                                         *  undo and redo storage that it
 
1402
                                         *  should store this change of an atom symbol
 
1403
                                         */
 
1404
                                        isUndoableChange = true;
 
1405
                                        /*
 
1406
                                         *  ---
 
1407
                                         */
 
1408
                                        // undoredo support
 
1409
                                        UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, x);
 
1410
                                        undoRedoHandler.postEdit(edit);
 
1411
                                        r2dm.fireChange();
 
1412
                                        fireChange();
 
1413
                                }
 
1414
                        }catch(Exception ex){
 
1415
                                ex.printStackTrace();
 
1416
                                logger.debug(ex.getMessage()+" in SELECTELEMENT");
 
1417
                        }
 
1418
                }
 
1419
        }
 
1420
 
 
1421
        private void increaseCharge() {
 
1422
                IAtom atomInRange = r2dm.getHighlightedAtom();
 
1423
                if (atomInRange != null)
 
1424
                {
 
1425
                        int formerCharge = atomInRange.getFormalCharge();
 
1426
                        atomInRange.setFormalCharge(atomInRange.getFormalCharge() + 1);
 
1427
 
 
1428
                        // update atom
 
1429
                        IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1430
                        updateAtom(container, atomInRange);
 
1431
                        //undoredo support
 
1432
            UndoableEdit  edit = new ChangeChargeEdit(atomInRange, formerCharge, atomInRange.getFormalCharge());
 
1433
                        undoRedoHandler.postEdit(edit);
 
1434
                        r2dm.fireChange();
 
1435
                        fireChange();
 
1436
                }
 
1437
        }
 
1438
 
 
1439
        private void changeElement() {
 
1440
                IAtom atomInRange = r2dm.getHighlightedAtom();
 
1441
                if (atomInRange != null)
 
1442
                {
 
1443
                        String symbol = c2dm.getDrawElement();
 
1444
                        if (!(atomInRange.getSymbol().equals(symbol)))
 
1445
                        {
 
1446
                                // only change symbol if needed
 
1447
                                String formerSymbol = atomInRange.getSymbol();
 
1448
                                atomInRange.setSymbol(symbol);
 
1449
                                // configure the atom, so that the atomic number matches the symbol
 
1450
                                try
 
1451
                                {
 
1452
                                        IsotopeFactory.getInstance(atomInRange.getBuilder()).configure(atomInRange);
 
1453
                                } catch (Exception exception)
 
1454
                                {
 
1455
                                        logger.error("Error while configuring atom");
 
1456
                                        logger.debug(exception);
 
1457
                                }
 
1458
                                // update atom
 
1459
                                IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1460
                                updateAtom(container, atomInRange);
 
1461
                                
 
1462
                                /*
 
1463
                                 *  PRESERVE THIS. This notifies the
 
1464
                                 *  the listener responsible for
 
1465
                                 *  undo and redo storage that it
 
1466
                                 *  should store this change of an atom symbol
 
1467
                                 */
 
1468
//                              isUndoableChange = true;
 
1469
                                /*
 
1470
                                 *  ---
 
1471
                                 */
 
1472
                                // undoredo support
 
1473
                                UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, symbol);
 
1474
                                undoRedoHandler.postEdit(edit);
 
1475
                                r2dm.fireChange();
 
1476
                                fireChange();
 
1477
                        }
 
1478
                }else{
 
1479
                        int startX = r2dm.getPointerVectorStart().x;
 
1480
                        int startY = r2dm.getPointerVectorStart().y;
 
1481
                        IAtom newAtom1 = chemModel.getBuilder().newAtom(c2dm.getDrawElement(), new Point2d(startX, startY));
 
1482
                        r2dm.setRenderingCoordinate(newAtom1,new Point2d(startX, startY));
 
1483
                        IAtomContainer atomCon = ChemModelManipulator.createNewMolecule(chemModel);
 
1484
                        atomCon.addAtom(newAtom1);
 
1485
                        // update atoms
 
1486
                        updateAtom(atomCon, newAtom1);
 
1487
                        chemModel.getMoleculeSet().addAtomContainer(atomCon);
 
1488
                        //FIXME undoredo
 
1489
                        IAtomContainer undoRedoContainer= chemModel.getBuilder().newAtomContainer();
 
1490
                        undoRedoContainer.addAtom(newAtom1);
 
1491
                        UndoableEdit  edit = new AddAtomsAndBondsEdit(chemModel, undoRedoContainer, "Add Atom",c2dm);
 
1492
                        undoRedoHandler.postEdit(edit);
 
1493
                        this.updateMoleculeCoordinates();
 
1494
                        r2dm.fireChange();
 
1495
                        fireChange();
 
1496
                }
 
1497
        }
 
1498
 
 
1499
        private void changeSymbol() {
 
1500
                IAtom atomInRange = r2dm.getHighlightedAtom();
 
1501
                if (atomInRange != null)
 
1502
                {
 
1503
                        if (currentCommonElement.get(atomInRange) == null)
 
1504
                        {
 
1505
                                currentCommonElement.put(atomInRange, new Integer(1));
 
1506
                        }
 
1507
                        int oldCommonElement = ((Integer) currentCommonElement.get(atomInRange)).intValue();
 
1508
                        String symbol = (String) commonElements.elementAt(oldCommonElement);
 
1509
                        if (!(atomInRange.getSymbol().equals(symbol)))
 
1510
                        {
 
1511
                                // only change symbol if needed
 
1512
                String formerSymbol = atomInRange.getSymbol();
 
1513
                                atomInRange.setSymbol(symbol);
 
1514
                                // configure the atom, so that the atomic number matches the symbol
 
1515
                                try
 
1516
                                {
 
1517
                                        IsotopeFactory.getInstance(atomInRange.getBuilder()).configure(atomInRange);
 
1518
                                } catch (Exception exception)
 
1519
                                {
 
1520
                                        logger.error("Error while configuring atom");
 
1521
                                        logger.debug(exception);
 
1522
                                }
 
1523
                                // update atom
 
1524
                                IAtomContainer container = ChemModelManipulator.getRelevantAtomContainer(chemModel, atomInRange);
 
1525
                                updateAtom(container, atomInRange);
 
1526
 
 
1527
                                /*
 
1528
                                 *  PRESERVE THIS. This notifies the
 
1529
                                 *  the listener responsible for
 
1530
                                 *  undo and redo storage that it
 
1531
                                 *  should store this change of an atom symbol
 
1532
                                 */
 
1533
                                isUndoableChange = true;
 
1534
                                /*
 
1535
                                 *  ---
 
1536
                                 */
 
1537
                UndoableEdit  edit = new ChangeAtomSymbolEdit(atomInRange, formerSymbol, symbol);
 
1538
                undoRedoHandler.postEdit(edit);
 
1539
                                r2dm.fireChange();
 
1540
                                fireChange();
 
1541
                        }
 
1542
                        oldCommonElement++;
 
1543
                        if (oldCommonElement == commonElements.size())
 
1544
                        {
 
1545
                                oldCommonElement = 0;
 
1546
                        }
 
1547
                        currentCommonElement.put(atomInRange, new Integer(oldCommonElement));
 
1548
                }
 
1549
        }
 
1550
 
 
1551
        /**
 
1552
         *  Makes a ring aromatic
 
1553
         *
 
1554
         *@param  ring  The ring to be made aromatic
 
1555
         */
 
1556
        private void makeRingAromatic(IRing ring)
 
1557
        {
 
1558
                Iterator atoms = ring.atoms();
 
1559
                while (atoms.hasNext()) {
 
1560
                        ((IAtom)atoms.next()).setFlag(CDKConstants.ISAROMATIC, true);
 
1561
                }
 
1562
                Iterator bonds = ring.bonds();
 
1563
                while (bonds.hasNext()) {
 
1564
                        ((IBond)bonds.next()).setFlag(CDKConstants.ISAROMATIC, true);
 
1565
                }
 
1566
        }
 
1567
 
 
1568
 
 
1569
        /**
 
1570
         *  manages all actions that will be invoked when a mouse button is clicked
 
1571
         *
 
1572
         *@param  e  MouseEvent object
 
1573
         */
 
1574
        public void mouseClicked(MouseEvent e)
 
1575
        {
 
1576
                // logger.debug("Mouse clicked");
 
1577
        }
 
1578
 
 
1579
 
 
1580
        /**
 
1581
         *  manages all actions that will be invoked when a mouse enters a component
 
1582
         *
 
1583
         *@param  e  MouseEvent object
 
1584
         */
 
1585
        public void mouseEntered(MouseEvent e)
 
1586
        {
 
1587
                // logger.debug("Mouse entered");
 
1588
        }
 
1589
 
 
1590
 
 
1591
        /**
 
1592
         *  manages all actions that will be invoked when a mouse exits a component
 
1593
         *
 
1594
         *@param  e  MouseEvent object
 
1595
         */
 
1596
        public void mouseExited(MouseEvent e)
 
1597
        {
 
1598
                // logger.debug("Mouse exited");
 
1599
        }
 
1600
 
 
1601
 
 
1602
        /**
 
1603
         *  manages all actions that will be invoked when a key is released
 
1604
         *
 
1605
         *@param  e  MouseEvent object
 
1606
         */
 
1607
        public void keyReleased(KeyEvent e)
 
1608
        {
 
1609
                logger.debug("Key released");
 
1610
        }
 
1611
 
 
1612
 
 
1613
        /**
 
1614
         *  manages all actions that will be invoked when a key is typed
 
1615
         *
 
1616
         *@param  e  MouseEvent object
 
1617
         */
 
1618
        public void keyTyped(KeyEvent e)
 
1619
        {
 
1620
                try{
 
1621
                        logger.debug("Key typed");
 
1622
                        if(r2dm.getHighlightedAtom()!=null){
 
1623
                                IsotopeFactory ifa=IsotopeFactory.getInstance(r2dm.getHighlightedAtom().getBuilder());
 
1624
                                IIsotope iso=ifa.getMajorIsotope(e.getKeyChar());
 
1625
                                if(iso!=null)
 
1626
                                        r2dm.getHighlightedAtom().setSymbol(e.getKeyChar()+"");
 
1627
                        }
 
1628
                }catch(Exception ex){
 
1629
                        logger.debug("Exception "+ex.getMessage()+" in keyPressed in AbstractController");
 
1630
                }
 
1631
        }
 
1632
 
 
1633
 
 
1634
        /**
 
1635
         *  manages all actions that will be invoked when a key is pressed
 
1636
         *
 
1637
         *@param  e  MouseEvent object
 
1638
         */
 
1639
        public void keyPressed(KeyEvent e)
 
1640
        {
 
1641
                logger.debug("Key pressed");
 
1642
        }
 
1643
 
 
1644
 
 
1645
        /*
 
1646
         *  Start of private methods
 
1647
         */
 
1648
        /**
 
1649
         *  Updates an array of atoms with respect to its hydrogen count
 
1650
         *
 
1651
         *@param  container  The AtomContainer to work on
 
1652
         *@param  atoms       The Atoms to update
 
1653
         */
 
1654
        private void updateAtoms(IAtomContainer container, java.util.Iterator atoms)
 
1655
        {
 
1656
                while (atoms.hasNext())
 
1657
                {
 
1658
                        updateAtom(container, (IAtom)atoms.next());
 
1659
                }
 
1660
        }
 
1661
 
 
1662
 
 
1663
        /**
 
1664
         *  Updates an atom with respect to its hydrogen count
 
1665
         *
 
1666
         *@param  container  The AtomContainer to work on
 
1667
         *@param  atom       The Atom to update
 
1668
         */
 
1669
        public void updateAtom(IAtomContainer container, IAtom atom)
 
1670
        {
 
1671
                if (c2dm.getAutoUpdateImplicitHydrogens())
 
1672
                {
 
1673
                        atom.setHydrogenCount(0);
 
1674
                        try
 
1675
                        {
 
1676
                                hydrogenAdder.addImplicitHydrogensToSatisfyValency(container, atom);
 
1677
                        } catch (Exception exception)
 
1678
                        {
 
1679
                                logger.error(exception.getMessage());
 
1680
                                logger.debug(exception);
 
1681
                        }
 
1682
                }
 
1683
        }
 
1684
 
 
1685
 
 
1686
        /**
 
1687
         *  No idea what this does
 
1688
         *
 
1689
         *@param  angle  Some kind of angle
 
1690
         *@return        Don't know what
 
1691
         */
 
1692
        private double snapAngle(double angle)
 
1693
        {
 
1694
                double div = (Math.PI / 180) * c2dm.getSnapAngle();
 
1695
                return (Math.rint(angle / div)) * div;
 
1696
        }
 
1697
 
 
1698
 
 
1699
        /**
 
1700
         *  Gets the chemObjectInRange attribute of the Controller2D object
 
1701
         *
 
1702
         *@param  X  Current mouse x
 
1703
         *@param  Y  Current mouse x
 
1704
         *@return    The chemObjectInRange value
 
1705
         */
 
1706
        public IChemObject getChemObjectInRange(int X, int Y)
 
1707
        {
 
1708
                IChemObject objectInRange = getAtomInRange(X, Y);
 
1709
                if (objectInRange != null)
 
1710
                {
 
1711
                        // logger.debug("Returning nearest Atom: " + objectInRange);
 
1712
                        return objectInRange;
 
1713
                }
 
1714
                objectInRange = getBondInRange(X, Y);
 
1715
                if (objectInRange != null)
 
1716
                {
 
1717
                        // logger.debug("Returning nearest Bond: " + objectInRange);
 
1718
                        return objectInRange;
 
1719
                }
 
1720
                objectInRange = getReactionInRange(X, Y);
 
1721
                if (objectInRange != null)
 
1722
                {
 
1723
                        // logger.debug("Returning nearest Reaction: " + objectInRange);
 
1724
                        return objectInRange;
 
1725
                }
 
1726
                /*
 
1727
                 *  chemModel covers whole of editing window, and if nothing
 
1728
                 *  more interesting is near, then them model is in range.
 
1729
                 */
 
1730
                // logger.debug("Returning nearest ChemModel: " + chemModel);
 
1731
                return chemModel;
 
1732
        }
 
1733
 
 
1734
 
 
1735
        /**
 
1736
         *  Returns an Atom if it is in a certain range of the given point. Used to
 
1737
         *  highlight an atom that is near the cursor. <p>
 
1738
         *
 
1739
         *  <b>Important: the coordinates must be given in world coordinates and not in
 
1740
         *  screen coordinates!
 
1741
         *
 
1742
         *@param  X  The x world coordinate of the point
 
1743
         *@param  Y  The y world coordinate of the point
 
1744
         *@return    An Atom if it is in a certain range of the given point
 
1745
         */
 
1746
        private IAtom getAtomInRange(int X, int Y)
 
1747
        {
 
1748
                return getAtomInRange(X,Y,null);
 
1749
        }
 
1750
        
 
1751
        
 
1752
        /**
 
1753
         *  Returns an Atom if it is in a certain range of the given point. Used to
 
1754
         *  highlight an atom that is near the cursor. <p>
 
1755
         *
 
1756
         *  <b>Important: the coordinates must be given in world coordinates and not in
 
1757
         *  screen coordinates!
 
1758
         *
 
1759
         *@param  X  The x world coordinate of the point
 
1760
         *@param  Y  The y world coordinate of the point
 
1761
         *@return    An Atom if it is in a certain range of the given point
 
1762
         */
 
1763
        private IAtom getAtomInRange(int X, int Y, IAtom ignore)
 
1764
        {
 
1765
                double highlightRadius = r2dm.getHighlightRadius();
 
1766
                IAtom closestAtom = GeometryTools.getClosestAtom(X, Y, chemModel, ignore, r2dm.getRenderingCoordinates());
 
1767
                if (closestAtom != null)
 
1768
                {
 
1769
                        //logger.debug("getAtomInRange(): An atom is near");
 
1770
                        if (!(Math.sqrt(Math.pow(r2dm.getRenderingCoordinate(closestAtom).x - X, 2) +
 
1771
                                        Math.pow(r2dm.getRenderingCoordinate(closestAtom).y - Y, 2)) < highlightRadius))
 
1772
                        {
 
1773
                                closestAtom = null;
 
1774
                        } else {
 
1775
                                // we got a winner!
 
1776
                                // set the associated AtomContainer, for use by JCP's Molecule Properties action
 
1777
                // COMMENTED OUT: causes cloning trouble
 
1778
/*                              closestAtom.setProperty(
 
1779
                                        SimpleController2D.MATCHING_ATOMCONTAINER,
 
1780
                                        ChemModelManipulator.getRelevantAtomContainer(chemModel, closestAtom)
 
1781
                                );*/
 
1782
                        }
 
1783
                }
 
1784
                return closestAtom;
 
1785
        }
 
1786
 
 
1787
        private IAtomContainer getBondInRangeTemporaryAtomContainer = null;
 
1788
 
 
1789
        /**
 
1790
         *  Returns a Bond if it is in a certain range of the given point. Used to
 
1791
         *  highlight a bond that is near the cursor. <p>
 
1792
         *
 
1793
         *  <b>Important: the coordinates must be given in world coordinates and not in
 
1794
         *  screen coordinates!
 
1795
         *
 
1796
         *@param  X  The x world coordinate of the point
 
1797
         *@param  Y  The y world coordinate of the point
 
1798
         *@return    An Atom if it is in a certain range of the given point
 
1799
         */
 
1800
        private IBond getBondInRange(int X, int Y) {
 
1801
                if (getBondInRangeTemporaryAtomContainer == null) {
 
1802
                        getBondInRangeTemporaryAtomContainer = chemModel.getBuilder().newAtomContainer();
 
1803
                } else {
 
1804
                        getBondInRangeTemporaryAtomContainer.removeAllElements();
 
1805
                }
 
1806
        double highlightRadius = r2dm.getHighlightRadius();
 
1807
                Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
 
1808
                while (atomCons.hasNext()) {
 
1809
                        getBondInRangeTemporaryAtomContainer.add((IAtomContainer)atomCons.next());
 
1810
                }
 
1811
        if (getBondInRangeTemporaryAtomContainer.getBondCount() != 0) {
 
1812
            IBond closestBond = GeometryTools.getClosestBond(X, Y, getBondInRangeTemporaryAtomContainer,r2dm.getRenderingCoordinates());
 
1813
                if (closestBond == null)
 
1814
                {
 
1815
                        return null;
 
1816
                }
 
1817
                // logger.debug("closestBond  "+ closestBond);
 
1818
                int[] coords = GeometryTools.distanceCalculator(
 
1819
                                GeometryTools.getBondCoordinates(closestBond, r2dm.getRenderingCoordinates()), highlightRadius);
 
1820
                int[] xCoords = {coords[0], coords[2], coords[4], coords[6]};
 
1821
                int[] yCoords = {coords[1], coords[3], coords[5], coords[7]};
 
1822
                if ((new Polygon(xCoords, yCoords, 4)).contains(new Point(X, Y)))
 
1823
                {
 
1824
                        return closestBond;
 
1825
                }
 
1826
        }
 
1827
                return null;
 
1828
        }
 
1829
 
 
1830
        abstract IReaction getReactionInRange(int X, int Y);
 
1831
 
 
1832
        /**
 
1833
         *  Returns an AtomContainer that contains the atom or the the bond with its
 
1834
         *  two atoms that are highlighted at the moment.
 
1835
         *
 
1836
         *@return    An AtomContainer containig the highlighted atom\atoms\bond
 
1837
         */
 
1838
         IAtomContainer getHighlighted()
 
1839
        {
 
1840
                IAtomContainer highlighted = chemModel.getBuilder().newAtomContainer();
 
1841
                IAtom highlightedAtom = r2dm.getHighlightedAtom();
 
1842
                IBond highlightedBond = r2dm.getHighlightedBond();
 
1843
                if (highlightedAtom != null)
 
1844
                {
 
1845
                        highlighted.addAtom(highlightedAtom);
 
1846
                } else if (highlightedBond != null)
 
1847
                {
 
1848
                        highlighted.addBond(highlightedBond);
 
1849
                        for (int i = 0; i < highlightedBond.getAtomCount(); i++)
 
1850
                        {
 
1851
                                highlighted.addAtom(highlightedBond.getAtom(i));
 
1852
                        }
 
1853
                }
 
1854
                logger.debug("sharedAtoms  ", highlighted);
 
1855
                return highlighted;
 
1856
        }
 
1857
 
 
1858
 
 
1859
        /**
 
1860
         *  Constructs a new Ring of a certain size that contains all the atoms and
 
1861
         *  bonds of the given AtomContainer and is filled up with new Atoms and Bonds.
 
1862
         *
 
1863
         *@param  sharedAtoms  The AtomContainer containing the Atoms and bonds for the
 
1864
         *      new Ring
 
1865
         *@param  ringSize     The size (number of Atoms) the Ring will have
 
1866
         *@param  symbol       The element symbol the new atoms will have
 
1867
         *@return              The constructed Ring
 
1868
         */
 
1869
         IRing createAttachRing(IAtomContainer sharedAtoms, int ringSize, String symbol)
 
1870
        {
 
1871
                IRing newRing = sharedAtoms.getBuilder().newRing(ringSize);
 
1872
                IAtom[] ringAtoms = new IAtom[ringSize];
 
1873
                for (int i = 0; i < sharedAtoms.getAtomCount(); i++)
 
1874
                {
 
1875
                        ringAtoms[i] = sharedAtoms.getAtom(i);
 
1876
                }
 
1877
                for (int i = sharedAtoms.getAtomCount(); i < ringSize; i++)
 
1878
                {
 
1879
                        ringAtoms[i] = sharedAtoms.getBuilder().newAtom(symbol);
 
1880
                }
 
1881
                Iterator bonds = sharedAtoms.bonds();
 
1882
                while (bonds.hasNext())
 
1883
                {
 
1884
                        newRing.addBond((IBond)bonds.next());
 
1885
                }
 
1886
                for (int i = sharedAtoms.getBondCount(); i < ringSize - 1; i++)
 
1887
                {
 
1888
                        newRing.addBond(sharedAtoms.getBuilder().newBond(ringAtoms[i], ringAtoms[i + 1], 1));
 
1889
                }
 
1890
                newRing.addBond(sharedAtoms.getBuilder().newBond(ringAtoms[ringSize - 1], ringAtoms[0], 1));
 
1891
                newRing.setAtoms(ringAtoms);
 
1892
                return newRing;
 
1893
        }
 
1894
 
 
1895
 
 
1896
        /**
 
1897
         *  Searches all the atoms attached to the Atoms in the given AtomContainer and
 
1898
         *  calculates the center point of them.
 
1899
         *
 
1900
         *@param  sharedAtoms  The Atoms the attached partners are searched of
 
1901
         *@return              The Center Point of all the atoms found
 
1902
         */
 
1903
         Point2d getConnectedAtomsCenter(IAtomContainer sharedAtoms)
 
1904
        {
 
1905
                IAtom currentAtom;
 
1906
                //IAtom[] conAtomsArray;
 
1907
                IAtomContainer conAtoms = sharedAtoms.getBuilder().newAtomContainer();
 
1908
                for (int i = 0; i < sharedAtoms.getAtomCount(); i++)
 
1909
                {
 
1910
                        currentAtom = sharedAtoms.getAtom(i);
 
1911
                        conAtoms.addAtom(currentAtom);
 
1912
                        IAtomContainer atomCon = ChemModelManipulator.getRelevantAtomContainer(chemModel, currentAtom);
 
1913
                        java.util.Iterator atoms = atomCon.getConnectedAtomsList(currentAtom).iterator();
 
1914
                        while (atoms.hasNext())
 
1915
                        {
 
1916
                                conAtoms.addAtom((IAtom)atoms.next());
 
1917
                        }
 
1918
                }
 
1919
                return GeometryTools.get2DCenter(conAtoms,r2dm.getRenderingCoordinates());
 
1920
        }
 
1921
 
 
1922
 
 
1923
        /**
 
1924
         *  Returns an AtomContainer with all the atoms and bonds that are inside a
 
1925
         *  given polygon.
 
1926
         *
 
1927
         *@param  polygon  The given Polygon
 
1928
         *@return          AtomContainer with all atoms and bonds inside the polygon
 
1929
         */
 
1930
         IAtomContainer getContainedAtoms(Polygon polygon)
 
1931
        {
 
1932
                IAtom currentAtom;
 
1933
                IBond currentBond;
 
1934
                IAtomContainer selectedPart = chemModel.getBuilder().newAtomContainer();
 
1935
                Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
 
1936
                while (atomCons.hasNext()) {
 
1937
                        IAtomContainer atomCon = (IAtomContainer)atomCons.next();
 
1938
                        for (int i = 0; i < atomCon.getAtomCount(); i++)
 
1939
                        {
 
1940
                                currentAtom = atomCon.getAtom(i);
 
1941
                                logger.debug("Atom: ", currentAtom);
 
1942
                                if (polygon.contains(new Point((int) ((Point2d)r2dm.getRenderingCoordinate(currentAtom)).x, (int) ((Point2d)r2dm.getRenderingCoordinate(currentAtom)).y)))
 
1943
                                {
 
1944
                                        selectedPart.addAtom(currentAtom);
 
1945
                                }
 
1946
                        }
 
1947
                        Iterator bonds = atomCon.bonds();
 
1948
                        while (bonds.hasNext())
 
1949
                        {
 
1950
                                currentBond = (IBond)bonds.next();
 
1951
                                for (int j = 0; j < selectedPart.getAtomCount(); j++)
 
1952
                                {
 
1953
                                        currentAtom = selectedPart.getAtom(j);
 
1954
                                        if (selectedPart.contains(currentBond.getConnectedAtom(currentAtom)))
 
1955
                                        {
 
1956
                                                selectedPart.addBond(currentBond);
 
1957
                                                break;
 
1958
                                        }
 
1959
                                }
 
1960
                        }
 
1961
                }
 
1962
                return selectedPart;
 
1963
        }
 
1964
 
 
1965
 
 
1966
        /**
 
1967
         *  This methods corrects for the zoom factor, and thus transforms screen
 
1968
         *  coordinates back into world coordinates. IMPORTANT: even coords are taken
 
1969
         *  as y coordinates, uneven as x coordinates.
 
1970
         *
 
1971
         *@param  coords  the array of coordinates to be used
 
1972
         *@return         The worldCoordinates value
 
1973
         */
 
1974
        public int[] getWorldCoordinates(int[] coords)
 
1975
        {
 
1976
                int[] worldCoords = new int[coords.length];
 
1977
                int coordCount = coords.length / 2;
 
1978
                //logger.debug("coord.length: ", coords.length);
 
1979
                int height = (int) (r2dm.getBackgroundDimension()).getHeight();
 
1980
                for (int i = 0; i < coordCount; i++)
 
1981
                {
 
1982
                        worldCoords[i * 2] = (int) ((double) coords[i * 2] / r2dm.getZoomFactor());
 
1983
                        worldCoords[i * 2 + 1] = (int) ((double) (height - coords[i * 2 + 1]) / r2dm.getZoomFactor());
 
1984
                        if (logger.isDebugEnabled())
 
1985
                        {
 
1986
                                //logger.debug("getWorldCoord: " + coords[i * 2] + " -> " + worldCoords[i * 2]);
 
1987
                                //logger.debug("getWorldCoord: " + coords[i * 2 + 1] + " -> " + worldCoords[i * 2 + 1]);
 
1988
                        }
 
1989
                }
 
1990
                return worldCoords;
 
1991
        }
 
1992
 
 
1993
 
 
1994
        /**
 
1995
         *  Adds a change listener to the list of listeners
 
1996
         *
 
1997
         *@param  listener  The listener added to the list
 
1998
         */
 
1999
 
 
2000
        public void addCDKChangeListener(ICDKChangeListener listener)
 
2001
        {
 
2002
                listeners.add(listener);
 
2003
        }
 
2004
 
 
2005
 
 
2006
        /**
 
2007
         *  Removes a change listener from the list of listeners
 
2008
         *
 
2009
         *@param  listener  The listener removed from the list
 
2010
         */
 
2011
        public void removeCDKChangeListener(ICDKChangeListener listener)
 
2012
        {
 
2013
                listeners.remove(listener);
 
2014
        }
 
2015
 
 
2016
 
 
2017
        /**
 
2018
         *  Notifies registered listeners of certain changes that have occurred in this
 
2019
         *  model.
 
2020
         */
 
2021
        public void fireChange()
 
2022
        {
 
2023
                EventObject event = new EventObject(this);
 
2024
                for (int i = 0; i < listeners.size(); i++)
 
2025
                {
 
2026
                        ((ICDKChangeListener) listeners.get(i)).stateChanged(event);
 
2027
                }
 
2028
        }
 
2029
 
 
2030
 
 
2031
        // ------------ CHEMICAL OPERATIONS -------------- //
 
2032
 
 
2033
        /**
 
2034
         *  Highlight the nearest Atom or Bond. <p>
 
2035
         *
 
2036
         *  FIXME: this needs to be extended for other ChemObjects.
 
2037
         *
 
2038
         *@param  mouseX  x coordinate in world coordinates (not screen coordinates)
 
2039
         *@param  mouseY  y coordinate in world coordinates (not screen coordinates)
 
2040
         */
 
2041
         void highlightNearestChemObject(int mouseX, int mouseY)
 
2042
        {
 
2043
                IChemObject objectInRange = getChemObjectInRange(mouseX, mouseY);
 
2044
                if (objectInRange instanceof IAtom)
 
2045
                {
 
2046
                        r2dm.setHighlightedAtom((IAtom) objectInRange);
 
2047
                        r2dm.setHighlightedBond(null);
 
2048
                } else if (objectInRange instanceof IBond)
 
2049
                {
 
2050
                        r2dm.setHighlightedBond((IBond) objectInRange);
 
2051
                        r2dm.setHighlightedAtom(null);
 
2052
                } else
 
2053
                {
 
2054
                        r2dm.setHighlightedBond(null);
 
2055
                        r2dm.setHighlightedAtom(null);
 
2056
                }
 
2057
        }
 
2058
 
 
2059
 
 
2060
        /**
 
2061
         *  Create a new bond. Possibly connecting the end point to the nearest Atom.
 
2062
         *  <p>
 
2063
         *
 
2064
         *  All coordinates are world coordinates.
 
2065
         *
 
2066
         *@param  startX  Start X coordinate of the new bond
 
2067
         *@param  startY  Start Y coordinate of the new bond
 
2068
         *@param  endX  End X coordinate of the new bond
 
2069
         *@param  endY  End Y coordinate of the new bond
 
2070
         */
 
2071
         void createNewBond(int startX, int startY, int endX, int endY)
 
2072
        {
 
2073
 
 
2074
        }
 
2075
 
 
2076
 
 
2077
        /**
 
2078
         *  Draws a proposed bond, i.e. shows the bond direction
 
2079
         *  during dragging of the mouse
 
2080
         *
 
2081
         *@param  startX  Start X coordinate of the proposed bond
 
2082
         *@param  startY  Start Y coordinate of the proposed bond
 
2083
         *@param  mouseX  Current X mouse coordinate
 
2084
         *@param  mouseY  Current Y mouse coordinate
 
2085
         */
 
2086
         void drawProposedBond(int startX, int startY, int mouseX, int mouseY)
 
2087
        {
 
2088
                logger.debug("Drawing proposed bond...");
 
2089
                int endX = 0;
 
2090
                int endY = 0;
 
2091
                double pointerVectorLength = c2dm.getBondPointerLength();
 
2092
                double angle = 0;
 
2093
                IAtom atomInRange;
 
2094
 
 
2095
                angle = GeometryTools.getAngle(startX - mouseX, startY - mouseY);
 
2096
                if (c2dm.getSnapToGridAngle())
 
2097
                {
 
2098
                        angle = snapAngle(angle);
 
2099
                }
 
2100
                atomInRange = getAtomInRange(mouseX, mouseY);
 
2101
                if (atomInRange != null)
 
2102
                {
 
2103
                        endX = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).x;
 
2104
                        endY = (int) ((Point2d)r2dm.getRenderingCoordinate(atomInRange)).y;
 
2105
                } else
 
2106
                {
 
2107
                        endX = startX - (int) (Math.cos(angle) * pointerVectorLength);
 
2108
                        endY = startY - (int) (Math.sin(angle) * pointerVectorLength);
 
2109
                }
 
2110
                logger.debug("End point: " + endX + ", " + endY);
 
2111
                logger.debug("Start point: " + startX + ", " + startY);
 
2112
                r2dm.setPointerVectorEnd(new Point(endX, endY));
 
2113
        }
 
2114
 
 
2115
 
 
2116
        /**
 
2117
         *  Selects a rectangular area on the screen 
 
2118
         *
 
2119
         *@param  startX  Start x coordinate
 
2120
         *@param  startY  Start y coordinate
 
2121
         *@param  mouseX  Current x mouse position
 
2122
         *@param  mouseY  Current y mouse position
 
2123
         */
 
2124
         void selectRectangularArea(int startX, int startY, int mouseX, int mouseY)
 
2125
        {
 
2126
                int[] xPoints = {startX, startX, mouseX, mouseX};
 
2127
                int[] yPoints = {startY, mouseY, mouseY, startY};
 
2128
                r2dm.setSelectRect(new Polygon(xPoints, yPoints, 4));
 
2129
        }
 
2130
 
 
2131
 
 
2132
        /**
 
2133
         *  Move an Atom by the specified change in coordinates.
 
2134
         *
 
2135
         *@param  deltaX  change in x direction
 
2136
         *@param  deltaY  change in y direction
 
2137
         */
 
2138
         void moveSelectedAtomsWith(int deltaX, int deltaY)
 
2139
        {
 
2140
                IAtomContainer container = r2dm.getSelectedPart();
 
2141
                if (container != null)
 
2142
                {
 
2143
                        // only move selected atoms if count > 0
 
2144
                        java.util.Iterator atoms = container.atoms();
 
2145
                        while (atoms.hasNext())
 
2146
                        {
 
2147
                                IAtom atom = (IAtom)atoms.next();
 
2148
                                atom.setNotification(false);
 
2149
                                atom.getPoint2d().x += deltaX;
 
2150
                                atom.getPoint2d().y += deltaY;
 
2151
                                atom.setNotification(true);
 
2152
                                ((Point2d)r2dm.getRenderingCoordinate(atom)).x+=deltaX;
 
2153
                                ((Point2d)r2dm.getRenderingCoordinate(atom)).y+=deltaY;
 
2154
                        }
 
2155
                        r2dm.getSelectedPart().notifyChanged();
 
2156
                }
 
2157
        }
 
2158
         
 
2159
         /**
 
2160
         * This updates the coordinates in the point2ds of the atoms with the renderingcoordinates in r2dm. This should be called
 
2161
         * after a change of the structure (e. g. adding atoms), since we cannot and do not need to preserve original coordinates after this.
 
2162
         */
 
2163
        private void updateMoleculeCoordinates(){
 
2164
                Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
 
2165
                while (atomCons.hasNext()) {
 
2166
                        IAtomContainer atomCon = (IAtomContainer)atomCons.next();
 
2167
                        for (int i = 0; i < atomCon.getAtomCount(); i++)
 
2168
                        {
 
2169
                                IAtom currentAtom = atomCon.getAtom(i);
 
2170
                                if(r2dm.getRenderingCoordinate(currentAtom)!=null){
 
2171
                                        currentAtom.setPoint2d(new Point2d((Point2d)r2dm.getRenderingCoordinate(currentAtom)));
 
2172
                                }
 
2173
                        }
 
2174
                }
 
2175
         }
 
2176
 
 
2177
 
 
2178
        /**
 
2179
         *  Selects the nearest item on the screen next to the 
 
2180
         *  mouse pointer, if none is selected yet
 
2181
         *
 
2182
         *  @param  mouseX  The current X coordinate of the mouse
 
2183
         *  @param  mouseY  The current Y coordinate of the mouse
 
2184
         */
 
2185
         void selectNearestChemObjectIfNoneSelected(int mouseX, int mouseY)
 
2186
        {
 
2187
                IAtomContainer container = r2dm.getSelectedPart();
 
2188
                if (container == null || (container.getAtomCount() == 0))
 
2189
                {
 
2190
                        // if no atoms are selected, then temporarily select nearest
 
2191
                        // to make sure to original state is reached again when the
 
2192
                        // mouse is released, the draggingSelected boolean is set
 
2193
                        logger.warn("No atoms selected: temporarily selecting nearest atom/bond");
 
2194
                        draggingSelected = false;
 
2195
                        IAtomContainer selected = chemModel.getBuilder().newAtomContainer();
 
2196
                        IAtom atomInRange = getAtomInRange(mouseX, mouseY);
 
2197
                        if (atomInRange != null)
 
2198
                        {
 
2199
                                selected.addAtom(atomInRange);
 
2200
                                r2dm.setSelectedPart(selected);
 
2201
                        } else
 
2202
                        {
 
2203
                                IBond bondInRange = getBondInRange(mouseX, mouseY);
 
2204
                                // because only atoms are dragged, select the atoms
 
2205
                                // in the bond, instead of the bond itself
 
2206
                                if (bondInRange != null)
 
2207
                                {
 
2208
                                        java.util.Iterator atoms = bondInRange.atoms();
 
2209
                                        while (atoms.hasNext())
 
2210
                                        {
 
2211
                                                selected.addAtom((IAtom)atoms.next());
 
2212
                                        }
 
2213
                                        r2dm.setSelectedPart(selected);
 
2214
                                }
 
2215
                        }
 
2216
                        logger.debug("Selected: ", selected);
 
2217
                        fireChange();
 
2218
                }
 
2219
        }
 
2220
 
 
2221
 
 
2222
        /**
 
2223
         * Centers an atom on a given background dimension
 
2224
         *
 
2225
         * @param  atom  The Atom to be centered
 
2226
         */
 
2227
         void centerAtom(IAtom atom, IChemModel chemModel)
 
2228
        {
 
2229
                 double smallestx=Integer.MAX_VALUE;
 
2230
                 double largestx=Integer.MIN_VALUE;
 
2231
                 double smallesty=Integer.MAX_VALUE;
 
2232
                 double largesty=Integer.MIN_VALUE;
 
2233
                 Iterator atomCons = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
 
2234
                 while (atomCons.hasNext()) {
 
2235
                         IAtomContainer atomCon = (IAtomContainer)atomCons.next();
 
2236
                         for(int i=0;i<atomCon.getAtomCount();i++){
 
2237
                                 if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x<smallestx)
 
2238
                                         smallestx=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x;
 
2239
                                 if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y<smallesty)
 
2240
                                         smallesty=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y;
 
2241
                                 if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x>largestx)
 
2242
                                         largestx=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).x;
 
2243
                                 if(((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y>largesty)
 
2244
                                         largesty=((Point2d)r2dm.getRenderingCoordinate(atomCon.getAtom(i))).y;
 
2245
                         }
 
2246
                 }
 
2247
                 int xstretch=((int)(largestx-smallestx))+20;
 
2248
                 int ystretch=((int)(largesty-smallesty))+20;
 
2249
                 if(xstretch<r2dm.getBackgroundDimension().width)
 
2250
                         xstretch=r2dm.getBackgroundDimension().width;
 
2251
                 if(ystretch<r2dm.getBackgroundDimension().height)
 
2252
                         ystretch=r2dm.getBackgroundDimension().height;
 
2253
                 r2dm.setBackgroundDimension(new Dimension(xstretch,ystretch));
 
2254
                if (atom == null)
 
2255
                {
 
2256
                        return;
 
2257
                }
 
2258
                if (((Point2d)r2dm.getRenderingCoordinate(atom)).x < 0 && shiftX > ((Point2d)r2dm.getRenderingCoordinate(atom)).x - 10)
 
2259
                {
 
2260
                        shiftX = ((Point2d)r2dm.getRenderingCoordinate(atom)).x - 10;
 
2261
                }
 
2262
                if (((Point2d)r2dm.getRenderingCoordinate(atom)).x > r2dm.getBackgroundDimension().getWidth() && shiftX < ((Point2d)r2dm.getRenderingCoordinate(atom)).x - r2dm.getBackgroundDimension().getWidth() + 10)
 
2263
                {
 
2264
                        shiftX = ((Point2d)r2dm.getRenderingCoordinate(atom)).x - r2dm.getBackgroundDimension().getWidth() + 10;
 
2265
                }
 
2266
                if (((Point2d)r2dm.getRenderingCoordinate(atom)).y < 0 && shiftY > ((Point2d)r2dm.getRenderingCoordinate(atom)).y - 10)
 
2267
                {
 
2268
                        shiftY = ((Point2d)r2dm.getRenderingCoordinate(atom)).y - 10;
 
2269
                }
 
2270
                if (((Point2d)r2dm.getRenderingCoordinate(atom)).y > r2dm.getBackgroundDimension().getHeight() && shiftY < ((Point2d)r2dm.getRenderingCoordinate(atom)).y - r2dm.getBackgroundDimension().getHeight() + 10)
 
2271
                {
 
2272
                        shiftY = ((Point2d)r2dm.getRenderingCoordinate(atom)).y - r2dm.getBackgroundDimension().getHeight() + 10;
 
2273
                }
 
2274
        }
 
2275
        
 
2276
 
 
2277
        void handleMapping(boolean wasDragged, Renderer2DModel r2dm)
 
2278
        {
 
2279
                logger.debug("Should make new mapping...");
 
2280
                if (wasDragged)
 
2281
                {
 
2282
                        int endX = r2dm.getPointerVectorEnd().x;
 
2283
                        int endY = r2dm.getPointerVectorEnd().y;
 
2284
                        IAtom mappedToAtom = getAtomInRange(endX, endY);
 
2285
                        if (mappedToAtom != null)
 
2286
                        {
 
2287
                                int startX = r2dm.getPointerVectorStart().x;
 
2288
                                int startY = r2dm.getPointerVectorStart().y;
 
2289
                                IAtom mappedFromAtom = getAtomInRange(startX, startY);
 
2290
                                if (mappedFromAtom != null)
 
2291
                                {
 
2292
                                        IMapping mapping = mappedFromAtom.getBuilder().newMapping(mappedFromAtom, mappedToAtom);
 
2293
                                        logger.debug("Created mapping: ", mapping);
 
2294
                                        logger.debug("  between ", mappedFromAtom);
 
2295
                                        logger.debug("  and ", mappedToAtom);
 
2296
                                        // ok, now figure out if they are in one reaction
 
2297
                                        IReaction reaction1 = ChemModelManipulator.getRelevantReaction(chemModel, mappedFromAtom);
 
2298
                                        IReaction reaction2 = ChemModelManipulator.getRelevantReaction(chemModel, mappedToAtom);
 
2299
                                        if (reaction1 != null && reaction2 != null && reaction1 == reaction2)
 
2300
                                        {
 
2301
                                                logger.debug("Adding mapping to reaction: ", reaction1.getID());
 
2302
                                                ((IReaction)reaction1).addMapping(mapping);
 
2303
                                        } else
 
2304
                                        {
 
2305
                                                logger.warn("Reactions do not match, or one or both are reactions are null");
 
2306
                                        }
 
2307
                                } else
 
2308
                                {
 
2309
                                        logger.debug("Dragging did not start in atom...");
 
2310
                                }
 
2311
                        } else
 
2312
                        {
 
2313
                                logger.debug("Dragging did not end in atom...");
 
2314
                        }
 
2315
                } else
 
2316
                {
 
2317
                        logger.debug("Not dragged in mapping mode");
 
2318
                }
 
2319
        }
 
2320
        
 
2321
        abstract IReaction getRelevantReaction(IChemModel model, IAtom atom);
 
2322
 
 
2323
 
 
2324
        public IChemModel getChemModel() {
 
2325
                return chemModel;
 
2326
        }
 
2327
 
 
2328
        public void setChemModel(IChemModel chemModel) {
 
2329
                this.chemModel = chemModel;
 
2330
        }
 
2331
 
 
2332
        public void setUndoRedoHandler(IUndoRedoHandler undoRedoHandler) {
 
2333
                this.undoRedoHandler = undoRedoHandler;
 
2334
        }
 
2335
 
 
2336
        public HashMap getFuncgroupsmap() {
 
2337
                return funcgroupsmap;
 
2338
        }
 
2339
 
 
2340
        public void setFuncgroupsmap(HashMap funcgroupsmap) {
 
2341
                this.funcgroupsmap = funcgroupsmap;
 
2342
        }
 
2343
        
 
2344
        static class EnterElementOrGroupDialog extends JDialog implements ActionListener {
 
2345
                
 
2346
            private static EnterElementOrGroupDialog dialog;
 
2347
            private static String value = "";
 
2348
            private JComboBox list;
 
2349
 
 
2350
            /**
 
2351
             * Set up and show the dialog.  The first Component argument
 
2352
             * determines which frame the dialog depends on; it should be
 
2353
             * a component in the dialog's controlling frame. The second
 
2354
             * Component argument should be null if you want the dialog
 
2355
             * to come up with its left corner in the center of the screen;
 
2356
             * otherwise, it should be the component on top of which the
 
2357
             * dialog should appear.
 
2358
             */
 
2359
            public static String showDialog(Component frameComp,
 
2360
                                            Component locationComp,
 
2361
                                            String labelText,
 
2362
                                            String title,
 
2363
                                            String[] possibleValues,
 
2364
                                            String initialValue,
 
2365
                                            String longValue) {
 
2366
                Frame frame = JOptionPane.getFrameForComponent(frameComp);
 
2367
                dialog = new EnterElementOrGroupDialog(frame,
 
2368
                                        locationComp,
 
2369
                                        labelText,
 
2370
                                        title,
 
2371
                                        possibleValues,
 
2372
                                        initialValue,
 
2373
                                        longValue);
 
2374
                dialog.setVisible(true);
 
2375
                return value;
 
2376
            }
 
2377
 
 
2378
            private EnterElementOrGroupDialog(Frame frame,
 
2379
                               Component locationComp,
 
2380
                               String labelText,
 
2381
                               String title,
 
2382
                               Object[] data,
 
2383
                               String initialValue,
 
2384
                               String longValue) {
 
2385
                super(frame, title, true);
 
2386
 
 
2387
                //Create and initialize the buttons.
 
2388
                JButton cancelButton = new JButton("Cancel");
 
2389
                cancelButton.addActionListener(this);
 
2390
                //
 
2391
                final JButton setButton = new JButton("Ok");
 
2392
                setButton.setActionCommand("Set");
 
2393
                setButton.addActionListener(this);
 
2394
                getRootPane().setDefaultButton(setButton);
 
2395
 
 
2396
                //main part of the dialog
 
2397
                list = new JComboBox(data);
 
2398
                list.setEditable(true);
 
2399
                JPanel listPane = new JPanel();
 
2400
                listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
 
2401
                JLabel label = new JLabel(labelText);
 
2402
                label.setLabelFor(list);
 
2403
                listPane.add(label);
 
2404
                listPane.add(Box.createRigidArea(new Dimension(0,5)));
 
2405
                listPane.add(list);
 
2406
                listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
 
2407
 
 
2408
                //Lay out the buttons from left to right.
 
2409
                JPanel buttonPane = new JPanel();
 
2410
                buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
 
2411
                buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
 
2412
                buttonPane.add(Box.createHorizontalGlue());
 
2413
                buttonPane.add(cancelButton);
 
2414
                buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
 
2415
                buttonPane.add(setButton);
 
2416
 
 
2417
                //Put everything together, using the content pane's BorderLayout.
 
2418
                Container contentPane = getContentPane();
 
2419
                contentPane.add(listPane, BorderLayout.CENTER);
 
2420
                contentPane.add(buttonPane, BorderLayout.PAGE_END);
 
2421
 
 
2422
                //Initialize values.
 
2423
                pack();
 
2424
                setLocationRelativeTo(locationComp);
 
2425
            }
 
2426
 
 
2427
            //Handle clicks on the Set and Cancel buttons.
 
2428
            public void actionPerformed(ActionEvent e) {
 
2429
                if ("Set".equals(e.getActionCommand())) {
 
2430
                    EnterElementOrGroupDialog.value = (String)(list.getSelectedItem());
 
2431
                }
 
2432
                if(e.getActionCommand().equals("Cancel")){
 
2433
                        EnterElementOrGroupDialog.value="";
 
2434
                }
 
2435
                EnterElementOrGroupDialog.dialog.setVisible(false);
 
2436
            }
 
2437
        }
 
2438
 
 
2439
}
 
2440