net.bioclipse.jmol.cdk.views.JmolView.java Source code

Java tutorial

Introduction

Here is the source code for net.bioclipse.jmol.cdk.views.JmolView.java

Source

/*******************************************************************************
 * Copyright (c) 2007-2008 Bioclipse Project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Ola Spjuth - core API and implementation
 *******************************************************************************/

package net.bioclipse.jmol.cdk.views;

import java.awt.event.MouseListener;
import java.io.ByteArrayOutputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JScrollPane;

import net.bioclipse.cdk.business.ICDKManager;
import net.bioclipse.cdk.domain.CDKConformer;
import net.bioclipse.cdk.domain.CDKMolecule;
import net.bioclipse.cdk.domain.ICDKMolecule;
import net.bioclipse.cdk.domain.AtomContainerSelection;
import net.bioclipse.cdk.providers.IPharmacophoreProvider;
import net.bioclipse.cdk.providers.PharmacophoreDistanceConstraint;
import net.bioclipse.core.business.BioclipseException;
import net.bioclipse.core.domain.AtomIndexSelection;
import net.bioclipse.core.domain.IChemicalSelection;
import net.bioclipse.core.domain.IMolecule;
import net.bioclipse.core.domain.ModelSelection;
import net.bioclipse.core.domain.ScriptSelection;
import net.bioclipse.jmol.cdk.adapter.CdkJmolAdapter;
import net.bioclipse.jmol.views.JmolCompMouseListener;
import net.bioclipse.jmol.views.JmolPolymerSelection;
import net.bioclipse.jmol.views.outline.JmolModelSet;
import net.bioclipse.jmol.views.outline.JmolModelString;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.openscience.cdk.ChemFile;
import org.openscience.cdk.ChemModel;
import org.openscience.cdk.ChemSequence;
import org.openscience.cdk.ConformerContainer;
import org.openscience.cdk.MoleculeSet;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.geometry.GeometryTools;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IChemFile;
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IMoleculeSet;
import org.openscience.cdk.io.CMLWriter;
import org.openscience.cdk.pharmacophore.PharmacophoreBond;
import org.openscience.cdk.tools.manipulator.ChemFileManipulator;

//import quicktime.app.image.Redrawable;

/**
 * A view for Jmol embedded in an SWT_AWT frame (requires java5.0+)
 * 
 * @author ola
 */
public class JmolView extends ViewPart
        implements ISelectionListener, ISelectionProvider, ISelectionChangedListener {

    //Use logging
    private static final Logger logger = Logger.getLogger(JmolView.class);

    public static final String ID = "net.bioclipse.jmol.cdk.views.JmolView";

    private JmolPanel jmolPanel;
    private Text text;
    private ArrayList<String> history;

    private Composite composite;

    //Provide selections from Jmol to e.g. outline
    private List<ISelectionChangedListener> selectionListeners;
    private JmolPolymerSelection selection;

    private ICDKManager cdk;

    //Keep track if we have contents in view
    private boolean cleared;

    //Store the chemfile we are displaying
    IChemFile chemFile;

    //A formatter for 2 decimals
    DecimalFormat formatter = new DecimalFormat("0.00");

    private List lastSelected;

    /**
     * The constructor.
     */
    public JmolView() {
        history = new ArrayList<String>(50);
        jmolPanel = new JmolPanel(this, new CdkJmolAdapter());
        cdk = net.bioclipse.cdk.business.Activator.getDefault().getJavaCDKManager();
        setCleared(true);
        lastSelected = new ArrayList();
    }

    public boolean isCleared() {
        return cleared;
    }

    public void setCleared(boolean cleared) {
        this.cleared = cleared;
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite parent) {

        logger.debug("JmolView is initiating...");

        //Set the layout for parent
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        layout.verticalSpacing = 2;
        layout.marginWidth = 0;
        layout.marginHeight = 2;
        parent.setLayout(layout);

        GridData layoutData = new GridData();
        layoutData.grabExcessHorizontalSpace = true;
        layoutData.grabExcessVerticalSpace = true;
        parent.setLayoutData(layoutData);

        //Add the Jmol composite to the top
        composite = new Composite(parent, SWT.EMBEDDED);
        layout = new GridLayout();
        composite.setLayout(layout);
        layoutData = new GridData(GridData.FILL_BOTH);
        composite.setLayoutData(layoutData);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, "net.bioclipse.jmol.scriptInputField");

        java.awt.Frame fileTableFrame = SWT_AWT.new_Frame(composite);
        java.awt.Panel panel = new java.awt.Panel(new java.awt.BorderLayout());
        fileTableFrame.add(panel);

        JScrollPane scrollPane = new JScrollPane(jmolPanel);
        panel.add(scrollPane);

        jmolPanel.addMouseListener((MouseListener) new JmolCompMouseListener(composite));

        /*
        Label label1 = new Label(parent, SWT.NONE);
        label1.setText("Jmol scripting console");
            
        //Layout the text field below Jmol
        text = new Text(parent, SWT.SINGLE | SWT.BORDER);
            
        GridData layoutData2 = new GridData();
        layoutData2.grabExcessHorizontalSpace = true;
        layoutData2.horizontalAlignment = GridData.FILL;
        text.setLayoutData(layoutData2);
        text.setTextLimit(60);
        text.setEditable(true);
        text.setEnabled(false);
        text.setText("");
            
        text.addKeyListener(new KeyListener() {
        public void keyPressed(KeyEvent e) {}
        public void keyReleased(KeyEvent e) {
            if (e.stateMask != SWT.CTRL && e.keyCode == SWT.CR){
                //Execute jmol command
                String jmolcmd=text.getText();
                if (jmolcmd!=null && jmolcmd.length()>0)
        //                        executeJmolCommand(jmolcmd);
                    if (!history.contains(text.getText()))
                        history.add(0, text.getText());
                text.setText("");
            }
            
            if (e.keyCode == SWT.ARROW_UP){
                text.setText(history.get(0));
                history.add(history.get(0));
                history.remove(0);
            }
            
            if (e.keyCode == SWT.ARROW_DOWN){
                text.setText(history.get(0));
                history.add(0, history.get(history.size()-1));
                history.remove(history.size()-1);
            }
        }
        });
        */
        //Register this page as a listener for selections
        //We want to update information based on selection i e g TreeViewer
        getViewSite().getPage().addSelectionListener(this);

    }

    @Override
    public void setFocus() {
        // TODO Auto-generated method stub

    }

    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        // TODO Auto-generated method stub

        reactOnSelection(selection);
    }

    /* Below are for setting selections in Bioclipse from Jmol, e.g when 
     clicked on an Atom*/

    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        if (!selectionListeners.contains(listener)) {
            selectionListeners.add(listener);
        }
    }

    public ISelection getSelection() {
        return selection;
    }

    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        if (selectionListeners.contains(listener))
            selectionListeners.remove(listener);
    }

    public void setSelection(ISelection selection) {
        this.selection = (JmolPolymerSelection) selection;
        java.util.Iterator<ISelectionChangedListener> iter = selectionListeners.iterator();
        while (iter.hasNext()) {
            final ISelectionChangedListener listener = iter.next();
            final SelectionChangedEvent e = new SelectionChangedEvent(this, this.selection);
            //Does SWT stuff so this has to be called on SWT's thread
            PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                public void run() {
                    listener.selectionChanged(e);
                }
            });

        }
    }

    public void selectionChanged(SelectionChangedEvent event) {
        reactOnSelection(event.getSelection());
    }

    /**
     * 
     * @param selection
     */
    private void reactOnSelection(ISelection selection) {

        if (!(selection instanceof IStructuredSelection)) {
            clearView();
            return;
        }
        IStructuredSelection eclipseSelection = (IStructuredSelection) selection;

        /*
         * Get info from selections directly or via adapter in this order:
         * 
         * 1. Collect (or generate from IMolecule) ICDKMolecules
         * 2. Collect ChemModels to visualize
         * 3. Collect atoms/bonds to highlight (IChemicalSelection)
         * 4. Collect scripts to run
         */

        //Store selected CDKMols in List
        List<ICDKMolecule> collectedCDKMols = new ArrayList<ICDKMolecule>();

        //Store chemical selections in List
        List<IChemicalSelection> chemicalSelections = new ArrayList<IChemicalSelection>();

        //Store pharmacophpreProviders in List
        List<IPharmacophoreProvider> pcoreProviders = new ArrayList<IPharmacophoreProvider>();

        //See if list is the same as previously selected
        boolean newSelection = false;
        for (Object obj : eclipseSelection.toList()) {

            if (!(lastSelected.contains(obj))) {
                newSelection = true;
            }
        }
        if (newSelection == false) {
            //            System.out.println("Omitting selection!");
            return;
        }

        //We have a new selection
        lastSelected.clear();

        //Extract molecules and chemical selection from the eclipseSelection
        //Store extracted info in lists
        extractFromSelection(eclipseSelection, collectedCDKMols, chemicalSelections, pcoreProviders);

        //Extract JmolModelSet from selection.
        //This happens when JmolEditor provides input via adapter
        JmolModelString jms = extractJmolModelsetFromSelection(eclipseSelection);
        //        System.out.println("** jms: " + jms);
        if (jms != null) {
            //            System.out.println("** jms string: " + jms.getModelString());
            //This overrides other ICDKMolecules (for now at least)
            runScript(jms.getModelString());
            return;
        }

        //TODO: continue here

        //We have now collected everything we are interested in.
        //If no fun, return
        if ((collectedCDKMols.size() <= 0) && chemicalSelections.size() <= 0) {

            return;

        }

        /*
         * If extracted molecules: Set up Chemfile and and send it to jmol
         */
        if (collectedCDKMols != null) {

            logger.debug("Extracted the following molecules from selection:");
            for (ICDKMolecule cmol : collectedCDKMols) {
                logger.debug("  * " + cmol.getName());
            }

            processMolecules(collectedCDKMols);
        }

        /*
         * Process any pharmacophoreProviders
        * This means e.g. to draw spheres and lines
        */
        if (pcoreProviders.size() > 0) {

            logger.debug("Extracted the following pcoreProviders:");
            for (IChemicalSelection csel : chemicalSelections) {
                logger.debug("  * " + csel.getSelection());
            }

            processPcoreProviders(pcoreProviders);
        }

        /*
         * Process any chemicalSelections
        * This means to show/filter/add commands to the already shown molecules
        * For example, display one or more models, highlight atoms, run scripts
        */
        if (chemicalSelections.size() > 0) {

            logger.debug("Extracted the following chemical selections:");
            for (IChemicalSelection csel : chemicalSelections) {
                logger.debug("  * " + csel.getSelection());
            }

            processChemicalSelections(chemicalSelections);
        }

    }

    private JmolModelString extractJmolModelsetFromSelection(IStructuredSelection eclipseSelection) {

        for (Object obj : eclipseSelection.toList()) {
            if (obj instanceof JmolModelString) {
                return (JmolModelString) obj;
            }

            if (obj instanceof IAdaptable) {
                IAdaptable adaptable = (IAdaptable) obj;
                JmolModelString jms = (JmolModelString) adaptable.getAdapter(JmolModelString.class);
                return jms;
            }
        }

        //Default is null
        return null;
    }

    private void processPcoreProviders(List<IPharmacophoreProvider> pcoreProviders) {

        for (IPharmacophoreProvider provider : pcoreProviders) {
            PharmacophoreBond constraint = provider.getConstraint();

            //For debug issues
            double dist = constraint.getBondLength();
            IAtom group1 = constraint.getAtom(0);
            IAtom group2 = constraint.getAtom(1);
            logger.debug("      (DistanceConstraint: " + group1.getSymbol() + "," + group2.getSymbol() + ", dist: "
                    + dist + ") ");

            String group1jmolcoords = "{" + group1.getPoint3d().x + " " + group1.getPoint3d().y + " "
                    + group1.getPoint3d().z + "}";

            String group2jmolcoords = "{" + group2.getPoint3d().x + " " + group2.getPoint3d().y + " "
                    + group2.getPoint3d().z + "}";

            String pcoreString1 = "isoSurface mySphere1 color purple resolution 4 center " + group1jmolcoords
                    + " sphere 1 mesh nofill";
            String pcoreString2 = "isoSurface mySphere2 color green resolution 4 center " + group2jmolcoords
                    + " sphere 1 mesh nofill";
            String lineString = "draw line1 color yellow " + group1jmolcoords + " " + group2jmolcoords;
            //                String lineString="draw line1 width 0.2 color yellow " + group1jmolcoords + " " + group2jmolcoords; 

            String lineLabel = "set echo lineEcho $line1; echo Distance: " + formatter.format(dist)
                    + "; color echo red";

            String group1Label = "set echo group1Echo " + group1jmolcoords + "; echo " + group1.getSymbol()
                    + "; color echo red";
            String group2Label = "set echo group2Echo " + group2jmolcoords + "; echo " + group2.getSymbol()
                    + "; color echo red";

            runScript(pcoreString1);
            runScript(pcoreString2);
            runScript(lineString);
            runScript(lineLabel);
            //                runScript( group1Label );
            //                runScript( group2Label );

        }

    }

    private void processChemicalSelections(List<IChemicalSelection> chemicalSelections) {

        //        logger.debug("######### Jmol Selections ############");

        //Handle highlighting if we have any
        //Start by atoms/bonds/models in a chemicalSelection

        //Store new model index
        ArrayList<Integer> modelSelectionIndices = new ArrayList<Integer>();

        //Store collected atom indices
        ArrayList<Integer> atomSelectionIndices = new ArrayList<Integer>();

        //Store collected scripts to run
        ArrayList<String> collectedScripts = new ArrayList<String>();

        //Loop over all stored IChemicalSelections
        for (IChemicalSelection chemicalSelection : chemicalSelections) {

            //Process model selections to display one or more models
            if (chemicalSelection instanceof ModelSelection) {
                ModelSelection modelSel = (ModelSelection) chemicalSelection;

                for (Integer i : modelSel.getSelection()) {
                    //Add one, since jmol starts indices on 1, and store in list
                    modelSelectionIndices.add(i + 1);

                    //                        logger.debug("# jmol: Added model to be shown: " + (i+1));
                }

            }

            //Process atom selections to highlight one or more atoms by index
            else if (chemicalSelection instanceof AtomIndexSelection) {
                AtomIndexSelection isel = (AtomIndexSelection) chemicalSelection;
                int[] selindices = isel.getSelection();

                for (int i = 0; i < selindices.length; i++) {

                    //Add one, since jmol starts indices on 1
                    atomSelectionIndices.add(new Integer(selindices[i] + 1));
                }
            }

            else if (chemicalSelection instanceof AtomContainerSelection) {
                //TODO
            }

            else if (chemicalSelection instanceof ScriptSelection) {
                ScriptSelection scriptSelection = (ScriptSelection) chemicalSelection;
                Map<String, String> scripts = scriptSelection.getSelection();
                for (String script : scripts.keySet()) {
                    if (scripts.get(script).equals("jmol")) {
                        collectedScripts.add(script);
                    }
                }
            }
        }

        /*
         * We have now collected what we want from the Chemical Selection.
         * Now, set up an run the jmol scripts for this.
         */

        //Start with models by index
        if (modelSelectionIndices.size() > 0) {

            //Collect all Select commands into one string
            String frameScript = "Frame all; display ";
            for (Iterator<Integer> it = modelSelectionIndices.iterator(); it.hasNext();) {
                Integer sel = it.next();
                frameScript += "1." + sel + ",";
            }

            String colorScript = "selectionHalos off; Select all; wireframe 40; spacefill 20%; "
                    + "color bonds cpk; color atoms cpk; select none; ";

            if (modelSelectionIndices.size() > 1) {
                colorScript = "selectionHalos off; Select all; spacefill off; wireframe 25; select none;";
                for (Integer i : modelSelectionIndices) {
                    colorScript = colorScript + " Select 1." + i + "; color bonds " + getColorEnum(i) + ";";
                }
            }

            //Remove last comma
            frameScript = frameScript.substring(0, frameScript.length() - 1);
            //                logger.debug("Jmol running collected display string: '" +
            //                                                     frameScript + "'");

            runScript(frameScript);
            runScript(colorScript);
        }

        //Continue with atoms by index
        if (atomSelectionIndices.size() > 0) {
            //Collect atoms, bonds etc and create script to highlight
            String selectionString = "selectionHalos on; Select none; SELECT ";
            Collections.sort(atomSelectionIndices);
            for (Integer i : atomSelectionIndices) {
                selectionString = selectionString + "atomno=" + i.intValue() + ",";
            }

            //Remove last comma
            selectionString = selectionString.substring(0, selectionString.length() - 1);
            //                logger.debug("Collected display string: '" + selectionString + "'");

            runScript(selectionString);
        }

        //Process all collected scripts
        if (collectedScripts.size() > 0) {
            logger.debug("Running scripts from selections in jmol: ");
            for (String script : collectedScripts) {
                //                    logger.debug("  " + script);
                runScript(script);
            }

        }

    }

    private void processMolecules(List<ICDKMolecule> collectedCDKMols) {

        //        logger.debug("######### Process jmol molecules ############");

        //Start by ICDKMolecules to set of the ChemFiles, which Jmol expects
        //as input

        //Store ChemModels here, to add them to ChemFile for input in Jmol
        List<ChemModel> collectedModels = new ArrayList<ChemModel>();

        //Loop over all collected molecules, extract ChemModels and add to list
        for (ICDKMolecule cdkMol : collectedCDKMols) {

            //The ICDKMolecule could be a CDKConformer
            if (cdkMol instanceof CDKConformer) {
                CDKConformer cdkConf = (CDKConformer) cdkMol;

                //Extract individual atomContainers
                //and add multiple models
                for (int i = 0; i < cdkConf.getConformerContainer().size(); i++) {

                    IAtomContainer cac = cdkConf.getConformerContainer().get(i);

                    //We need to clone, as same AC returned
                    //TODO: Verfy this
                    IAtomContainer caccopy;
                    try {
                        caccopy = (IAtomContainer) cac.clone();
                        addAtomContainer(collectedModels, caccopy);
                        //                            logger.debug("Added an AC from conformer.");

                    } catch (CloneNotSupportedException e) {
                        logger.debug("Could not clone AC in Conformer." + " AC omitted in Jmol.");
                    }

                }

                //FIXME: above uses for, below uses generic iterator.
                //Remove one of them when bug fixed.

                /*                    for (IAtomContainer cac: cdkConf.getConformerContainer()){
                    //We need to clone, as same AC returned
                    //TODO: Verfy this
                    IAtomContainer caccopy;
                    try {
                        caccopy = (IAtomContainer) cac.clone();
                        addAtomContainer(collectedModels, caccopy);
                //                            logger.debug("Added an AC from conformer.");
                    
                    } catch ( CloneNotSupportedException e ) {
                        logger.debug("Could not clone AC in Conformer."+
                        " AC omitted in Jmol.");
                    }
                }
                    */
            }

            //Else, we have an ICDKMolecule
            else {
                IAtomContainer ac = cdkMol.getAtomContainer();

                //Only add if have 3D coords
                if (GeometryTools.has3DCoordinates(ac)) {
                    addAtomContainer(collectedModels, ac);
                }
            }
        }

        //If we have models collected, add them to a ChemFile and send to Jmol
        if (collectedModels.size() > 0) {

            logger.debug("# Jmol, we have " + collectedModels.size() + " ChemModels to send to jmol");

            //Check if stored ChemFile's models differs from New ChemModels
            boolean similar = false;

            if (chemFile != null) {
                int oldModelCount = chemFile.getChemSequence(0).getChemModelCount();
                int newModelCount = collectedModels.size();

                similar = true;

                //Fast way to see if we should continue comparing models
                if (oldModelCount == newModelCount) {

                    //Compare one by one
                    for (int i = 0; i < chemFile.getChemSequence(0).getChemModelCount(); i++) {
                        IChemModel cm1 = chemFile.getChemSequence(0).getChemModel(i);
                        IChemModel cm2 = collectedModels.get(i);
                        String title1 = (String) cm1.getMoleculeSet().getMolecule(0).getProperty("cdk:Title");
                        String title2 = (String) cm2.getMoleculeSet().getMolecule(0).getProperty("cdk:Title");

                        //If all titles are same, we conclude the chemmodels are similar
                        if (title1 != null && title1 != null) {
                            if (!(title1.equals(title2))) {
                                similar = false;
                            }
                        } else {
                            similar = false;
                        }

                    }

                } else {
                    similar = false;
                }

            }

            //See if we already have chemModels stored, for example 
            //clicking on another conformer
            if (similar == false) {
                //Create a chemfile, as jmol expects this
                ChemFile cf = new ChemFile();
                ChemSequence seq = new ChemSequence();
                cf.addChemSequence(seq);

                //Add all available chemmodels to chemfile
                for (ChemModel model : collectedModels) {
                    seq.addChemModel(model);
                }

                //Set the ChemFile as input to jmol
                setChemFile(cf);

                //Indicate that we now have content
                setCleared(false);
            }
        } else if (isCleared() == false) {
            clearView();
            setCleared(true);
        }

    } //End act upon collected ChemModels

    private void extractFromSelection(IStructuredSelection ssel, List<ICDKMolecule> collectedCDKMols,
            List<IChemicalSelection> chemicalSelections, List<IPharmacophoreProvider> pcoreProviders) {

        //Loop all selections; if they can provide AC: add to moleculeSet
        for (Object obj : ssel.toList()) {

            boolean storeSelection = false;

            //If we have an ICDKMolecule, just get the AC directly
            if (obj instanceof ICDKMolecule) {
                ICDKMolecule cdkmol = (ICDKMolecule) obj;
                collectedCDKMols.add(cdkmol);
                storeSelection = true;

                //                if (cdkmol.getAtomContainer()==null){
                //                    logger.debug("CDKMolecule but can't get AtomContainer.");
                //                }
                //                //Only add if have 3D coords
                //                IAtomContainer ac=cdkmol.getAtomContainer();
                //                if (GeometryTools.has3DCoordinates(ac)){
                //                    addAtomContainer( displayedModels, ac );
                //                }
            }

            //Else try to get the different adapters
            else if (obj instanceof IAdaptable) {
                IAdaptable ada = (IAdaptable) obj;

                //Handle case where Iadaptable can return a molecule
                Object molobj = ada.getAdapter(net.bioclipse.core.domain.IMolecule.class);
                if (molobj != null) {
                    //If adaptable returns a cdkmolecule, add it directly 
                    if (molobj instanceof ICDKMolecule) {
                        ICDKMolecule cdkmol = (ICDKMolecule) molobj;
                        collectedCDKMols.add(cdkmol);
                    }

                    //If adaptable at least returns an IMolecule
                    //we can create CDKMolecule from it (this is costly though)
                    else if (molobj instanceof net.bioclipse.core.domain.IMolecule) {
                        net.bioclipse.core.domain.IMolecule bcmol = (net.bioclipse.core.domain.IMolecule) molobj;
                        try {
                            //Lengthy operation, as via CML or SMILES
                            ICDKMolecule cdkmol = cdk.asCDKMolecule(bcmol);
                            collectedCDKMols.add(cdkmol);
                        } catch (BioclipseException e) {
                            e.printStackTrace();
                        }
                    }
                    storeSelection = true;
                }

                //Handle case where Iadaptable can return atoms to be highlighted
                Object chemSelectionObj = ada.getAdapter(IChemicalSelection.class);
                if (chemSelectionObj != null) {
                    chemicalSelections.add((IChemicalSelection) chemSelectionObj);
                    storeSelection = true;
                }

                //Handle case where Iadaptable can return models to be shown
                Object chemModelSel = ada.getAdapter(ModelSelection.class);
                if (chemModelSel != null) {
                    chemicalSelections.add((IChemicalSelection) chemModelSel);
                    storeSelection = true;
                }

                //Handle case where Iadaptable can return a script
                Object scriptSelection = ada.getAdapter(ScriptSelection.class);
                if (scriptSelection != null) {
                    chemicalSelections.add((ScriptSelection) scriptSelection);
                    storeSelection = true;
                }

                //Handle case where Iadaptable can return a pharmacophoreProvider
                Object pcoreProvider = ada.getAdapter(IPharmacophoreProvider.class);
                if (pcoreProvider != null) {
                    pcoreProviders.add((IPharmacophoreProvider) pcoreProvider);
                    storeSelection = true;
                }

            } //End of adaptable collection

            if (storeSelection == true) {
                System.out.println("Storing selection in jmol");
                lastSelected.add(obj);
            }

        } //End of loop over selections
    }

    /**
     * Return a color from list by index
     * @param i
     * @return
     */
    private String getColorEnum(Integer i) {

        switch (i % 7) {
        case 1:
            return "red";
        case 2:
            return "green";
        case 3:
            return "yellow";
        case 4:
            return "blue";
        case 5:
            return "magenta";
        case 6:
            return "cyan";
        case 7:
            return "amber";
        default:
            return "brown";
        }
    }

    private void addAtomContainer(List<ChemModel> models, IAtomContainer ac) {

        //Create a MolSet to hold the molecule
        MoleculeSet ms = new MoleculeSet();
        ms.addAtomContainer(ac);

        //Create a ChemModel to hold the MolSet
        ChemModel model = new ChemModel();
        model.setMoleculeSet(ms);

        models.add(model);

    }

    /**
     * Clear JmolView by issuing the "zap" command
     */
    private void clearView() {

        runScript("zap; echo /No molecule with 3D coordinates available");
    }

    /**
     * Set a chemfile as mol in Jmol with openClientFile("","",ChemFile)
     * @param cf
     */
    private void setChemFile(IChemFile cf) {

        //Compare if we have new things, else just return

        chemFile = cf;
        //        System.out.println("%%%%%%%%%%%");
        //        System.out.println(cf);
        //        System.out.println("%%%%%%%%%%%");

        //        try {
        //            ByteArrayOutputStream bo=new ByteArrayOutputStream();
        //            CMLWriter writer=new CMLWriter(bo);
        //            writer.write( cf );
        //            System.out.println("%%%%%%%%%%%");
        //            System.out.println(bo.toString());
        //            System.out.println("%%%%%%%%%%%");
        //            
        //        } catch ( CDKException e ) {
        //            e.printStackTrace();
        //        }
        //        
        //
        //

        logger.debug("Opening Jmol via CDK's ChemFile and CdkJmolAdapter...");

        //Maybe fork off a new thread?? TODO!
        jmolPanel.openClientFile("", "", cf);

        String strError = jmolPanel.getOpenFileError();
        if (strError != null) {
            logger.error(strError);
            text.setEnabled(false);
        }
    }

    /**
     * Execute a script in Jmol
     * @param script
     */
    public void runScript(String script) {

        logger.debug("Running jmol script: '" + script + "'");
        String res = jmolPanel.getViewer().evalString(script);
        if (res != null)
            logger.debug("Jmol said: '" + res + "'");

    }

}