001/* 002 * Copyright (c) 1998-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-06-28 21:28:16 +0000 (Thu, 28 Jun 2012) $' 007 * '$Revision: 30086 $' 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.gui.frame; 031 032import java.awt.Color; 033import java.lang.ref.WeakReference; 034import java.util.List; 035import java.util.Vector; 036 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.kepler.gui.KeplerGraphFrame; 040import org.kepler.gui.kar.KAREffigy; 041import org.kepler.kar.KARManager; 042import org.kepler.moml.NamedObjId; 043import org.kepler.moml.NamedObjIdReferralList; 044import org.kepler.objectmanager.ObjectManager; 045import org.kepler.objectmanager.lsid.KeplerLSID; 046import org.kepler.util.TransientStringAttribute; 047 048import ptolemy.actor.gui.Effigy; 049import ptolemy.actor.gui.PtolemyEffigy; 050import ptolemy.actor.gui.Tableau; 051import ptolemy.actor.gui.TableauFactory; 052import ptolemy.actor.gui.TableauFrame; 053import ptolemy.kernel.CompositeEntity; 054import ptolemy.kernel.InstantiableNamedObj; 055import ptolemy.kernel.util.Attribute; 056import ptolemy.kernel.util.IllegalActionException; 057import ptolemy.kernel.util.InternalErrorException; 058import ptolemy.kernel.util.NameDuplicationException; 059import ptolemy.kernel.util.NamedObj; 060import ptolemy.kernel.util.StringAttribute; 061import ptolemy.kernel.util.Workspace; 062import ptolemy.moml.LibraryAttribute; 063 064////////////////////////////////////////////////////////////////////////// 065//// Kepler GraphTableau 066 067/** 068 A graph editor for ptolemy models. 069 070 This is a graph editor for ptolemy models. It constructs an instance 071 of GraphFrame, which contains an editor pane based on diva. 072 073 @see ptolemy.vergil.actor.ActorGraphTableau 074 @author Based on GraphTableau by Steve Neuendorffer and Edward A. Lee 075 @version $Id: KeplerGraphTableau.java 30086 2012-06-28 21:28:16Z crawl $ 076 @since Ptolemy II 2.0 077 @Pt.ProposedRating Red (neuendor) 078 @Pt.AcceptedRating Red (johnr) 079 */ 080public class KeplerGraphTableau extends Tableau { 081 private static final Log log = LogFactory.getLog(KeplerGraphTableau.class 082 .getName()); 083 private static final boolean isDebugging = log.isDebugEnabled(); 084 085 // This class extends Tableau so that highlighting of actors 086 // works. See 087 // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=2321 088 // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4050 089 // util/src/org/kepler/sms/gui/WorkflowTypeCheckerDialog.java 090 // ptII/ptolemy/vergil/unit/UnitSolverDialog.java 091 092 // The only substantive difference between this class and 093 // ptolemy.vergil.actor.ActorGraphTableau is that this class 094 // constructs an instance of KeplerGraphFrame. 095 096 /** 097 * Create a tableau in the specified workspace. 098 * 099 * @param workspace 100 * The workspace. 101 * @exception IllegalActionException 102 * If thrown by the superclass. 103 * @exception NameDuplicationException 104 * If thrown by the superclass. 105 */ 106 public KeplerGraphTableau(Workspace workspace) 107 throws IllegalActionException, NameDuplicationException { 108 super(workspace); 109 if (isDebugging) { 110 log.debug("KeplerGraphTableau(workspace)"); 111 } 112 } 113 114 /** 115 * Create a tableau with the specified container and name, with no specified 116 * default library. 117 * 118 * @param container 119 * The container. 120 * @param name 121 * The name. 122 * @exception IllegalActionException 123 * If thrown by the superclass. 124 * @exception NameDuplicationException 125 * If thrown by the superclass. 126 */ 127 public KeplerGraphTableau(PtolemyEffigy container, String name) 128 throws IllegalActionException, NameDuplicationException { 129 this(container, name, null); 130 } 131 132 /** 133 * Create a tableau with the specified container, name, and default library. 134 * 135 * @param container 136 * The container. 137 * @param name 138 * The name. 139 * @param defaultLibrary 140 * The default library, or null to not specify one. 141 * @exception IllegalActionException 142 * If thrown by the superclass. 143 * @exception NameDuplicationException 144 * If thrown by the superclass. 145 */ 146 public KeplerGraphTableau(PtolemyEffigy container, String name, 147 LibraryAttribute defaultLibrary) throws IllegalActionException, 148 NameDuplicationException { 149 super(container, name); 150 if (isDebugging) { 151 log.debug("KeplerGraphTableau"); 152 if (container == null) { 153 log.debug("container is null"); 154 } else { 155 log.debug(container.getName() + " : " + container.getClassName()); 156 } 157 log.debug("name: " + name); 158 } 159 160 NamedObj model = container.getModel(); 161 162 if (model == null) { 163 return; 164 } 165 166 if (!(model instanceof CompositeEntity)) { 167 throw new IllegalActionException(this, 168 "Cannot graphically edit a model " 169 + "that is not a CompositeEntity. Model is a " 170 + model); 171 } 172 173 InstantiableNamedObj inoModel = (InstantiableNamedObj) model; 174 boolean isClass = inoModel.isClassDefinition(); 175 //System.out.println("isClass: " + isClass); 176 //System.out.println("model class name: " + inoModel.getClassName()); 177 178 ObjectManager om = ObjectManager.getInstance(); 179 180 if (isClass) { 181 // This is a class so assign a new id to it 182 NamedObjId noid = NamedObjId.getIdAttributeFor(model); 183 if (noid == null) { 184 // probably will always get this 185 try { 186 NamedObjId.assignIdTo(model); 187 } catch (Exception e) { 188 e.printStackTrace(); 189 } 190 } 191 192 // And figure out the class name 193 if (model instanceof InstantiableNamedObj) { 194 InstantiableNamedObj ino = (InstantiableNamedObj) model; 195 List inoc = ino.getChildren(); 196 if (inoc != null) { 197 if (isDebugging) log.debug("has " + inoc.size() + " children"); 198 if (inoc.size() > 0) { 199 Vector<NamedObj> noChildren = new Vector<NamedObj>(); 200 for (Object o : inoc) { 201 if (isDebugging) log.debug(o.getClass().getName()); 202 if (o instanceof WeakReference) { 203 WeakReference w = (WeakReference) o; 204 Object o2 = w.get(); 205 if (isDebugging) log.debug(o2.getClass().getName()); 206 if (o2 instanceof NamedObj) { 207 noChildren.add((NamedObj) o2); 208 } 209 } else if (o instanceof NamedObj) { 210 noChildren.add( (NamedObj) o ); 211 } 212 } 213 NamedObj theChild = null; 214 Vector<NamedObj> noChildrenWithClass = new Vector<NamedObj>(); 215 for (NamedObj aChild : noChildren) { 216 Attribute classAtt = aChild.getAttribute("class"); 217 if (classAtt != null) { 218 StringAttribute classAttribute = (StringAttribute) classAtt; 219 String className = classAttribute.getExpression(); 220 noChildrenWithClass.add(aChild); 221 //System.out.println("class name: " + className); 222 } 223 } 224 if (noChildrenWithClass.size() == 1) { 225 theChild = noChildrenWithClass.get(0); 226 } 227 if (theChild != null) { 228 // Tag this object with the classname from the child so it can be saved properly 229 // See ActorMetadata(NamedObj) 230 Attribute classAtt = theChild.getAttribute("class"); 231 if (classAtt != null) { 232 Attribute tcn = model.getAttribute("tempClassName"); 233 if (tcn == null) { 234 StringAttribute classAttribute = (StringAttribute) classAtt; 235 String className = classAttribute.getExpression(); 236 TransientStringAttribute newClassAttribute = new TransientStringAttribute(model,"tempClassName"); 237 newClassAttribute.setExpression(className); 238 Attribute idAtt = classAttribute.getAttribute("id"); 239 if (idAtt != null) { 240 String classId = ((StringAttribute) idAtt).getExpression(); 241 TransientStringAttribute newClassIdAttribute = new TransientStringAttribute(newClassAttribute,"id"); 242 newClassIdAttribute.setExpression(classId); 243 } 244 } 245 } 246 // Also, populate the Referral list with the child's Id, and set the parent 247 NamedObjId childId = NamedObjId.getIdAttributeFor(theChild); 248 if (childId != null) { 249 NamedObjId newNoId = NamedObjId.getIdAttributeFor(model); 250 try { 251 //NamedObjId.assignIdTo(model); 252 NamedObjIdReferralList childIdList = NamedObjId.getIDListAttributeFor(model); 253 if (childIdList == null) { 254 childIdList = new NamedObjIdReferralList(model,NamedObjIdReferralList.NAME); 255 } 256 KeplerLSID childLsid = childId.getId(); 257 boolean alreadyInList = childIdList.hasReferral(childLsid); 258 boolean matchesLsid = childLsid.equals(newNoId.getId()); 259 if (!alreadyInList && !matchesLsid) { 260 String childLsidStr = childLsid.toString(); 261 KeplerLSID newId = new KeplerLSID(childLsidStr); 262 childIdList.addReferral(newId); 263 } 264 } catch (Exception e) { 265 e.printStackTrace(); 266 } 267 // Also, we need to set the child id as the parent of the new id 268 // This allows the id to be updated when the new opened actor is edited. 269 try { 270 NamedObjId.assignIdTo(theChild, newNoId.getId()); 271 } catch (Exception e) { 272 e.printStackTrace(); 273 } 274 newNoId.setParentId(NamedObjId.getIdAttributeFor(theChild)); 275 } 276 277 } 278 } 279 } 280 } 281 282 283 } else { 284 // Check to see if this model has a KeplerLSID associated with it 285 try { 286 NamedObjId noid = NamedObjId.getIdAttributeFor(model); 287 if (noid == null) { 288 // if there is no KeplerLSID we'll check to see if this model 289 // was cloned from a child through instantiation, if it was 290 // we will assign the child's id to this model 291 if (model instanceof InstantiableNamedObj) { 292 InstantiableNamedObj ino = (InstantiableNamedObj) model; 293 List inoc = ino.getChildren(); 294 if (inoc != null) { 295 if (isDebugging) log.debug("has " + inoc.size() + " children"); 296 if (inoc.size() > 0) { 297 Vector<NamedObj> noChildren = new Vector<NamedObj>(); 298 for (Object o : inoc) { 299 if (isDebugging) log.debug(o.getClass().getName()); 300 if (o instanceof WeakReference) { 301 WeakReference w = (WeakReference) o; 302 Object o2 = w.get(); 303 if (isDebugging) log.debug(o2.getClass().getName()); 304 if (o2 instanceof NamedObj) { 305 noChildren.add((NamedObj) o2); 306 } 307 } else if (o instanceof NamedObj) { 308 noChildren.add( (NamedObj) o ); 309 } 310 } 311 NamedObj theChild = null; 312 Vector<NamedObj> noChildrenWithIds = new Vector<NamedObj>(); 313 for (NamedObj aChild : noChildren) { 314 NamedObjId aNoi = NamedObjId.getIdAttributeFor(aChild); 315 if (aNoi != null) { 316 noChildrenWithIds.add(aChild); 317 } 318 } 319 if (noChildrenWithIds.size() == 1) { 320 theChild = noChildrenWithIds.get(0); 321 } 322 if (theChild != null) { 323 if (isDebugging) log.debug("child: "+theChild.getName() + " : " + theChild.getClassName()); 324 /* 325 System.out.println("***************************************************************"); 326 System.out.println(model.exportMoML()); 327 System.out.println("***************************************************************"); 328 System.out.println(no.exportMoML()); 329 System.out.println("***************************************************************"); 330 */ 331 NamedObjId theChildId = NamedObjId.getIdAttributeFor(theChild); 332 if (theChildId != null) { 333 noid = theChildId; 334 } 335 } 336 } 337 } else { 338 log.debug("instantiable model has no children"); 339 } 340 } 341 } 342 if (noid == null) { 343 NamedObjId.assignIdTo(model); 344 } else { 345 NamedObjId.assignIdTo(model,noid.getId()); 346 } 347 if (isDebugging) { 348 NamedObjId tnoid = NamedObjId.getIdAttributeFor(model); 349 if (tnoid == null) { 350 log.debug("NamedObjId is still null"); 351 } else { 352 log.debug(tnoid.getId().toString()); 353 } 354 } 355 } catch (Exception e) { 356 throw new IllegalActionException(model, e, 357 "No Kepler ID was or could be assigned to model: " 358 + e.toString()); 359 } 360 } 361 362 CompositeEntity entity = (CompositeEntity) model; 363 try { 364 om.addNamedObj(entity); 365 } catch (Exception e1) { 366 e1.printStackTrace(); 367 } 368 369 createGraphFrame(entity, defaultLibrary); 370 371 if(container instanceof KAREffigy) { 372 KAREffigy effigy = (KAREffigy) container; 373 // associate the frame 374 KARManager.getInstance().add(getFrame(), effigy.getKARFile()); 375 376 // if it's a kar, open the non-actor entries, e.g., report layout 377 effigy.openKAREntries((TableauFrame) getFrame(), false); 378 } 379 380 } 381 382 /** Create the graph frame that displays the model associated with 383 * this tableau together with the specified library. 384 * @param model The Ptolemy II model to display in the graph frame. 385 * @param defaultLibrary The default library, or null to not specify 386 * one. 387 */ 388 public void createGraphFrame(CompositeEntity model, 389 LibraryAttribute defaultLibrary) 390 { 391 KeplerGraphFrame frame = new KeplerGraphFrame(model, this, 392 defaultLibrary); 393 394 try { 395 setFrame(frame); 396 } catch (IllegalActionException e) { 397 throw new InternalErrorException(e); 398 } 399 frame.setBackground(BACKGROUND_COLOR); 400 } 401 402 // ///////////////////////////////////////////////////////////////// 403 // // private members //// 404 // The background color. 405 private static Color BACKGROUND_COLOR = new Color(0xe5e5e5); 406 407 // ///////////////////////////////////////////////////////////////// 408 // // public inner classes //// 409 410 /** 411 * A factory that creates graph editing tableaux for Ptolemy models. 412 */ 413 public static class Factory extends TableauFactory { 414 /** 415 * Create an factory with the given name and container. 416 * 417 * @param container 418 * The container. 419 * @param name 420 * The name. 421 * @exception IllegalActionException 422 * If the container is incompatible with this attribute. 423 * @exception NameDuplicationException 424 * If the name coincides with an attribute already in the 425 * container. 426 */ 427 public Factory(NamedObj container, String name) 428 throws IllegalActionException, NameDuplicationException { 429 super(container, name); 430 } 431 432 /** 433 * Create a tableau in the default workspace with no name for the given 434 * Effigy. The tableau will created with a new unique name in the given 435 * model effigy. If this factory cannot create a tableau for the given 436 * effigy (perhaps because the effigy is not of the appropriate 437 * subclass) then return null. It is the responsibility of callers of 438 * this method to check the return value and call show(). 439 * 440 * @param effigy 441 * The model effigy. 442 * @return A new KeplerGraphTableau, if the effigy is a PtolemyEffigy, 443 * or null otherwise. 444 * @exception Exception 445 * If an exception occurs when creating the tableau. 446 */ 447 public Tableau createTableau(Effigy effigy) throws Exception { 448 if (effigy instanceof PtolemyEffigy) { 449 // First see whether the effigy already contains a graphTableau. 450 KeplerGraphTableau tableau = (KeplerGraphTableau) effigy 451 .getEntity("graphTableau"); 452 453 if (tableau == null) { 454 // Check to see whether this factory contains a 455 // default library. 456 LibraryAttribute library = (LibraryAttribute) getAttribute( 457 "_library", LibraryAttribute.class); 458 tableau = new KeplerGraphTableau((PtolemyEffigy) effigy, 459 "graphTableau", library); 460 } 461 462 // Don't call show() here, it is called for us in 463 // TableauFrame.ViewMenuListener.actionPerformed() 464 return tableau; 465 } else { 466 return null; 467 } 468 } 469 } 470}