001/*
002 * Copyright (c) 1997-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2013-03-27 18:47:49 +0000 (Wed, 27 Mar 2013) $' 
007 * '$Revision: 31770 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.icon;
031
032import java.io.IOException;
033import java.util.List;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.kepler.configuration.ConfigurationManager;
038import org.kepler.configuration.ConfigurationNamespace;
039import org.kepler.configuration.ConfigurationProperty;
040import org.kepler.moml.NamedObjId;
041import org.kepler.objectmanager.cache.CacheException;
042import org.kepler.objectmanager.cache.CacheManager;
043import org.kepler.objectmanager.lsid.KeplerLSID;
044import org.kepler.util.StaticResources;
045
046import ptolemy.actor.CompositeActor;
047import ptolemy.kernel.util.Attribute;
048import ptolemy.kernel.util.ConfigurableAttribute;
049import ptolemy.kernel.util.IllegalActionException;
050import ptolemy.kernel.util.NameDuplicationException;
051import ptolemy.kernel.util.NamedObj;
052import ptolemy.util.MessageHandler;
053
054//////////////////////////////////////////////////////////////////////////
055//// ComponentEntityConfig
056
057/**
058 * Configuration Utilities for ComponentEntity class, which is a base class for
059 * all actors.
060 * 
061 * @author Matthew Brooke
062 * @version $Id: ComponentEntityConfig.java 31770 2013-03-27 18:47:49Z crawl $
063 * @since Ptolemy II 0.2
064 * @Pt.ProposedRating
065 * @Pt.AcceptedRating
066 */
067public class ComponentEntityConfig {
068
069        /**
070         * attribute name for attribute added to actors to describe
071         * (batik-renderable) SVG image file location
072         */
073        public static final String SVG_ICON_ATTRIB_NAME = "_svgIcon";
074
075        /**
076         * attribute name for attribute added to actors to describe raster thumbnail
077         * image file location
078         */
079        public static final String RASTER_THUMB_ATTRIB_NAME = "_thumbnailRasterIcon";
080
081        // /////////////////////////////////////////////////////////////////
082
083        /**
084         * Key for finding default actor-icon name in resource bundle (example value
085         * associated with this key: "basic-actor")
086         */
087        private static final String DEFAULT_ACTOR_ICON_KEY = "DEFAULT_ACTOR_ICON";
088
089        /**
090         * Key for finding default director-icon name in resource bundle (example
091         * value associated with this key: "director")
092         */
093        private static final String DEFAULT_DIRECTOR_ICON_KEY = "DEFAULT_DIRECTOR_ICON";
094
095        private static String DEFAULT_ACTOR_ICON_BASENAME;
096        private static String DEFAULT_DIRECTOR_ICON_BASENAME;
097
098        private static Log log;
099        private static boolean isDebugging;
100
101        static {
102                // logging...
103                log = LogFactory.getLog("SVG." + ComponentEntityConfig.class.getName());
104                isDebugging = log.isDebugEnabled();
105
106                try {
107                        DEFAULT_ACTOR_ICON_BASENAME = StaticResources.getSettingsString(
108                                        DEFAULT_ACTOR_ICON_KEY, null);
109                } catch (Exception ex) {
110                        if (isDebugging) {
111                                log.debug("EXCEPTION GETTING DEFAULT_ACTOR_ICON_BASENAME: "
112                                                + ex.getMessage());
113                        }
114                }
115                try {
116                        DEFAULT_DIRECTOR_ICON_BASENAME = StaticResources.getSettingsString(
117                                        DEFAULT_DIRECTOR_ICON_KEY, null);
118                } catch (Exception ex) {
119                        if (isDebugging) {
120                                log.debug("EXCEPTION GETTING DEFAULT_DIRECTOR_ICON_BASENAME: "
121                                                + ex.getMessage());
122                        }
123                }
124        }
125
126        private static final String PERIOD = ".";
127
128        // /////////////////////////////////////////////////////////////////
129        // // public methods ////
130        // /////////////////////////////////////////////////////////////////
131
132        public static synchronized void addSVGIconTo(NamedObj namedObj)
133                        throws IOException, IllegalArgumentException,
134                        NameDuplicationException, IllegalActionException {
135                if (isDebugging)
136                        log.debug("addSVGIconTo(" + namedObj + ")");
137
138                if (StaticResources.getUISettingsProperty() == null) {
139                        throw new IOException("Could not access actor icon mappings.");
140                }
141                if (namedObj == null) {
142                        throw new IllegalArgumentException(
143                                        "addSVGIconTo() received NULL arg");
144                }
145
146                // try to assign an icon to this object based on it's LSID
147                boolean assigned = tryToAssignIconByLSID(namedObj);
148                if (assigned) {
149                        return;
150                }
151
152                // try to get a generic icon definition from byClass resourcebundle:
153                String iconBaseName = tryToAssignIconByClass(namedObj);
154
155                // if we could not find an icon using the lsid or class, try
156                // the semantic type
157        if (iconBaseName == null || iconBaseName.trim().length() < 1) {
158            iconBaseName = tryToAssignIconBySemanticType(namedObj);
159        }
160
161        // get a default icon
162                if (iconBaseName == null || iconBaseName.trim().length() < 1) {
163                        iconBaseName = getDefaultIconBaseName(namedObj);
164                }
165
166                if (iconBaseName == null) {
167                        if (isDebugging) {
168                                log.warn("Couldn't assign batik icon for: "
169                                                + namedObj.getClassName());
170                        }
171                        return;
172                }
173                addRasterAndSVGAttributes(namedObj, iconBaseName);
174        }
175
176        /**
177         * Look for an LSID in an Attribute, and if it exists, try to find an icon
178         * mapping in the appropriate resource bundle
179         * 
180         * @param container
181         *            NamedObj
182         * @throws IOException
183         * @throws NameDuplicationException
184         * @throws IllegalActionException
185         */
186        public static boolean tryToAssignIconByLSID(NamedObj container)
187                        throws IOException, NameDuplicationException,
188                        IllegalActionException {
189                boolean success = false;
190
191                if (container == null) {
192                        return success;
193                }
194
195                NamedObjId lsid = NamedObjId.getIdAttributeFor(container);
196                String iconBaseName = null;
197                if (lsid != null) {
198
199                        if (isDebugging) {
200                                log.debug("\n\n*** FOUND LSID (" + lsid.getExpression()
201                                                + ") for: " + container.getClassName());
202                        }
203                        try {
204
205                                iconBaseName = StaticResources.getValueFromName(
206                                                getByLSIDResBundle(), lsid.getExpression());
207                                if (isDebugging) {
208                                        log.debug("*** icon (" + iconBaseName
209                                                        + ") selected by LSID (" + lsid.getExpression()
210                                                        + ") for: " + container.getClassName());
211                                }
212                        } catch (Exception ex) {
213                                log.debug(ex.getMessage());
214                                iconBaseName = null;
215                        }
216                }
217
218                if (iconBaseName == null) {
219                        return success;
220                }
221
222                addRasterAndSVGAttributes(container, iconBaseName);
223                return success;
224        }
225
226        /**
227         * Try to find an icon by class using mapping in the appropriate resource
228         * bundle
229         * 
230         * @param container
231         *            NamedObj
232         * @throws IOException
233         * @throws NameDuplicationException
234         * @throws IllegalActionException
235         */
236        public static String tryToAssignIconByClass(NamedObj namedObj)
237                        throws IOException {
238
239                return tryToAssignIconByClassName(namedObj, namedObj.getClassName());
240
241        }
242
243        public static String tryToAssignIconByClassName(NamedObj namedObj,
244                        String className) throws IOException {
245                String iconBaseName = null;
246                if (getByClassResBundle() != null) {
247                        try {
248                                iconBaseName = StaticResources.getValueFromName(
249                                                getByClassResBundle(), className);
250                                addRasterAndSVGAttributes(namedObj, iconBaseName);
251                                if (isDebugging) {
252                                        log.debug("icon (" + iconBaseName
253                                                        + ") selected by ClassName for: "
254                                                        + namedObj.getClassName());
255                                }
256                        } catch (Exception ex1) {
257                                //ex1.printStackTrace();
258                                log.debug(ex1.getMessage());
259                                iconBaseName = null;
260                        }
261                }
262                return iconBaseName;
263        }
264        
265        /** Try to assign the icon based on the semantic type. */
266        public static String tryToAssignIconBySemanticType(NamedObj namedObj) {
267            
268       if (_iconForSemanticTypeProp == null) {
269            ConfigurationNamespace ns = new ConfigurationNamespace(
270                    "uiSVGIconMappingsBySemanticType");
271            _iconForSemanticTypeProp = ConfigurationManager.getInstance()
272                    .getProperty(ConfigurationManager.getModule("gui"), ns);
273            if(_iconForSemanticTypeProp == null) {
274                MessageHandler.error("Could not find uiSVGIconMappingsBySemanticType.xml.");
275                return null;
276            }
277       }
278       
279       String iconBaseName = null;
280       
281       CacheManager cacheManager = null;
282       try {
283           cacheManager = CacheManager.getInstance();
284       } catch(CacheException e) {
285           MessageHandler.error("Error accessing cache manager.", e);
286           return null;
287       }
288
289       KeplerLSID lsid = null;
290       // try to get the lsid from the object
291       NamedObjId namedObjId = NamedObjId.getIdAttributeFor(namedObj);
292       if(namedObjId == null) {
293           // try to get the lsid from the cache based on the class name
294           List<KeplerLSID> lsids = null;
295        try {
296            lsids = cacheManager.getCachedLsidsForClass(namedObj.getClassName());
297        } catch (Exception e) {
298            System.err.println("Exception query cache for LSIDs of " + namedObj.getClassName());
299            return null;
300        }
301           if(lsids != null && !lsids.isEmpty()) {
302               lsid = lsids.get(0);
303           }
304       } else {
305           lsid = namedObjId.getId();
306       }
307           
308       // if we found the lsid, get the semantic types
309       if(lsid != null) {
310           List<KeplerLSID> semanticTypes = cacheManager.getSemanticTypesFor(lsid);
311           for(KeplerLSID semanticType : semanticTypes) {
312               iconBaseName = StaticResources.getValueFromName(_iconForSemanticTypeProp, semanticType.toString());
313               if(iconBaseName != null) {
314                   return iconBaseName;
315               }
316           }
317       }
318           return null;
319        }
320
321        // /////////////////////////////////////////////////////////////////
322        // // private methods ////
323        // /////////////////////////////////////////////////////////////////
324
325        private static void addRasterAndSVGAttributes(NamedObj namedObj,
326                        String iconBaseName) throws IllegalActionException,
327                        NameDuplicationException, IOException {
328
329                // If iconBaseName is null or empty, just abort; either a previously-
330                // assigned icon, or default icon from Ptolemy base classes will be
331                // used.
332                if (iconBaseName == null || iconBaseName.trim().length() < 1) {
333                        if (isDebugging) {
334                                log.debug("Using base class default icon for: "
335                                                + namedObj.getClassName());
336                        }
337                        return;
338                } else {
339                        if (isDebugging) {
340                                log.debug("*** FOUND ICON MAPPING (" + iconBaseName + ") FOR: "
341                                                + namedObj.getClassName());
342                        }
343                }
344
345                // gets here only if iconBaseName is not null or empty...
346
347                // add base SVG icon
348                _addIconAttributeToNamedObj(namedObj, SVG_ICON_ATTRIB_NAME,
349                                "SVG_ICON_BASE_PATH", iconBaseName, "SVG_BASE_ICON_EXT");
350
351                // now add raster thumbnail icon
352                _addIconAttributeToNamedObj(namedObj, RASTER_THUMB_ATTRIB_NAME,
353                                "RASTER_THUMBNAIL_BASE_PATH", iconBaseName,
354                                "RASTER_THUMBNAIL_EXT");
355        }
356
357        private static String getDefaultIconBaseName(NamedObj namedObj) {
358
359                String iconBaseName = null;
360
361                //System.out.println("using default icon for " + namedObj.getFullName());
362                
363                if (namedObj instanceof ptolemy.actor.Director) {
364                        if (isDebugging) {
365                                log.debug("getDefaultIconBaseName() found a DIRECTOR: "
366                                                + namedObj.getClassName());
367                        }
368                        iconBaseName = DEFAULT_DIRECTOR_ICON_BASENAME;
369                } else if (namedObj instanceof CompositeActor) {
370                    iconBaseName = "composite";
371                } else if (!(namedObj instanceof Attribute)) {
372                        if (isDebugging) {
373                                log.debug("getDefaultIconBaseName() found an ACTOR: "
374                                                + namedObj.getClassName());
375                        }
376                        iconBaseName = DEFAULT_ACTOR_ICON_BASENAME;
377                }
378                return iconBaseName;
379        }
380
381        private static void _addIconAttributeToNamedObj(NamedObj namedObj,
382                        String attribName, String iconBasePathKey, String iconBaseName,
383                        String iconExtensionKey) throws IOException,
384                        NameDuplicationException, IllegalActionException {
385
386                if (isDebugging) {
387                        log.debug("_addIconAttributeToNamedObj() received: "
388                                        + "\n namedObj:" + namedObj.getClassName()
389                                        + "\n attribName:" + attribName + "\n iconBasePathKey:"
390                                        + iconBasePathKey + "\n iconBaseName:" + iconBaseName
391                                        + "\n iconExtensionKey:" + iconExtensionKey);
392                }
393
394                String iconBasePath = StaticResources.getSettingsString(
395                                iconBasePathKey, null);
396                if (iconBasePath == null) {
397                        throw new IOException("Could not get icon base path (key = "
398                                        + iconBasePathKey + ") from configuration file");
399                }
400                String iconExtension = StaticResources.getSettingsString(
401                                iconExtensionKey, null);
402                if (iconExtension == null) {
403                        throw new IOException("Could not get icon extension (key = "
404                                        + iconExtensionKey + ") from configuration file");
405                }
406
407                // make sure we haven't already got an attribute with this name; if we
408                // have, get it instead of trying to create a new one
409                ConfigurableAttribute svgIconAttrib = getExistingOrNewAttribute(
410                                namedObj, attribName);
411
412                StringBuffer buff = new StringBuffer(iconBasePath);
413
414                // ensure last char of iconBasePath is a slash:
415                if (!iconBasePath.endsWith("/")) {
416                        buff.append("/");
417                }
418
419                buff.append(iconBaseName.trim());
420
421                // ensure iconExtension contains a ".":
422                if (iconExtension.indexOf(PERIOD) < 0) {
423                        buff.append(PERIOD);
424                }
425
426                buff.append(iconExtension);
427                if (isDebugging) {
428                        log.debug("_addIconAttributeToNamedObj(): " + "\n actor is: "
429                                        + namedObj.getClassName() + "\n attribute name: "
430                                        + attribName + "\n setExpression:" + buff.toString());
431                }
432                svgIconAttrib.setExpression(buff.toString());
433
434                // set non-persistent so it doesn't get saved in MOML
435                svgIconAttrib.setPersistent(false);
436
437                if (isDebugging) {
438                        log.debug("from actual svgIconAttrib: "
439                                        + "\n svgIconAttrib.getExpression() = "
440                                        + svgIconAttrib.getExpression()
441                                        + "\n svgIconAttrib.getContainer() = "
442                                        + svgIconAttrib.getContainer().getClass().getName());
443                }
444        }
445
446        private static ConfigurableAttribute getExistingOrNewAttribute(
447                        NamedObj namedObj, String attribName) {
448
449                ConfigurableAttribute attrib = null;
450                try {
451                        attrib = (ConfigurableAttribute) namedObj.getAttribute(attribName);
452                } catch (Exception ex) {
453                        ex.printStackTrace();
454                        if (isDebugging) {
455                                log.warn(namedObj.getClass().getName()
456                                                + ") : exception getting svgIcon attribute: "
457                                                + attribName + "; exception was: " + ex.getMessage()
458                                                + "\n\n");
459                        }
460                        attrib = null;
461                }
462                if (attrib != null) {
463                        return attrib;
464                }
465
466                try {
467                        // the Attribute is automatically added to namedObj as an attribute,
468                        // simply by passing namedObj to the constructor
469                        attrib = new ConfigurableAttribute(namedObj, attribName);
470                } catch (Exception ex) {
471                        ex.printStackTrace();
472                        if (isDebugging) {
473                                log.warn(namedObj.getClass().getName()
474                                                + ") : exception getting svgIcon attribute: "
475                                                + attribName + "; exception was: " + ex.getMessage()
476                                                + "\n\n");
477                        }
478                        attrib = null;
479                }
480                return attrib;
481        }
482
483        private static ConfigurationProperty getByClassResBundle()
484                        throws IOException {
485
486                //System.out.println("byClassProperty: " + byClassProperty);
487                if (byClassProperty == null) {
488                        byClassProperty = StaticResources.getUiSVGIconMappingsByClass();
489                }
490                return byClassProperty;
491        }
492
493        private static ConfigurationProperty getByLSIDResBundle()
494                        throws IOException {
495
496                if (byLSIDProperty == null) {
497                        byLSIDProperty = StaticResources.getUiSVGIconMappingsByLSID();
498                }
499                return byLSIDProperty;
500        }
501
502        // /////////////////////////////////////////////////////////////////
503        // // private variables ////
504        // /////////////////////////////////////////////////////////////////
505
506        private static ConfigurationProperty byClassProperty;
507        private static ConfigurationProperty byLSIDProperty;
508        private static ConfigurationProperty _iconForSemanticTypeProp;
509}