001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    package edu.wisc.ssec.mcidasv;
029    
030    import static ucar.unidata.util.GuiUtils.makeMenu;
031    import static ucar.unidata.util.GuiUtils.makeMenuItem;
032    import static ucar.unidata.util.MenuUtil.MENU_SEPARATOR;
033    
034    import java.util.ArrayList;
035    import java.util.List;
036    import java.util.Map;
037    
038    import org.python.util.PythonInterpreter;
039    
040    import org.slf4j.Logger;
041    import org.slf4j.LoggerFactory;
042    
043    import edu.wisc.ssec.mcidasv.util.CollectionHelpers;
044    
045    import ucar.unidata.data.DataSource;
046    import ucar.unidata.data.DescriptorDataSource;
047    import ucar.unidata.idv.IntegratedDataViewer;
048    import ucar.unidata.idv.ui.ImageGenerator;
049    import ucar.unidata.idv.ui.JythonShell;
050    
051    /**
052     * Overrides the IDV's {@link ucar.unidata.idv.JythonManager JythonManager} to 
053     * associate a {@link JythonShell} with a given {@code JythonManager}.
054     */
055    public class JythonManager extends ucar.unidata.idv.JythonManager {
056        
057        /** Trusty logging object. */
058        private static final Logger logger = LoggerFactory.getLogger(JythonManager.class);
059        
060        /** Associated Jython Shell. May be {@code null}. */
061        private JythonShell jythonShell;
062        
063        /**
064         * Create the manager and call initPython.
065         *
066         * @param idv The IDV.
067         */
068        public JythonManager(IntegratedDataViewer idv) {
069            super(idv);
070        }
071        
072        /**
073         * Create a Jython shell, if one doesn't already exist. This will also 
074         * bring the window {@literal "to the front"} of the rest of the McIDAS-V
075         * session.
076         * 
077         * @return JythonShell object for interactive Jython usage.
078         */
079        public JythonShell createShell() {
080            if (jythonShell == null) {
081                jythonShell = new JythonShell(getIdv());
082                
083            }
084            jythonShell.toFront();
085            return jythonShell;
086        }
087        
088        /** 
089         * Returns the Jython Shell associated with this {@code JythonManager}.
090         * 
091         * @return Jython Shell being used by this manager. May be {@code null}.
092         */
093        public JythonShell getShell() {
094            return jythonShell;
095        }
096        
097        /**
098         * Create and initialize a Jython interpreter.
099         * 
100         * @return Newly created Jython interpreter.
101         */
102        @Override public PythonInterpreter createInterpreter() {
103            PythonInterpreter interpreter = super.createInterpreter();
104            return interpreter;
105        }
106        
107        /**
108         * Removes the given interpreter from the list of active interpreters. 
109         * 
110         * <p>Also attempts to close any Jython Shell associated with the 
111         * interpreter.</p>
112         * 
113         * @param interpreter Interpreter to remove. Should not be {@code null}. 
114         */
115        @Override public void removeInterpreter(PythonInterpreter interpreter) {
116            super.removeInterpreter(interpreter);
117            if (jythonShell != null && !jythonShell.isShellResetting() && jythonShell.getInterpreter().equals(interpreter)) {
118                jythonShell.close();
119                jythonShell = null;
120            }
121        }
122        
123        /**
124         * Overridden so that McIDAS-V can inject a variable named {@code _idv}
125         * into {@code interpreter's} globals.
126         * 
127         * @param interpreter Jython interpreter being initialized by the IDV. Cannot be {@code null}.
128         */
129        @Override protected void initBasicInterpreter(PythonInterpreter interpreter) {
130            interpreter.set("_idv", getIdv());
131            interpreter.set("idv", getIdv());
132            super.initBasicInterpreter(interpreter);
133        }
134        
135        /**
136         * Overridden so that McIDAS-V can add an {@code islInterpreter} object
137         * to the interpreter's locals (before executing the contents of {@code}.
138         * 
139         * @param code Jython code to evaluate. {@code null} is probably a bad idea.
140         * @param properties {@code String->Object} pairs to insert into the 
141         * locals. Parameter may be {@code null}.
142         */
143        @SuppressWarnings("unchecked") // dealing with idv code that predates generics.
144        @Override public void evaluateTrusted(String code, Map<String, Object> properties) {
145            if (properties == null) {
146                properties = CollectionHelpers.newMap();
147            }
148            if (!properties.containsKey("islInterpreter")) {
149                properties.put("islInterpreter", new ImageGenerator(getIdv()));
150            }
151            if (!properties.containsKey("_idv")) {
152                properties.put("_idv", getIdv());
153            }
154            if (!properties.containsKey("idv")) {
155                properties.put("idv", getIdv());
156            }
157            super.evaluateTrusted(code, properties);
158        }
159        
160        /**
161         * Return the list of menu items to use when the user has clicked on a 
162         * formula {@link DataSource}.
163         * 
164         * @param dataSource The data source clicked on.
165         * 
166         * @return {@link List} of menu items.
167         */
168        @SuppressWarnings("unchecked") // dealing with idv code that predates generics.
169        @Override public List doMakeFormulaDataSourceMenuItems(DataSource dataSource) {
170            List menuItems = new ArrayList(100);
171            menuItems.add(makeMenuItem("Create Formula", this, "showFormulaDialog"));
172            List editItems;
173            if (dataSource instanceof DescriptorDataSource) {
174                editItems = doMakeEditMenuItems((DescriptorDataSource)dataSource);
175            }
176            else {
177                editItems = doMakeEditMenuItems();
178            }
179            menuItems.add(makeMenu("Edit Formulas", editItems));
180            menuItems.add(MENU_SEPARATOR);
181            menuItems.add(makeMenuItem("Jython Library", this, "showJythonEditor"));
182            menuItems.add(makeMenuItem("Jython Shell", this, "createShell"));
183            menuItems.add(MENU_SEPARATOR);
184            menuItems.add(makeMenuItem("Import", this, "importFormulas"));
185            menuItems.add(makeMenuItem("Export", this, "exportFormulas"));
186            return menuItems;
187        }
188        
189    }