Package org.openscience.jchempaint

Source Code of org.openscience.jchempaint.RenderPanel

/*
*  $RCSfile$
*  $Author: egonw $
*  $Date: 2007-01-04 17:26:00 +0000 (Thu, 04 Jan 2007) $
*  $Revision: 7634 $
*
*  Copyright (C) 1997-2008 Stefan Kuhn
*
*  Contact: cdk-jchempaint@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.jchempaint;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;

import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IAtomContainerSet;
import org.openscience.cdk.renderer.font.AWTFontManager;
import org.openscience.cdk.renderer.generators.BasicSceneGenerator;
import org.openscience.cdk.renderer.generators.RingGenerator;
import org.openscience.cdk.tools.manipulator.ChemModelManipulator;
import org.openscience.cdk.tools.manipulator.MolecularFormulaManipulator;
import org.openscience.jchempaint.action.ZoomAction;
import org.openscience.jchempaint.applet.JChemPaintAbstractApplet;
import org.openscience.jchempaint.controller.ControllerHub;
import org.openscience.jchempaint.controller.ControllerModel;
import org.openscience.jchempaint.controller.IControllerModule;
import org.openscience.jchempaint.controller.IViewEventRelay;
import org.openscience.jchempaint.controller.PhantomArrowGenerator;
import org.openscience.jchempaint.controller.PhantomBondGenerator;
import org.openscience.jchempaint.controller.PhantomTextGenerator;
import org.openscience.jchempaint.controller.SwingMouseEventRelay;
import org.openscience.jchempaint.controller.undoredo.IUndoListener;
import org.openscience.jchempaint.controller.undoredo.IUndoRedoable;
import org.openscience.jchempaint.controller.undoredo.UndoRedoHandler;
import org.openscience.jchempaint.renderer.Renderer;
import org.openscience.jchempaint.renderer.generators.AtomContainerBoundsGenerator;
import org.openscience.jchempaint.renderer.generators.AtomContainerTitleGenerator;
import org.openscience.jchempaint.renderer.generators.BoundsGenerator;
import org.openscience.jchempaint.renderer.generators.ExtendedAtomGenerator;
import org.openscience.jchempaint.renderer.generators.ExternalHighlightAtomGenerator;
import org.openscience.jchempaint.renderer.generators.ExternalHighlightBondGenerator;
import org.openscience.jchempaint.renderer.generators.HighlightAtomGenerator;
import org.openscience.jchempaint.renderer.generators.HighlightBondGenerator;
import org.openscience.cdk.renderer.generators.IGenerator;
import org.openscience.jchempaint.renderer.generators.IReactionGenerator;
import org.openscience.jchempaint.renderer.generators.LonePairGenerator;
import org.openscience.jchempaint.renderer.generators.MappingGenerator;
import org.openscience.jchempaint.renderer.generators.MergeAtomsGenerator;
import org.openscience.jchempaint.renderer.generators.ProductsBoxGenerator;
import org.openscience.jchempaint.renderer.generators.RGroupGenerator;
import org.openscience.jchempaint.renderer.generators.RadicalGenerator;
import org.openscience.jchempaint.renderer.generators.ReactantsBoxGenerator;
import org.openscience.jchempaint.renderer.generators.ReactionArrowGenerator;
import org.openscience.jchempaint.renderer.generators.ReactionBoxGenerator;
import org.openscience.jchempaint.renderer.generators.ReactionPlusGenerator;
import org.openscience.jchempaint.renderer.generators.SelectAtomGenerator;
import org.openscience.jchempaint.renderer.generators.SelectBondGenerator;
import org.openscience.jchempaint.renderer.generators.SelectionToolGenerator;
import org.openscience.jchempaint.renderer.generators.TooltipGenerator;
import org.openscience.cdk.renderer.selection.IChemObjectSelection;
import org.openscience.jchempaint.renderer.visitor.AWTDrawVisitor;
import org.openscience.jchempaint.renderer.visitor.SVGGenerator;
import org.openscience.jchempaint.undoredo.SwingUndoRedoFactory;

public class RenderPanel extends JPanel implements IViewEventRelay,
        IUndoListener {

    protected Renderer renderer;

    private boolean isNewChemModel;

    private ControllerHub hub;

    private ControllerModel controllerModel;

    private SwingMouseEventRelay mouseEventRelay;

    private boolean fitToScreen;

    private boolean zoomWide;

    private boolean shouldPaintFromCache = false;

    private UndoManager undoManager = new UndoManager();

    private boolean debug = false;

    private PhantomBondGenerator pbg = new PhantomBondGenerator();
   
    private PhantomArrowGenerator pag = new PhantomArrowGenerator();
   
    private PhantomTextGenerator ptg = new PhantomTextGenerator();

    boolean isFirstDrawing = true;

    public RenderPanel(IChemModel chemModel, int width, int height,
            boolean fitToScreen, boolean debug, boolean isViewer, JChemPaintAbstractApplet applet) throws IOException {
        this.debug = debug;
        this.setupMachinery(chemModel, fitToScreen, isViewer, applet);
        this.setupPanel(width, height);
        this.fitToScreen = fitToScreen;
        int limit = Integer.parseInt(JCPPropertyHandler.getInstance(true)
                .getJCPProperties().getProperty("General.UndoStackSize"));
        undoManager.setLimit(limit);
        JCPPropertyHandler.getInstance(true).setRenderingPreferences(this.renderer.getRenderer2DModel());
    }

    public void setFitToScreen(boolean fitToScreen) {
        this.renderer.getRenderer2DModel().setFitToScreen(fitToScreen);
    }

    public void setZoomWide(boolean zoomWide) {
        this.zoomWide=zoomWide;
    }

   
    public IChemModel getChemModel() {
        return this.hub.getIChemModel();
    }

    public void setChemModel(IChemModel model) {
        this.hub.setChemModel(model);
    }

    public ControllerHub getHub() {
        return hub;
    }

    private void setupMachinery(IChemModel chemModel, boolean fitToScreen,
            boolean isViewer, JChemPaintAbstractApplet applet)
            throws IOException {
        // setup the Renderer and the controller 'model'

        if (this.renderer == null) {
            this.renderer = new Renderer(makeGenerators(chemModel),
                    makeReactionGenerators(), new AWTFontManager());
            // any specific rendering settings defaults that overwrite user settings should go here
            //this.renderer.getRenderer2DModel().setShowEndCarbons(false);
            //this.renderer.getRenderer2DModel().setShowAromaticity(false);
        }
        this.setFitToScreen(fitToScreen);
        this.controllerModel = new ControllerModel();

        UndoRedoHandler undoredohandler = new UndoRedoHandler();
        undoredohandler.addIUndoListener(this);
        // connect the Renderer to the Hub
        this.hub = new ControllerHub(controllerModel, renderer, chemModel,
                this, undoredohandler, new SwingUndoRedoFactory(), isViewer, applet);
        pbg.setControllerHub(hub);
        pag.setControllerHub(hub);
        ptg.setControllerHub(hub);

        // connect mouse events from Panel to the Hub
        this.mouseEventRelay = new SwingMouseEventRelay(this.hub);
        this.addMouseListener(mouseEventRelay);
        this.addMouseMotionListener(mouseEventRelay);
        this.addMouseWheelListener(mouseEventRelay);
        this.isNewChemModel = true;
    }

    private List<IReactionGenerator> makeReactionGenerators() {
        List<IReactionGenerator> generators = new ArrayList<IReactionGenerator>();
        // generate the bounds first, so that they are to the back
        if (debug) {
            generators.add(new BoundsGenerator());
        }
        generators.add(new ReactionBoxGenerator());
        generators.add(new ReactionArrowGenerator());
        generators.add(new ReactionPlusGenerator());
        generators.add(new ReactantsBoxGenerator());
        generators.add(new ProductsBoxGenerator());
        generators.add(new MappingGenerator());
        return generators;
    }

    private List<IGenerator> makeGenerators(IChemModel chemModel)
            throws IOException {
        List<IGenerator> generators = new ArrayList<IGenerator>();
        if (debug) {
            generators.add(new AtomContainerBoundsGenerator());
        }
        generators.add(new BasicSceneGenerator());
        generators.add(new RGroupGenerator());
        generators.add(new RingGenerator());
        generators.add(new ExtendedAtomGenerator());
        generators.add(new LonePairGenerator());
        generators.add(new RadicalGenerator());
        generators.add(new ExternalHighlightAtomGenerator());
        generators.add(new ExternalHighlightBondGenerator());
        generators.add(new HighlightAtomGenerator());
        generators.add(new HighlightBondGenerator());
        generators.add(new SelectAtomGenerator());
        generators.add(new SelectBondGenerator());
        generators.add(new SelectionToolGenerator());
        generators.add(new MergeAtomsGenerator());
        generators.add(new AtomContainerTitleGenerator());
        generators.add(new TooltipGenerator());
        generators.add(pbg);
        generators.add(pag);
        generators.add(ptg);
        return generators;
    }

    private void setupPanel(int width, int height) {
        this.setBackground(renderer.getRenderer2DModel().getBackColor());
        this.setPreferredSize(new Dimension(width, height));
    }

    public String toSVG() {
        IChemModel chemModel = this.hub.getIChemModel();
        if (chemModel != null && chemModel.getMoleculeSet() != null) {
            SVGGenerator svgGenerator = new SVGGenerator();
            this.renderer.paintChemModel(chemModel, svgGenerator);
            return svgGenerator.getResult();
        } else {
            return "<svg></svg>";
        }
    }

    public Image takeSnapshot() {
        IChemModel chemModel = hub.getIChemModel();
        if (isValidChemModel(chemModel)) {
            Rectangle2D modelBounds = Renderer.calculateBounds(chemModel);
            Rectangle bounds = renderer.calculateScreenBounds(modelBounds);
            bounds.height *=1.1;
            bounds.width *=1.1;
            Image image = GraphicsEnvironment.getLocalGraphicsEnvironment()
                    .getScreenDevices()[0].getDefaultConfiguration()
                    .createCompatibleImage(bounds.width, bounds.height);
            Graphics2D g = (Graphics2D) image.getGraphics();
            takeSnapshot(g, chemModel, bounds, modelBounds);
            return image;
        } else {
            return null;
        }
    }

    public void takeSnapshot(Graphics2D g) {
        IChemModel chemModel = hub.getIChemModel();
        Rectangle2D modelBounds = Renderer.calculateBounds(chemModel);
        Rectangle bounds = renderer.calculateScreenBounds(modelBounds);
        this.takeSnapshot(g, hub.getIChemModel(), bounds, modelBounds);
    }

    public void takeSnapshot(Graphics2D g, IChemModel chemModel, Rectangle s,
            Rectangle2D m) {
        g.setColor(renderer.getRenderer2DModel().getBackColor());
        g.fillRect(0, 0, s.width, s.height);

        renderer.setDrawCenter(s.getWidth() / 2, s.getHeight() / 2);
        renderer.setModelCenter(m.getCenterX(), m.getCenterY());

        renderer.paintChemModel(chemModel, new AWTDrawVisitor(g));
    }

    protected boolean isValidChemModel(IChemModel chemModel) {
        return chemModel != null
                && (chemModel.getMoleculeSet() != null || chemModel
                        .getReactionSet() != null);
    }

    public void paint(Graphics g) {
        this.setBackground(renderer.getRenderer2DModel().getBackColor());
        super.paint(g);

        Graphics2D g2 = (Graphics2D) g;

        if (this.shouldPaintFromCache) {
            renderer.repaint(new AWTDrawVisitor(g2));
        } else {
            IChemModel chemModel = this.hub.getIChemModel();

            if (!isValidChemModel(chemModel))
                return;

            /*
             * It is more correct to use a rectangle starting at (0,0) than to
             * use getBounds() as the RenderPanel may be a child of some
             * container window, and its Graphics will be translated relative to
             * its parent.
             */
            Rectangle screen = new Rectangle(0, 0, getParent().getWidth() - 20,
                    getParent().getHeight() - 20);

            if (renderer.getRenderer2DModel().isFitToScreen()||zoomWide) {
                this.paintChemModelFitToScreen(chemModel, g2, screen);
                if(zoomWide)
                    zoomWide=false;
               
            } else {
                this.paintChemModel(chemModel, g2, screen);
            }
        }
        // for some reason, the first drawing of a string takes around 0.5
        // seconds.
        // If the user experiences this delay, it's annoying, so we do a dummy
        // draw.
        if (isFirstDrawing && this.isVisible()) {
            g.setFont(((AWTFontManager) renderer.getFontManager()).getFont());
            g.setColor(getBackground());
            g.drawString("Black", 100, 100);
            isFirstDrawing = false;
        }
    }

    /**
     * Paint the chem model not fit-to-screen
     *
     * @param chemModel
     * @param g
     * @param screen
     */
    private void paintChemModel(

    IChemModel chemModel, Graphics2D g, Rectangle screen) {

        if (isNewChemModel) {
            renderer.setup(chemModel, screen);
        }

        Rectangle diagram = renderer.calculateDiagramBounds(chemModel);
        isNewChemModel = false;

        this.shouldPaintFromCache = false;

        // determine the size the canvas needs to be to fit the model
        if (diagram != null) {
            Rectangle result = shift(screen, diagram);

            // this makes sure the toolbars get drawn
            this.setPreferredSize(new Dimension(result.width, result.height));
            this.revalidate();
            renderer.paintChemModel(chemModel, new AWTDrawVisitor(g));

        }
    }

    private void paintChemModelFitToScreen(IChemModel chemModel, Graphics2D g,
            Rectangle screen) {

        renderer.paintChemModel(chemModel, new AWTDrawVisitor(g), screen, true);

    }

    public void setIsNewChemModel(boolean isNewChemModel) {
        this.isNewChemModel = isNewChemModel;
    }

    public void updateView() {
        /*
         * updateView should only be called in a ControllerModule where we
         * assume that things have changed so we can't use the cache
         */
        this.shouldPaintFromCache = false;
        this.repaint();
    }

    public void update(Graphics g) {
        // System.out.println("renderpanel update");
        paint(g);
    }

    /**
     * Returns one of the status strings at the given position
     *
     * @param position
     * @return the current status
     */
    public String getStatus(int position) {
        String status = "";
        if (position == 0) {
            // depict editing mode
            IControllerModule activeDrawModule = hub.getActiveDrawModule();
            if (activeDrawModule == null) {
                return "";
            } else {
                String mode = activeDrawModule.getDrawModeString();
                status = JCPMenuTextMaker.getInstance("applet").getText(mode);
            }
        } else if (position == 1) {
            // depict bruto formula
            IChemModel chemModel = hub.getIChemModel();
            IAtomContainerSet molecules = chemModel.getMoleculeSet();
            if (molecules != null && molecules.getAtomContainerCount() > 0) {
                Iterator<IAtomContainer> containers = ChemModelManipulator
                        .getAllAtomContainers(chemModel).iterator();
                int implicitHs = 0;
                while (containers.hasNext()) {
                    for (IAtom atom : containers.next().atoms()) {
                        if (atom.getImplicitHydrogenCount() != null) {
                            implicitHs += atom.getImplicitHydrogenCount();
                        }
                    }
                }
                status = makeStatusBarString(hub.getFormula(), implicitHs);
            }
        } else if (position == 2) {
            // depict brutto formula of the selected molecule or part of
            // molecule
            IChemObjectSelection selection = renderer.getRenderer2DModel()
                    .getSelection();

            if (selection != null) {
                IAtomContainer ac = selection.getConnectedAtomContainer();
                if (ac != null) {
                    int implicitHs = 0;
                    for (IAtom atom : ac.atoms()) {
                        if (atom.getImplicitHydrogenCount() != null) {
                            implicitHs += atom.getImplicitHydrogenCount();
                        }
                    }
                    String formula = MolecularFormulaManipulator
                            .getHTML(MolecularFormulaManipulator
                                    .getMolecularFormula(ac), true, false);
                    status = makeStatusBarString(formula, implicitHs);
                }
            }
        } else if (position == 3) {
            status = GT.get("Zoomfactor")
                    + ": "
                    + NumberFormat.getPercentInstance().format(
                            renderer.getRenderer2DModel().getZoomFactor());
        }
        return status;
    }

    private String makeStatusBarString(String formula, int implicitHs) {
        return "<html>" + formula + "</html>";
    }

    public Renderer getRenderer() {
        return renderer;
    }

    public UndoManager getUndoManager() {
        return undoManager;
    }

    public void doUndo(IUndoRedoable undoredo) {
        undoManager.addEdit((UndoableEdit) undoredo);
        Container root = this.getParent().getParent().getParent();
        if (root instanceof JChemPaintPanel)
            ((JChemPaintPanel) root).updateUndoRedoControls();
    }

    public Rectangle shift(Rectangle screenBounds, Rectangle diagramBounds) {

      final int LABEL_MARGIN=50; // prevents text or labels from dropping off screen
        int screenMaxX = screenBounds.x + screenBounds.width-LABEL_MARGIN;
        int screenMaxY = screenBounds.y + screenBounds.height-LABEL_MARGIN;
        int diagramMaxX = diagramBounds.x + diagramBounds.width;
        int diagramMaxY = diagramBounds.y + diagramBounds.height;
        int leftOverlap = screenBounds.x - diagramBounds.x;
        int rightOverlap = diagramMaxX - screenMaxX;
        int topOverlap = screenBounds.y - diagramBounds.y;
        int bottomOverlap = diagramMaxY - screenMaxY;

        int dx = 0;
        int dy = 0;
        int w = screenBounds.width;
        int h = screenBounds.height;

        if (leftOverlap > 0) {
            dx = leftOverlap;
        }

        if (rightOverlap > 0) {
            w += rightOverlap;
        }

        if (topOverlap > 0) {
            dy = topOverlap;
        }

        if (bottomOverlap > 0) {
            h += bottomOverlap;
        }

        if (dx != 0 || dy != 0) {
            // System.out.println("shifting "+dx+" "+dy);
            this.renderer.shiftDrawCenter(dx, dy);
        }

        else {
            int dxShiftBack = 0, dyShiftBack = 0;
            if (diagramBounds.x > screenMaxX / 3) {
                /* prevent drifting off horizontally */
                dxShiftBack = -1 * (diagramBounds.x - (screenMaxX / 3));
            }
            if (diagramBounds.y > screenMaxY / 3) {
                /* prevent drifting off vertically ! */
                dyShiftBack = -1 * (diagramBounds.y - (screenMaxY / 3));
            }

            if (dxShiftBack != 0 || dyShiftBack != 0) {

                if (ZoomAction.zoomDone) {
                    ZoomAction.zoomDone = false;
                    this.renderer.shiftDrawCenter(dxShiftBack, dyShiftBack);
                    // System.out.println("shifting back");
                }
            }
        }

        return new Rectangle(dx, dy, w, h);
    }
}
TOP

Related Classes of org.openscience.jchempaint.RenderPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.