3
* Copyright (C) 2001-2007 Rajarshi Guha <rajarshi@users.sourceforge.net>
5
* Contact: cdk-devel@lists.sourceforge.net
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 we ask is that proper credit is given for our 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.
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.
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.
26
package org.openscience.cdk.applications.jchempaint;
28
import java.awt.GridBagConstraints;
29
import java.awt.GridBagLayout;
30
import java.awt.Insets;
31
import java.awt.event.ActionEvent;
32
import java.awt.event.ActionListener;
33
import java.io.BufferedReader;
34
import java.io.IOException;
35
import java.io.InputStreamReader;
37
import java.util.ArrayList;
38
import java.util.Iterator;
39
import java.util.List;
40
import java.util.regex.Matcher;
41
import java.util.regex.Pattern;
43
import javax.swing.JButton;
44
import javax.swing.JComboBox;
45
import javax.swing.JFrame;
46
import javax.swing.JOptionPane;
47
import javax.swing.JPanel;
48
import javax.swing.text.JTextComponent;
49
import javax.vecmath.Vector2d;
51
import net.sf.jniinchi.INCHI_RET;
53
import org.openscience.cdk.DefaultChemObjectBuilder;
54
import org.openscience.cdk.MoleculeSet;
55
import org.openscience.cdk.exception.CDKException;
56
import org.openscience.cdk.exception.InvalidSmilesException;
57
import org.openscience.cdk.geometry.GeometryTools;
58
import org.openscience.cdk.inchi.InChIGeneratorFactory;
59
import org.openscience.cdk.inchi.InChIToStructure;
60
import org.openscience.cdk.interfaces.IAtomContainer;
61
import org.openscience.cdk.interfaces.IMolecule;
62
import org.openscience.cdk.layout.StructureDiagramGenerator;
63
import org.openscience.cdk.layout.TemplateHandler;
64
import org.openscience.cdk.renderer.Renderer2DModel;
65
import org.openscience.cdk.smiles.SmilesParser;
66
import org.openscience.cdk.tools.manipulator.ChemModelManipulator;
69
* A panel containing a text field and button to directly insert SMILES or InChI's
71
* @author Rajarshi Guha
72
* @cdk.module jchempaint
75
public class InsertTextPanel extends JPanel implements ActionListener {
77
private JChemPaintPanel jChemPaintPanel;
78
private JComboBox textCombo;
79
private JTextComponent editor;
80
private JFrame closeafter=null;
83
public InsertTextPanel(JChemPaintPanel jChemPaintPanel, JFrame closeafter) {
85
this.closeafter=closeafter;
86
setLayout(new GridBagLayout());
88
List oldText = new ArrayList();
91
textCombo = new JComboBox(oldText.toArray());
92
textCombo.setEditable(true);
93
textCombo.setToolTipText("Enter a CAS, SMILES or InChI string");
95
textCombo.addActionListener(this);
96
editor = (JTextComponent) textCombo.getEditor().getEditorComponent();
99
JButton button = new JButton("Insert");
100
button.addActionListener(this);
102
GridBagConstraints gridBagConstraints = new GridBagConstraints();
105
gridBagConstraints.gridx = 0;
106
gridBagConstraints.gridy = 0;
107
gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
108
gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
109
gridBagConstraints.weightx = 0.5;
110
gridBagConstraints.ipadx = 5;
111
gridBagConstraints.insets = new Insets(0, 0, 0, 5);
112
add(textCombo, gridBagConstraints);
114
gridBagConstraints.insets = new Insets(0, 0, 2, 0);
115
gridBagConstraints.ipadx = 5;
116
gridBagConstraints.ipady = 2;
117
gridBagConstraints.weightx = 0.0;
118
gridBagConstraints.gridx = 1;
119
add(button, gridBagConstraints);
122
this.jChemPaintPanel = jChemPaintPanel;
125
public void actionPerformed(ActionEvent actionEvent) {
126
String actionCommand = actionEvent.getActionCommand();
127
if (actionCommand.equals("comboBoxEdited") || actionCommand.equals("Insert")) {
128
IMolecule molecule = getMolecule();
129
if (molecule == null) return;
130
generateModel(molecule);
132
closeafter.setVisible(false);
136
private IMolecule getMolecule() {
139
String text = (String) textCombo.getSelectedItem();
140
text = text.trim(); // clean up extra white space
142
if (text.equals("")) return null;
144
if (text.startsWith("InChI")) { // handle it as an InChI
146
InChIGeneratorFactory inchiFactory = new InChIGeneratorFactory();
147
InChIToStructure inchiToStructure = inchiFactory.getInChIToStructure(text);
148
INCHI_RET status = inchiToStructure.getReturnStatus();
149
if (status != INCHI_RET.OKAY) {
150
JOptionPane.showMessageDialog(jChemPaintPanel, "Could not process InChI");
153
IAtomContainer atomContainer = inchiToStructure.getAtomContainer();
154
molecule = atomContainer.getBuilder().newMolecule(atomContainer);
155
} catch (CDKException e2) {
156
JOptionPane.showMessageDialog(jChemPaintPanel, "Could not load InChI subsystem");
159
} else if (isCASNumber(text)) { // is it a CAS number?
161
molecule = getMoleculeFromCAS(text);
162
} catch (IOException e) {
163
JOptionPane.showMessageDialog(jChemPaintPanel, "Error in reading data from PubChem");
166
} else { // OK, it must be a SMILES
167
SmilesParser smilesParser = new SmilesParser(DefaultChemObjectBuilder.getInstance());
169
molecule = smilesParser.parseSmiles(text);
170
} catch (InvalidSmilesException e1) {
171
JOptionPane.showMessageDialog(jChemPaintPanel, "Invalid SMILES specified");
176
// OK, we have a valid molecule, save it and show it
177
String tmp = (String) textCombo.getItemAt(0);
178
if (tmp.equals("")) textCombo.removeItemAt(0);
179
textCombo.addItem(text);
185
private boolean isCASNumber(String text) {
186
String[] chars = text.split("-");
187
if (chars.length != 3) return false;
188
for (int i = 0; i < 3; i++) {
189
if (i == 2 && chars[i].length() != 1) return false;
190
if (i == 1 && chars[i].length() != 2) return false;
191
if (i == 0 && chars[i].length() > 6) return false;
193
Integer.parseInt(chars[i]);
194
} catch (NumberFormatException e) {
201
private IMolecule getMoleculeFromCAS(String cas) throws IOException {
204
String firstURL = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pccompound&term=" + cas;
206
data = getDataFromURL(firstURL);
208
Pattern pattern = Pattern.compile("http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi\\?cid=(\\d*)");
209
Matcher matcher = pattern.matcher(data);
212
boolean found = false;
213
while (matcher.find()) {
214
cid = matcher.group(1);
215
try { // should be an integer
216
Integer.parseInt(cid);
219
} catch (NumberFormatException e) {
223
if (!found) return null;
225
String secondURL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?tool=jcppubchem&db=pccompound&id=" + cid;
226
data = getDataFromURL(secondURL);
228
pattern = Pattern.compile("<Item Name=\"CanonicalSmile\" Type=\"String\">([^\\s]*?)</Item>");
229
matcher = pattern.matcher(data);
230
String smiles = null;
232
while (matcher.find()) {
233
smiles = matcher.group(1);
234
if (smiles != null || !smiles.equals("")) {
239
if (!found) return null;
241
// got the canonical SMILES, lets get the molecule
242
SmilesParser smilesParser = new SmilesParser(DefaultChemObjectBuilder.getInstance());
245
molecule = smilesParser.parseSmiles(smiles);
246
} catch (InvalidSmilesException e1) {
247
JOptionPane.showMessageDialog(jChemPaintPanel, "Couldn't process data from PubChem");
253
private String getDataFromURL(String url) throws IOException {
254
URL theURL = new URL(url);
255
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(theURL.openStream()));
258
while ((line = bufferedReader.readLine()) != null) data += line;
259
bufferedReader.close();
263
public void generateModel(IMolecule molecule) {
264
if (molecule == null) return;
266
// ok, get relevent bits from active model
267
JChemPaintModel jcpModel = jChemPaintPanel.getJChemPaintModel();
268
Renderer2DModel renderModel = jcpModel.getRendererModel();
269
org.openscience.cdk.interfaces.IChemModel chemModel = jcpModel.getChemModel();
270
org.openscience.cdk.interfaces.IMoleculeSet moleculeSet = chemModel.getMoleculeSet();
271
if (moleculeSet == null) {
272
moleculeSet = new MoleculeSet();
275
// ok, now generate 2D coordinates
276
StructureDiagramGenerator sdg = new StructureDiagramGenerator();
277
sdg.setTemplateHandler(new TemplateHandler(moleculeSet.getBuilder()));
279
sdg.setMolecule(molecule);
280
sdg.generateCoordinates(new Vector2d(0, 1));
281
molecule = sdg.getMolecule();
282
double bondLength = renderModel.getBondLength();
283
double scaleFactor = GeometryTools.getScaleFactor(molecule, bondLength,jChemPaintPanel.getJChemPaintModel().getRendererModel().getRenderingCoordinates());
284
GeometryTools.scaleMolecule(molecule, scaleFactor, renderModel.getRenderingCoordinates());
285
//if there are no atoms in the actual chemModel all 2D-coordinates would be set to NaN
286
if (ChemModelManipulator.getAtomCount(chemModel) != 0) {
287
IAtomContainer container = chemModel.getBuilder().newAtomContainer();
288
Iterator containers = ChemModelManipulator.getAllAtomContainers(chemModel).iterator();
289
while (containers.hasNext()) {
290
container.add((IAtomContainer)containers.next());
292
GeometryTools.translate2DCenterTo((IAtomContainer)molecule,
293
GeometryTools.get2DCenter(container,
294
jChemPaintPanel.getJChemPaintModel().getRendererModel().getRenderingCoordinates()
296
jChemPaintPanel.getJChemPaintModel().getRendererModel().getRenderingCoordinates()
299
GeometryTools.translate2D(molecule, 5 * bondLength, 0, renderModel.getRenderingCoordinates()); // in pixels
300
} catch (Exception exc) {
301
exc.printStackTrace();
304
moleculeSet.addMolecule(molecule);
305
// renderModel.setSelectedPart(m);
306
jChemPaintPanel.getChemModel().setMoleculeSet(moleculeSet);
307
jChemPaintPanel.scaleAndCenterMolecule(jChemPaintPanel.getChemModel());
308
jcpModel.fireChange(jChemPaintPanel.getChemModel());