/* $RCSfile$ * $Author: egonw $ * $Date: 2007-05-01 18:33:49 +0200 (Tue, 01 May 2007) $ * $Revision: 8289 $ * * Copyright (C) 2005-2007 The JChemPaint project * * Contact: jchempaint-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * All we ask is that proper credit is given for our work, which includes * - but is not limited to - adding the above copyright notice to the beginning * of your source code files, and to any copyright notice that you may distribute * with programs based on this work. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.applications.jchempaint.action; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Constructor; import java.util.Iterator; import javax.swing.undo.UndoableEdit; import org.openscience.cdk.ChemFile; import org.openscience.cdk.ChemModel; import org.openscience.cdk.DefaultChemObjectBuilder; import org.openscience.cdk.Molecule; import org.openscience.cdk.MoleculeSet; import org.openscience.cdk.applications.jchempaint.JChemPaintModel; import org.openscience.cdk.applications.undoredo.AddAtomsAndBondsEdit; import org.openscience.cdk.geometry.GeometryTools; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IChemFile; import org.openscience.cdk.io.IChemObjectReader; import org.openscience.cdk.io.IChemObjectWriter; import org.openscience.cdk.io.MDLV2000Reader; import org.openscience.cdk.io.MDLWriter; import org.openscience.cdk.io.ReaderFactory; import org.openscience.cdk.io.SVGWriter; import org.openscience.cdk.layout.StructureDiagramGenerator; import org.openscience.cdk.layout.TemplateHandler; import org.openscience.cdk.renderer.Renderer2DModel; import org.openscience.cdk.smiles.SmilesGenerator; import org.openscience.cdk.smiles.SmilesParser; import org.openscience.cdk.tools.manipulator.ChemFileManipulator; /** * Action to copy/paste structures. * * @cdk.module jchempaint * @author Egon Willighagen <e.willighagen@science.ru.nl> * @cdk.bug 1288449 */ 00075 public class CopyPasteAction extends JCPAction{ private static final long serialVersionUID = -3343207264261279526L; private DataFlavor molFlavor = new DataFlavor( "chemical/x-mdl-molfile", "mdl mol file format"); private DataFlavor svgFlavor = new DataFlavor( "image/svg+xml", "scalable vector graphics"); private DataFlavor cmlFlavor = new DataFlavor( "image/cml", "chemical markup language"); 00086 public void actionPerformed(ActionEvent e) { try { handleSystemClipboard(); logger.info(" type ", type); logger.debug(" source ", e.getSource()); JChemPaintModel jcpModel = jcpPanel.getJChemPaintModel(); Renderer2DModel renderModel = jcpModel.getRendererModel(); if ("copy".equals(type)) { IAtomContainer tocopy = renderModel.getSelectedPart(); if (tocopy == null) { return; } Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard(); IAtomContainer tocopyclone=(IAtomContainer)tocopy.clone(); for(int i=0;i<tocopy.getAtomCount();i++){ tocopyclone.getAtom(i).setPoint2d(renderModel.getRenderingCoordinate(tocopy.getAtom(i))); } JcpSelection jcpselection=new JcpSelection(tocopyclone); sysClip.setContents(jcpselection,null); } else if ("paste".equals(type)) { Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable transfer = sysClip.getContents( null ); IChemObjectReader reader = null; // if a MIME type is given ... if (transfer!=null && (transfer.isDataFlavorSupported (molFlavor))) { String mol = (String) transfer.getTransferData (molFlavor); logger.debug("Dataflavor molFlavor found"); reader = new MDLV2000Reader(new StringReader(mol)); } else if(transfer!=null && (transfer.isDataFlavorSupported (DataFlavor.stringFlavor))) { // otherwise, try to use the ReaderFactory... logger.debug("Dataflavor stringFlavor found"); String content = (String) transfer.getTransferData (DataFlavor.stringFlavor); try { reader = new ReaderFactory().createReader(new StringReader(content)); } catch (Exception exception) { logger.warn("Pastes string is not recognized."); } } IAtomContainer topaste = null; if (reader != null) { if (reader.accepts(Molecule.class)) { topaste = (IAtomContainer) reader.read(new Molecule()); } else if (reader.accepts(ChemFile.class)) { topaste = new Molecule(); IChemFile file = (IChemFile)reader.read(new ChemFile()); Iterator containers = ChemFileManipulator.getAllAtomContainers(file).iterator(); while (containers.hasNext()) { topaste.add((IAtomContainer)containers.next()); } } } if(topaste==null && transfer!=null && (transfer.isDataFlavorSupported (DataFlavor.stringFlavor))) { try{ SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); topaste = sp.parseSmiles((String) transfer.getTransferData (DataFlavor.stringFlavor)); StructureDiagramGenerator sdg = new StructureDiagramGenerator((Molecule)topaste); sdg.setTemplateHandler( new TemplateHandler(topaste.getBuilder()) ); sdg.generateCoordinates(); jcpPanel.scaleAndCenterMolecule(topaste,jcpPanel.getSize()); for(int i=0;i<topaste.getAtomCount();i++){ renderModel.getRenderingCoordinates().put(topaste.getAtom(i), topaste.getAtom(i).getPoint2d()); } }catch(Exception ex){ //we just try smiles } } if (topaste != null) { topaste = (IAtomContainer)topaste.clone(); org.openscience.cdk.interfaces.IChemModel chemModel = jcpModel.getChemModel(); //translate the new structure a bit GeometryTools.translate2D(topaste, 25, 25,jcpModel.getRendererModel().getRenderingCoordinates()); //in pixels //paste the new structure into the active model org.openscience.cdk.interfaces.IMoleculeSet moleculeSet = chemModel.getMoleculeSet(); if (moleculeSet == null) { moleculeSet = new MoleculeSet(); chemModel.setMoleculeSet(moleculeSet); } moleculeSet.addMolecule(new Molecule(topaste)); // to ensure, that the molecule is shown in the actual visibile part of jcp jcpPanel.scaleAndCenterMolecule((ChemModel)jcpPanel.getChemModel()); //make the pasted structure selected renderModel.setSelectedPart(topaste); //handle undo/redo UndoableEdit edit = new AddAtomsAndBondsEdit(chemModel, topaste, "Pasted something",jcpModel.getControllerModel()); jcpPanel.getUndoSupport().postEdit(edit); } } } catch(Exception ex){ ex.printStackTrace(); } } void handleSystemClipboard() { Clipboard clipboard = jcpPanel.getToolkit().getSystemClipboard(); Transferable clipboardContent = clipboard.getContents(this); DataFlavor flavors[]=clipboardContent.getTransferDataFlavors(); String text = "System.clipoard content"; for(int i=0;i<flavors.length;++i) { text+="\n\n Name: "+ flavors[i].getHumanPresentableName(); text+="\n MIME Type: "+flavors[i].getMimeType(); text+="\n Class: "; Class cl = flavors[i].getRepresentationClass(); if(cl==null) text+="null"; else text+=cl.getName(); } logger.debug(text); } class JcpSelection implements Transferable, ClipboardOwner { private DataFlavor [] supportedFlavors = { molFlavor, DataFlavor.stringFlavor, svgFlavor, cmlFlavor }; String mol; String smiles; String svg; String cml; public JcpSelection (IAtomContainer tocopy1) throws Exception{ Molecule tocopy=new Molecule(tocopy1); // MDL mol output StringWriter sw = new StringWriter(); new MDLWriter(sw).writeMolecule(tocopy); this.mol=sw.toString(); SmilesGenerator sg=new SmilesGenerator(); smiles = sg.createSMILES(tocopy); // SVG output sw=new StringWriter(); IChemObjectWriter cow = new SVGWriter(sw); cow.write(tocopy); cow.close(); svg=sw.toString(); // CML output sw = new StringWriter(); Class cmlWriterClass = null; try { cmlWriterClass = this.getClass().getClassLoader().loadClass("org.openscience.cdk.io.CMLWriter"); } catch (Exception exception) { logger.error("Could not load CMLWriter: ", exception.getMessage()); logger.debug(exception); } if (cmlWriterClass != null) { cow = (IChemObjectWriter)cmlWriterClass.newInstance(); Constructor constructor = cow.getClass().getConstructor(new Class[]{Writer.class}); cow = (IChemObjectWriter)constructor.newInstance(new Object[]{sw}); cow.write(tocopy); cow.close(); } cml=sw.toString(); } public synchronized DataFlavor [] getTransferDataFlavors () { return (supportedFlavors); } public boolean isDataFlavorSupported (DataFlavor parFlavor) { for(int i=0;i<supportedFlavors.length;i++){ if(supportedFlavors[i].equals(parFlavor)) return true; } return false; } public synchronized Object getTransferData (DataFlavor parFlavor) throws UnsupportedFlavorException { if (parFlavor.equals (molFlavor)) { return mol; } else if(parFlavor.equals(DataFlavor.stringFlavor)) { return smiles; } else if(parFlavor.equals(cmlFlavor)) { return cml; } else if(parFlavor.equals(svgFlavor)) { return svg; } else { throw new UnsupportedFlavorException (parFlavor); } } public void lostOwnership (Clipboard parClipboard, Transferable parTransferable) { System.out.println ("Lost ownership"); } } }