net.bioclipse.cdk.smartsmatching.views.SmartsMatchingView.java Source code

Java tutorial

Introduction

Here is the source code for net.bioclipse.cdk.smartsmatching.views.SmartsMatchingView.java

Source

/*******************************************************************************
 * Copyright (c) 2009 Ola Spjuth.
 * 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 - initial API and implementation
 ******************************************************************************/
package net.bioclipse.cdk.smartsmatching.views;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.bioclipse.cdk.business.CDKManager;
import net.bioclipse.cdk.business.ICDKManager;
import net.bioclipse.cdk.domain.ICDKMolecule;
import net.bioclipse.cdk.jchempaint.editor.JChemPaintEditor;
import net.bioclipse.cdk.smartsmatching.Activator;
import net.bioclipse.cdk.smartsmatching.AddEditSmartsDialog;
import net.bioclipse.cdk.smartsmatching.model.SmartsHit;
import net.bioclipse.cdk.smartsmatching.model.SmartsWrapper;
import net.bioclipse.cdk.smartsmatching.prefs.SmartsMatchingPrefsHelper;
import net.bioclipse.core.business.BioclipseException;

import org.apache.log4j.Logger;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.*;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.*;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.SWT;
import org.openscience.cdk.interfaces.IAtomContainer;

/**
 * A view for matching smarts in open editors and views
 * @author ola
 *
 */
public class SmartsMatchingView extends ViewPart implements IPartListener {

    private static final Logger logger = Logger.getLogger(CDKManager.class);

    private static TreeViewer viewer;
    private Action addSmartsAction;
    private Action removeSmartsAction;

    private Action runAction;

    private static Map<IWorkbenchPart, List<SmartsWrapper>> editorSmartsMap;
    private static List<SmartsWrapper> smartsInView;

    private Action clearAction;
    ICDKManager cdk;

    //Used to handle the case with no open editor
    private static EditorPart bogusWBPart = new EditorPart() {
        @Override
        public void doSave(IProgressMonitor monitor) {
        }

        @Override
        public void doSaveAs() {
        }

        @Override
        public void init(IEditorSite site, IEditorInput input) throws PartInitException {
        }

        @Override
        public boolean isDirty() {
            return false;
        }

        @Override
        public boolean isSaveAsAllowed() {
            return false;
        }

        @Override
        public void createPartControl(Composite parent) {
        }

        @Override
        public void setFocus() {
        }
    };

    private static IWorkbenchPart currentPart;

    private Action expandAllAction;

    private Action collapseAllAction;

    private Action showPropertiesViewAction;

    /**
     * The constructor.
     */
    public SmartsMatchingView() {
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite parent) {
        viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        viewer.setContentProvider(new SmartsMatchingContentProvider());
        viewer.setLabelProvider(new SmartsMatchingLabelProvider());
        viewer.setSorter(new ViewerSorter());

        cdk = net.bioclipse.cdk.business.Activator.getDefault().getJavaCDKManager();

        //Read prefs for stored smarts
        smartsInView = SmartsMatchingPrefsHelper.getPreferences();
        viewer.setInput(smartsInView);
        editorSmartsMap = new HashMap<IWorkbenchPart, List<SmartsWrapper>>();
        editorSmartsMap.put(bogusWBPart, smartsInView);

        // Create the help context id for the viewer's control
        PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(),
                "net.bioclipse.cdk.smartsmatching.viewer");
        makeActions();
        hookContextMenu();
        contributeToActionBars();

        //Listen for part lifecycle events to react on editors
        getSite().getWorkbenchWindow().getPartService().addPartListener(this);

        //Post selections to Eclipse
        getSite().setSelectionProvider(viewer);
    }

    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                SmartsMatchingView.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        getSite().registerContextMenu(menuMgr, viewer);
    }

    private void contributeToActionBars() {
        IActionBars bars = getViewSite().getActionBars();
        fillLocalToolBar(bars.getToolBarManager());
    }

    private void fillContextMenu(IMenuManager manager) {
        manager.add(runAction);
        manager.add(clearAction);
        manager.add(new Separator());
        manager.add(addSmartsAction);
        manager.add(removeSmartsAction);
        manager.add(new Separator());
        manager.add(showPropertiesViewAction);

        // Other plug-ins can contribute there actions here
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(runAction);
        manager.add(clearAction);
        manager.add(new Separator());
        manager.add(expandAllAction);
        manager.add(collapseAllAction);
        manager.add(new Separator());
        manager.add(addSmartsAction);
        manager.add(removeSmartsAction);
    }

    private void makeActions() {

        collapseAllAction = new Action() {
            public void run() {
                viewer.collapseAll();
            }
        };
        collapseAllAction.setText("Collapse all");
        collapseAllAction.setToolTipText("Collapse all SMARTS");
        collapseAllAction.setImageDescriptor(Activator.getImageDecriptor("icons/collapseall.gif"));

        expandAllAction = new Action() {
            public void run() {
                viewer.expandAll();
            }
        };
        expandAllAction.setText("Expand all");
        expandAllAction.setToolTipText("Expand all SMARTS to reveal hits");
        expandAllAction.setImageDescriptor(Activator.getImageDecriptor("icons/expandall.gif"));

        runAction = new Action() {
            public void run() {
                runSmartsMatching();
            }
        };
        runAction.setText("Run matching");
        runAction.setToolTipText("Run SMARTS matching for the active aditor");
        runAction.setImageDescriptor(Activator.getImageDecriptor("icons/smallRun.gif"));

        clearAction = new Action() {
            public void run() {
                //Re-read from prefs, creates new objects
                smartsInView = SmartsMatchingPrefsHelper.getPreferences();
                viewer.setInput(smartsInView);
            }
        };
        clearAction.setText("Clear matches");
        clearAction.setToolTipText("Clear all SMARTS matches");
        clearAction.setImageDescriptor(Activator.getImageDecriptor("icons/clear_co.gif"));

        addSmartsAction = new Action() {
            public void run() {

                AddEditSmartsDialog dlg = new AddEditSmartsDialog(getSite().getShell());
                int ret = dlg.open();
                if (ret == Window.CANCEL)
                    return;

                SmartsWrapper wrapper = dlg.getSmartsWrapper();

                //Add to current list
                smartsInView.add(wrapper);

                savePrefsAndUpdate();

            }
        };
        addSmartsAction.setText("Add SMARTS");
        addSmartsAction.setToolTipText("Add a SMARTS entry");
        addSmartsAction.setImageDescriptor(Activator.getImageDecriptor("icons/add_obj.gif"));

        removeSmartsAction = new Action() {
            public void run() {

                if (!(viewer.getSelection() instanceof IStructuredSelection)) {
                    showError("Please select one or more SMARTS to remove");
                    return;
                }
                IStructuredSelection ssel = (IStructuredSelection) viewer.getSelection();

                boolean prefsChanged = false;
                for (Object obj : ssel.toList()) {
                    if (obj instanceof SmartsWrapper) {
                        prefsChanged = true;
                        SmartsWrapper swToRemove = (SmartsWrapper) obj;
                        //For all lists, remove this smart
                        for (Iterator<IWorkbenchPart> it = editorSmartsMap.keySet().iterator(); it.hasNext();) {
                            IWorkbenchPart part = it.next();
                            editorSmartsMap.get(part).remove(swToRemove);
                        }
                        smartsInView.remove(swToRemove);
                    }
                }

                if (prefsChanged) {
                    //Write list to preferences
                    SmartsMatchingPrefsHelper.setPreferences(smartsInView);
                    viewer.refresh();
                }

            }
        };
        removeSmartsAction.setText("Remove SMARTS");
        removeSmartsAction.setToolTipText("Remove the selected SMARTS");
        removeSmartsAction.setImageDescriptor(Activator.getImageDecriptor("icons/delete_obj.gif"));

        showPropertiesViewAction = new Action() {
            public void run() {
                IWorkbenchPage page = getSite().getWorkbenchWindow().getActivePage();
                try {
                    page.showView(IPageLayout.ID_PROP_SHEET);
                } catch (PartInitException e) {
                    showError("Could not show Properties View: " + e.getMessage());
                }
            }
        };
        showPropertiesViewAction.setText("Show Properties");
        showPropertiesViewAction.setToolTipText("Show the Properties View");
        showPropertiesViewAction.setImageDescriptor(Activator.getImageDecriptor("icons/table_row_props.gif"));

    }

    protected void runSmartsMatching() {

        IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
        if (!(part instanceof JChemPaintEditor)) {
            showMessage("You must have an open 2D editor to run SmartsMatching on.");
            return;
        }

        JChemPaintEditor jcp = (JChemPaintEditor) part;

        ICDKMolecule mol = jcp.getCDKMolecule();

        //For each smarts...
        for (SmartsWrapper sw : smartsInView) {
            if (sw.getHits() != null) {
                sw.getHits().clear();
            }
            processSmarts2(sw, mol);
        }

        viewer.refresh();

    }

    private void processSmarts2(SmartsWrapper sw, ICDKMolecule mol) {

        //Clear old matches
        sw.setHits(new ArrayList<SmartsHit>());
        if (!cdk.isValidSmarts(sw.getSmartsString()))
            return;

        List<IAtomContainer> lst;
        try {
            lst = cdk.getSmartsMatches(mol, sw.getSmartsString());

            int i = 1;
            if (lst != null) {

                for (IAtomContainer ac : lst) {
                    SmartsHit hit = new SmartsHit("Hit " + i, ac);
                    hit.setParent(sw);
                    hit.setHitMolecule(mol);
                    sw.getHits().add(hit);
                    i++;
                }
            }
        } catch (BioclipseException e) {
            logger.equals("Error matching smiles: " + e.getMessage());
        }

    }

    private void showMessage(String message) {
        MessageDialog.openInformation(viewer.getControl().getShell(), "Smarts Matching", message);
    }

    private void showError(String message) {
        MessageDialog.openError(viewer.getControl().getShell(), "Smarts Matching", message);
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
        viewer.getControl().setFocus();
    }

    public void partActivated(IWorkbenchPart part) {
        updateViewContent(part);
    }

    public void partBroughtToTop(IWorkbenchPart part) {
        updateViewContent(part);
    }

    /**
     * When editor closed, remove entry in map
     */
    public void partClosed(IWorkbenchPart part) {
        System.out.println("Part:" + part.getTitle() + " closed");
        if (!(isSupportedEditor(part)))
            return;

        if (editorSmartsMap.keySet().contains(part)) {
            //Remove entry
            editorSmartsMap.remove(part);
        }
        if (getSite() != null) {
            if (getSite().getWorkbenchWindow() != null) {
                if (getSite().getWorkbenchWindow().getActivePage() != null) {
                    IEditorReference[] editors = getSite().getWorkbenchWindow().getActivePage()
                            .getEditorReferences();
                    if (editors.length <= 0) {
                        partActivated(bogusWBPart);
                    }
                }
            }
        }
    }

    public void partDeactivated(IWorkbenchPart part) {
    }

    public void partOpened(IWorkbenchPart part) {
        updateViewContent(part);
    }

    private static void updateViewContent(IWorkbenchPart part) {

        if (!(isSupportedEditor(part)))
            return;
        if (part == currentPart)
            return;

        if (part instanceof JChemPaintEditor) {
            JChemPaintEditor jcp = (JChemPaintEditor) part;

            if (editorSmartsMap.keySet().contains(part)) {
                //Use existing
                smartsInView = editorSmartsMap.get(part);
            } else {
                //Create new
                List<SmartsWrapper> newSmartsInView = SmartsMatchingPrefsHelper.getPreferences();

                // Register interest in changes from JCP editor
                jcp.addPropertyChangedListener(new IPropertyChangeListener() {
                    public void propertyChange(PropertyChangeEvent event) {

                        if (event.getProperty().equals(JChemPaintEditor.STRUCUTRE_CHANGED_EVENT)) {

                            // editor model has changed, clear everything for now
                            //TODO: start new match in background thread
                            logger.debug(((JChemPaintEditor) event.getSource()).getTitle() + " editor has changed");

                            smartsInView = SmartsMatchingPrefsHelper.getPreferences();
                            viewer.setInput(smartsInView);
                        }
                    }
                });

                editorSmartsMap.put(part, newSmartsInView);
                smartsInView = newSmartsInView;

            }
        }

        currentPart = part;

        viewer.setInput(smartsInView);

    }

    private static boolean isSupportedEditor(IWorkbenchPart part) {
        if (part instanceof JChemPaintEditor) {
            return true;
        }
        if (part == bogusWBPart) {
            return true;
        }

        //TODO: update here to support MolTable as well

        //Not supported
        return false;
    }

    private static void savePrefsAndUpdate() {

        //Write list to preferences
        SmartsMatchingPrefsHelper.setPreferences(smartsInView);

        //Clear all editors matches, they are now invalid
        editorSmartsMap.clear();
        editorSmartsMap.put(bogusWBPart, SmartsMatchingPrefsHelper.getPreferences());

        //Update current editor, if open
        IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
        if ((isSupportedEditor(part))) {
            updateViewContent(part);
        }

        viewer.refresh();
    }

    public static void firePropertyChanged() {
        savePrefsAndUpdate();

    }

    //    @Override
    //    public Object getAdapter( Class adapter ) {
    //        
    //        if (adapter.equals(IContextProvider.class)) {
    //            return new SmartsContextProvider();
    //          }
    //        return super.getAdapter( adapter );
    //    }

    @Override
    public void dispose() {

        //Unregister listening on parts
        getSite().getWorkbenchWindow().getPartService().removePartListener(this);
        super.dispose();
    }

}