001/* Utility that checks the size of a model.
002
003 Copyright (c) 2006-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_3
025 COPYRIGHTENDKEY
026 */
027package ptolemy.actor.gui;
028
029import java.io.File;
030import java.net.URL;
031import java.util.HashSet;
032import java.util.Iterator;
033import java.util.List;
034import java.util.Set;
035
036import ptolemy.actor.CompositeActor;
037import ptolemy.actor.TypedCompositeActor;
038import ptolemy.data.ArrayToken;
039import ptolemy.data.DoubleToken;
040import ptolemy.data.IntMatrixToken;
041import ptolemy.data.ScalarToken;
042import ptolemy.data.expr.ExpertParameter;
043import ptolemy.kernel.CompositeEntity;
044import ptolemy.kernel.util.IllegalActionException;
045import ptolemy.kernel.util.KernelException;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.moml.MoMLParser;
048import ptolemy.moml.filter.BackwardCompatibility;
049import ptolemy.moml.filter.RemoveGraphicalClasses;
050
051//////////////////////////////////////////////////////////////////////////
052//// CheckModelSize
053
054/**
055 Class that checks the size, zoom, and location of a model.
056 @author Rowland R Johnson
057 @version $Id$
058 @since Ptolemy II 5.2
059 @Pt.ProposedRating Red (rowland)
060 @Pt.AcceptedRating Red (rowland)
061 */
062public class CheckModelSize {
063    /** Check the size, zoom and location of the models named
064     *  by the args.
065     *  @param configuration The optional configuration to check.
066     *  @param args An array of Strings naming the models to be checked.
067     *  @return HTML that describes possible problems with the models.
068     *  @exception Exception If there is a problem reading a model.
069     */
070    public static String checkModelSize(Configuration configuration,
071            String[] args) throws Exception {
072        StringBuffer results = new StringBuffer();
073        Set sizeProblemSet = new HashSet();
074        if (configuration != null) {
075            List entityList = configuration.entityList(CompositeEntity.class);
076            Iterator entities = entityList.iterator();
077            while (entities.hasNext()) {
078                Object entity = entities.next();
079                if (entity instanceof TypedCompositeActor
080                        && !sizeProblemSet.contains(entity)) {
081                    String checkSizeOutput = _checkSize(
082                            (TypedCompositeActor) entity, false);
083                    if (!checkSizeOutput.equals("")) {
084                        results.append(
085                                "<tr>\n  <td>"
086                                        + ((TypedCompositeActor) entity)
087                                                .getFullName()
088                                        + "</td>\n  <td>" + checkSizeOutput
089                                        + "</td>\n");
090                    }
091                    sizeProblemSet.add(entity);
092                }
093            }
094
095            List classList = configuration.classDefinitionList();
096            entities = classList.iterator();
097            while (entities.hasNext()) {
098                Object entity = entities.next();
099                System.out.println("CheckModelSize: " + entity + " "
100                        + (entity instanceof TypedCompositeActor));
101                if (entity instanceof TypedCompositeActor
102                        && !sizeProblemSet.contains(entity)) {
103                    String checkSizeOutput = _checkSize(
104                            (TypedCompositeActor) entity, false);
105                    if (!checkSizeOutput.equals("")) {
106                        results.append(
107                                "<tr>\n  <td><b>Class</b> "
108                                        + ((TypedCompositeActor) entity)
109                                                .getFullName()
110                                        + "</td>\n  <td>" + checkSizeOutput
111                                        + "</td>\n");
112                    }
113                    sizeProblemSet.add(entity);
114                }
115            }
116
117        }
118
119        for (String arg : args) {
120            String fileName = arg;
121            //             if (fileName.endsWith("ENM_11_18_04.xml")
122            //                     || fileName.endsWith("IPCC_Base_Layers.xml")
123            //                     || fileName.endsWith("dataFrame_R.xml")
124            //                     || fileName.endsWith("eml_Table_as_Record_R.xml")
125            //                     || fileName.endsWith("emlToRecord_R.xml")
126            //                     || fileName.endsWith("eml-simple-linearRegression-R.xml")
127            //                     || fileName.endsWith("eml-pairs-R.xml")) {
128            //                 System.out.println("CheckModelSize: skipping " + fileName);
129            //                 continue;
130            //             }
131            StringBuffer analysis = new StringBuffer();
132
133            MoMLParser parser = new MoMLParser();
134            MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters());
135
136            RemoveGraphicalClasses removeGraphicalClasses = new RemoveGraphicalClasses();
137
138            // Remove StaticSchedulingCodeGenerator from Butterfly
139            // because during the nightly build the codegenerator is
140            // not yet built when the tests in actor.gui are run.
141            removeGraphicalClasses.put(
142                    "ptolemy.codegen.kernel.StaticSchedulingCodeGenerator",
143                    null);
144            // We need the _vergilSize attribute, which is removed by
145            // removeGraphicalClasses, so we modify removeGraphicalClasses
146            // so that it no longer removes SizeAttributes.
147            removeGraphicalClasses.remove("ptolemy.actor.gui.SizeAttribute");
148
149            // Filter out any graphical classes.
150            MoMLParser.addMoMLFilter(removeGraphicalClasses);
151
152            if (!(fileName.endsWith(".xml") || fileName.endsWith(".moml"))) {
153                continue;
154            }
155
156            try {
157                NamedObj top = null;
158                try {
159                    top = parser.parse(null,
160                            new File(fileName).toURI().toURL());
161                } catch (Exception ex) {
162                    try {
163                        top = parser.parse(null, new URL(fileName));
164                    } catch (Exception ex2) {
165                        throw new Exception("Failed to parse \"" + fileName
166                                + "\". First exception:\n" + ex, ex2);
167                    }
168                }
169                String checkSizeOutput = _checkSize(top, false);
170                if (checkSizeOutput.equals("")) {
171                    analysis.append(" seems to be OK.");
172                } else {
173                    analysis.append(checkSizeOutput);
174                }
175
176                if (top instanceof CompositeEntity) {
177                    List entityList = ((CompositeEntity) top).deepEntityList();
178                    Iterator entities = entityList.iterator();
179                    while (entities.hasNext()) {
180                        Object entity = entities.next();
181                        if (entity instanceof TypedCompositeActor
182                                && !sizeProblemSet.contains(entity)) {
183                            checkSizeOutput = _checkSize(
184                                    (TypedCompositeActor) entity, false);
185                            if (!checkSizeOutput.equals("")) {
186                                sizeProblemSet.add(entity);
187                                results.append("<tr>\n  <td>"
188                                        + ((TypedCompositeActor) entity)
189                                                .getFullName()
190                                        + "</td>\n  <td>" + checkSizeOutput
191                                        + "</td>\n");
192                            }
193                            sizeProblemSet.add(entity);
194                        }
195                    }
196                }
197
198            } catch (Throwable throwable) {
199                analysis.append(" can't be parsed because ");
200                analysis.append(KernelException.stackTraceToString(throwable));
201            }
202            String fileURL = new File(fileName).toURI().toURL().toString();
203            results.append("<tr>\n  <td><a href=\"" + fileURL + "\">" + fileURL
204                    + "</a></td>\n  <td>" + analysis + "</td>\n");
205
206        }
207
208        return "<h1>Check Size</h1>\nBelow are the results from checking the "
209                + "sizes of and centering of models\n<table>\n"
210                + "<b>Note: after running review these results, be"
211                + " sure to exit, as the graphical elements of the "
212                + " models will have been removed</b>\n" + results.toString()
213                + "</table>\n";
214    }
215
216    /** Check the size, zoom and location of the models named
217     *  by the args.
218     *  @param args An array of Strings naming the models to be checked.
219     *
220     */
221    public static void main(String[] args) {
222        try {
223            System.out.println(CheckModelSize.checkModelSize(null, args));
224        } catch (Throwable throwable) {
225            throwable.printStackTrace();
226        }
227    }
228
229    /** Check the size and centering of the model.
230     *  @param top The NamedObj to check
231     *  @return A string describing size problems associated with the model.
232     */
233    private static String _checkSize(NamedObj top,
234            boolean ignoreMissingVergilSize) {
235        StringBuffer analysis = new StringBuffer();
236        if (top instanceof CompositeActor) {
237            SizeAttribute vergilSize = (SizeAttribute) top
238                    .getAttribute("_vergilSize");
239            ExpertParameter vergilZoom = (ExpertParameter) top
240                    .getAttribute("_vergilZoomFactor");
241            ExpertParameter vergilCenter = (ExpertParameter) top
242                    .getAttribute("_vergilCenter");
243
244            if (vergilSize != null) {
245                try {
246                    IntMatrixToken vergilSizeToken;
247                    vergilSizeToken = (IntMatrixToken) vergilSize.getToken();
248
249                    if (vergilSizeToken == null) {
250                        throw new IllegalActionException(top,
251                                "_vergilSize token was null?");
252                    }
253                    int width = vergilSizeToken.getElementAt(0, 0);
254                    int height = vergilSizeToken.getElementAt(0, 1);
255
256                    if (width > 800) {
257                        analysis.append(" width(" + width + ") > 800");
258                    }
259
260                    if (height > 768) {
261                        analysis.append(" height(" + height + ") > 768");
262                    }
263
264                    if (vergilCenter != null) {
265                        try {
266                            ArrayToken vergilCenterToken = (ArrayToken) vergilCenter
267                                    .getToken();
268                            double x = ((ScalarToken) vergilCenterToken
269                                    .getElement(0)).doubleValue();
270                            double y = ((ScalarToken) vergilCenterToken
271                                    .getElement(1)).doubleValue();
272
273                            // Avoid comparing floats.
274                            if (Math.abs(x - width / 2.0) > 0.1
275                                    || Math.abs(y - height / 2.0) > 0.1) {
276                                analysis.append(" Center([" + x + ", " + y
277                                        + "]) is not centered, should be ["
278                                        + width / 2.0 + ", " + height / 2.0
279                                        + "]");
280                            }
281                        } catch (IllegalActionException ex) {
282                            analysis.append(" _vergilCenter malformed");
283                            analysis.append(
284                                    KernelException.stackTraceToString(ex));
285                        }
286                    }
287                } catch (IllegalActionException ex) {
288                    analysis.append(" _vergilSize malformed");
289                    analysis.append(KernelException.stackTraceToString(ex));
290                }
291
292                if (vergilZoom != null) {
293                    try {
294                        DoubleToken vergilZoomToken = (DoubleToken) vergilZoom
295                                .getToken();
296                        double zoom = vergilZoomToken.doubleValue();
297
298                        if (zoom != 1.0) {
299                            analysis.append(" Zoom(" + zoom + ") != 1.0");
300                        }
301                    } catch (IllegalActionException ex) {
302                        analysis.append(" _vergilZoom malformed");
303                        analysis.append(KernelException.stackTraceToString(ex));
304                    }
305                }
306            } else {
307                if (!ignoreMissingVergilSize) {
308                    analysis.append(" has no _vergilSize.");
309                }
310            }
311        } else {
312            analysis.append(
313                    " is a " + top.getClassName() + " not a CompositeActor.");
314        }
315
316        return analysis.toString();
317    }
318}