001/* A top-level dialog window for editing Unit constraints. 002 003 Copyright (c) 2003-2016 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_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.vergil.unit; 028 029import java.awt.BorderLayout; 030import java.awt.Color; 031import java.awt.Frame; 032import java.awt.event.ActionEvent; 033import java.net.URL; 034import java.util.HashSet; 035import java.util.Iterator; 036import java.util.Set; 037import java.util.Vector; 038 039import javax.swing.AbstractListModel; 040import javax.swing.BorderFactory; 041import javax.swing.BoxLayout; 042import javax.swing.JButton; 043import javax.swing.JLabel; 044import javax.swing.JList; 045import javax.swing.JPanel; 046import javax.swing.JScrollPane; 047import javax.swing.ListSelectionModel; 048import javax.swing.event.ListSelectionEvent; 049import javax.swing.event.ListSelectionListener; 050 051import diva.canvas.Figure; 052import diva.canvas.interactor.BasicSelectionRenderer; 053import diva.canvas.interactor.Interactor; 054import diva.canvas.interactor.SelectionEvent; 055import diva.canvas.interactor.SelectionInteractor; 056import diva.canvas.interactor.SelectionListener; 057import diva.canvas.interactor.SelectionModel; 058import diva.canvas.interactor.SelectionRenderer; 059import diva.graph.GraphController; 060import diva.graph.GraphPane; 061import diva.graph.GraphUtilities; 062import diva.graph.JGraph; 063import ptolemy.actor.TypedCompositeActor; 064import ptolemy.actor.gui.Configuration; 065import ptolemy.actor.gui.DialogTableau; 066import ptolemy.actor.gui.PtolemyDialog; 067import ptolemy.actor.gui.Tableau; 068import ptolemy.actor.gui.TableauFrame; 069import ptolemy.kernel.ComponentEntity; 070import ptolemy.kernel.Entity; 071import ptolemy.kernel.Port; 072import ptolemy.kernel.Relation; 073import ptolemy.kernel.util.Attribute; 074import ptolemy.kernel.util.IllegalActionException; 075import ptolemy.kernel.util.Location; 076import ptolemy.kernel.util.NamedObj; 077import ptolemy.moml.MoMLChangeRequest; 078import ptolemy.moml.unit.Solution; 079import ptolemy.moml.unit.UnitConstraints; 080import ptolemy.util.MessageHandler; 081import ptolemy.vergil.basic.AbstractBasicGraphModel; 082import ptolemy.vergil.basic.BasicGraphFrame; 083 084/////////////////////////////////////////////////////////////////// 085//// UnitSolverDialog 086 087/** 088 Dialog for the Unit Solver. 089 090 @author Rowland R Johnson 091 @version $Id$ 092 @since Ptolemy II 8.0 093 @Pt.ProposedRating Red (rowland) 094 @Pt.AcceptedRating Red (rowland) 095 */ 096@SuppressWarnings("serial") 097public class UnitSolverDialog extends PtolemyDialog 098 implements ListSelectionListener, SelectionListener { 099 /** 100 * Construct a Unit Solver Dialog. 101 * @param dialogTableau The DialogTableau. 102 * @param owner The object that, per the user, appears to be generating the 103 * dialog. 104 * @param target The object whose units are being solved. 105 * @param configuration The configuration to use to open the help screen. 106 */ 107 public UnitSolverDialog(DialogTableau dialogTableau, Frame owner, 108 Entity target, Configuration configuration) { 109 super("Solve units for " + target.getName(), dialogTableau, owner, 110 target, configuration); 111 112 SelectionRenderer tempSelectionRenderer = null; 113 _tableau = ((TableauFrame) owner).getTableau(); 114 115 _model = (TypedCompositeActor) target; 116 117 // ((TypedCompositeActor) (((PtolemyEffigy) (_tableau.getContainer())) 118 // .getModel())); 119 BasicGraphFrame parent = (BasicGraphFrame) _tableau.getFrame(); 120 JGraph jGraph = parent.getJGraph(); 121 GraphPane graphPane = jGraph.getGraphPane(); 122 _controller = graphPane.getGraphController(); 123 _selectionModel = _controller.getSelectionModel(); 124 125 Interactor interactor = _controller.getEdgeController(new Object()) 126 .getEdgeInteractor(); 127 _graphModel = (AbstractBasicGraphModel) _controller.getGraphModel(); 128 _selectionInteractor = (SelectionInteractor) interactor; 129 _defaultSelectionRenderer = _selectionInteractor.getSelectionRenderer(); 130 tempSelectionRenderer = new BasicSelectionRenderer( 131 new BasicEdgeHighlighter()); 132 133 if (_model == getTarget()) { 134 _entities = _getSelectedNodes(); 135 _relations = _getSelectedRelations(); 136 137 if (_entities.isEmpty() && _relations.isEmpty()) { 138 _entities = new HashSet<ComponentEntity>( 139 _model.entityList(ComponentEntity.class)); 140 _relations = new HashSet<Relation>(_model.relationList()); 141 } 142 } else { 143 _entities = new HashSet<ComponentEntity>(); 144 Entity targetEntity = getTarget(); 145 if (targetEntity instanceof ComponentEntity) { 146 _entities.add((ComponentEntity) targetEntity); 147 } 148 _relations = new HashSet<Relation>(); 149 } 150 151 _selectionModel.clearSelection(); 152 _selectionInteractor.setSelectionRenderer(tempSelectionRenderer); 153 _showComponents(); 154 _selectionModel.addSelectionListener(this); 155 156 JPanel fullSolverPanel = new JPanel(); 157 fullSolverPanel 158 .setLayout(new BoxLayout(fullSolverPanel, BoxLayout.Y_AXIS)); 159 fullSolverPanel.setBorder(BorderFactory.createCompoundBorder( 160 BorderFactory.createTitledBorder("Full Solution"), 161 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 162 _runFullSolverButton.addActionListener(this); 163 fullSolverPanel.add(_runFullSolverButton); 164 _fullSolutionResult.setOpaque(true); 165 _fullSolutionResult.setBackground(Color.white); 166 fullSolverPanel.add(_fullSolutionResult); 167 168 JPanel componentsPanel = new JPanel(); 169 componentsPanel 170 .setLayout(new BoxLayout(componentsPanel, BoxLayout.Y_AXIS)); 171 componentsPanel.setBorder(BorderFactory.createCompoundBorder( 172 BorderFactory.createTitledBorder("Components"), 173 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 174 _setToSelectedButton.setEnabled(false); 175 componentsPanel.add(_setToSelectedButton); 176 _setToSelectedButton.addActionListener(this); 177 componentsPanel.add(_showComponentsButton); 178 _showComponentsButton.addActionListener(this); 179 180 JPanel topPanel = new JPanel(); 181 topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS)); 182 topPanel.add(fullSolverPanel); 183 topPanel.add(componentsPanel); 184 185 JPanel minimalSpanPanel = new JPanel(new BorderLayout()); 186 minimalSpanPanel.setBorder(BorderFactory.createCompoundBorder( 187 BorderFactory.createTitledBorder("Minimal Spanning Solutions"), 188 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 189 minimalSpanPanel.add(_runMinimalSpanSolverButton, BorderLayout.NORTH); 190 _runMinimalSpanSolverButton.addActionListener(this); 191 _solutionsListModel = new SolutionListModel(); 192 _solutionsList = new JList(_solutionsListModel); 193 _solutionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 194 _solutionsList.addListSelectionListener(this); 195 196 JScrollPane scrollPane = new JScrollPane(_solutionsList); 197 minimalSpanPanel.add(scrollPane, BorderLayout.CENTER); 198 199 JPanel mainPane = new JPanel(); 200 mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); 201 mainPane.add(topPanel); 202 mainPane.add(minimalSpanPanel); 203 setContents(mainPane); 204 } 205 206 /////////////////////////////////////////////////////////////////// 207 //// public methods //// 208 209 /* (non-Javadoc) 210 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent) 211 */ 212 @Override 213 public void actionPerformed(ActionEvent aEvent) { 214 //String command = aEvent.getActionCommand(); 215 if (aEvent.getSource() == _runMinimalSpanSolverButton) { 216 try { 217 // FIXME: UnitContstraint ctor should take args other than Vectors. 218 _uConstraints = new UnitConstraints(_model, 219 new Vector(_entities), new Vector(_relations)); 220 _solutions = _uConstraints.minimalSpanSolutions(); 221 } catch (IllegalActionException e) { 222 MessageHandler.error("Minimal Span Solver failed: ", e); 223 return; 224 } 225 226 _solutionsListModel.setSolutions(_solutions); 227 _solutionsList.setModel(_solutionsListModel); 228 } else if (aEvent.getSource() == _runFullSolverButton) { 229 _solutionsList.clearSelection(); 230 231 try { 232 _uConstraints = new UnitConstraints(_model, 233 new Vector(_entities), new Vector(_relations)); 234 235 Solution solution = _uConstraints.completeSolution(); 236 _fullSolutionResult.setText(solution.getShortStateDesc()); 237 238 //solution.trace(); 239 } catch (IllegalActionException e) { 240 MessageHandler.error("Full Solver failed: ", e); 241 return; 242 } 243 } else if (aEvent.getSource() == _setToSelectedButton) { 244 _setSelectedComponents(); 245 } else if (aEvent.getSource() == _showComponentsButton) { 246 _showComponents(); 247 } else { 248 super.actionPerformed(aEvent); 249 } 250 } 251 252 /** Remove all the annotations from the graph. 253 * Actors, their ports, and relations are inspected to see if they either a 254 * _color and/or an _explanation attribute. If so, then the attribute is 255 * removed via a MoMl changeRequest. 256 */ 257 public void deAnnotateGraph() { 258 StringBuffer moml = new StringBuffer(); 259 Iterator entities = _model.entityList(ComponentEntity.class).iterator(); 260 261 while (entities.hasNext()) { 262 ComponentEntity entity = (ComponentEntity) entities.next(); 263 String entityDeletes = _deletesIfNecessary(entity); 264 moml.append("<entity name=\"" + entity.getName() + "\">"); 265 266 if (entityDeletes != null) { 267 moml.append(entityDeletes); 268 } 269 270 Iterator ports = entity.portList().iterator(); 271 272 while (ports.hasNext()) { 273 Port port = (Port) ports.next(); 274 String portDeletes = _deletesIfNecessary(port); 275 276 if (portDeletes != null) { 277 moml.append("<port name=\"" + port.getName() + "\">" 278 + portDeletes + "</port>"); 279 } 280 } 281 282 moml.append("</entity>"); 283 } 284 285 Iterator relations = _model.relationList().iterator(); 286 287 while (relations.hasNext()) { 288 Relation relation = (Relation) relations.next(); 289 String relationDeletes = _deletesIfNecessary(relation); 290 291 if (relationDeletes != null) { 292 moml.append("<relation name=\"" + relation.getName() + "\">" 293 + relationDeletes + "\"/></relation>"); 294 } 295 } 296 297 if (moml.length() > 0) { 298 String momlUpdate = "<group>" + moml.toString() + "</group>"; 299 MoMLChangeRequest request = new MoMLChangeRequest(this, _model, 300 momlUpdate); 301 request.setUndoable(true); 302 request.setPersistent(false); 303 304 _model.requestChange(request); 305 } 306 } 307 308 /* (non-Javadoc) 309 * @see diva.canvas.interactor 310 * .SelectionListener#selectionChanged(SelectionEvent) 311 */ 312 @Override 313 public void selectionChanged(SelectionEvent e) { 314 _setToSelectedButton.setEnabled(true); 315 } 316 317 /* (non-Javadoc) 318 * @see javax.swing.event 319 * .ListSelectionListener#valueChanged(ListSelectionEvent) 320 */ 321 @Override 322 public void valueChanged(ListSelectionEvent e) { 323 if (e.getValueIsAdjusting()) { 324 return; 325 } 326 327 int index = _solutionsList.getSelectedIndex(); 328 329 if (index >= 0) { 330 _showComponents(); 331 332 Solution solution = (Solution) _solutions.elementAt(index); 333 solution.annotateGraph(); 334 335 //solution.trace(); 336 } 337 } 338 339 /** List of solutions. 340 */ 341 public static class SolutionListModel extends AbstractListModel { 342 Vector _solutions = new Vector(); 343 344 /** Return an element. 345 * @param index The index of the element to be returned. 346 * @return The element at the specified index. 347 */ 348 @Override 349 public Object getElementAt(int index) { 350 return ((Solution) _solutions.elementAt(index)).getStateDesc(); 351 } 352 353 /** Return the number of solutions. 354 * @return The number of solutions. 355 */ 356 @Override 357 public int getSize() { 358 return _solutions.size(); 359 } 360 361 /** Set the solutions to the specified argument. 362 * @param solutions A vector of solutions. 363 */ 364 public void setSolutions(Vector solutions) { 365 _solutions = solutions; 366 fireContentsChanged(this, 0, _solutions.size()); 367 } 368 369 /** Clear the current set of solutions. 370 */ 371 public void clear() { 372 _solutions = new Vector(); 373 } 374 } 375 376 /////////////////////////////////////////////////////////////////// 377 //// protected methods //// 378 @Override 379 protected void _cancel() { 380 _selectionModel.removeSelectionListener(this); 381 _selectionModel.clearSelection(); 382 _selectionInteractor.setSelectionRenderer(_defaultSelectionRenderer); 383 _showComponents(); 384 super._cancel(); 385 } 386 387 /* (non-Javadoc) 388 * @see ptolemy.actor.gui.PtolemyDialog#_createExtendedButtons(JPanel) 389 */ 390 @Override 391 protected void _createExtendedButtons(JPanel _buttons) { 392 } 393 394 @Override 395 protected URL _getHelpURL() { 396 URL helpURL = getClass().getClassLoader() 397 .getResource("ptolemy/actor/gui/doc/unitConstraintsSolver.htm"); 398 return helpURL; 399 } 400 401 /////////////////////////////////////////////////////////////////// 402 //// private methods //// 403 private String _deletesIfNecessary(NamedObj obj) { 404 String retv = null; 405 Attribute color = obj.getAttribute("_color"); 406 Attribute explanation = obj.getAttribute("_explanation"); 407 408 if (color != null && explanation != null) { 409 retv = "<deleteProperty name=\"_color\"/>" 410 + "<deleteProperty name=\"_explanation\"/>"; 411 } 412 413 return retv; 414 } 415 416 /** Create a Vector of selected nodes in a Tableau. This method really 417 * belongs elsewhere and will be moved there at some point. 418 * @return Vector of selected Nodes. 419 */ 420 private Set<ComponentEntity> _getSelectedNodes() { 421 Set<ComponentEntity> nodes = new HashSet<ComponentEntity>(); 422 423 if (_tableau.getFrame() instanceof BasicGraphFrame) { 424 Object[] selection = _selectionModel.getSelectionAsArray(); 425 426 for (Object element : selection) { 427 if (element instanceof Figure) { 428 Object userObject = ((Figure) element).getUserObject(); 429 NamedObj actual = (NamedObj) _graphModel 430 .getSemanticObject(userObject); 431 432 if (actual instanceof ComponentEntity) { 433 nodes.add((ComponentEntity) actual); 434 } 435 } 436 } 437 } 438 439 return nodes; 440 } 441 442 /** Create a Vector of selected Relations in a Tableau. This method really 443 * belongs elsewhere and will be moved there at some point. 444 * @return Vector of selected Relations. 445 */ 446 private Set<Relation> _getSelectedRelations() { 447 Set<Relation> relations = new HashSet<Relation>(); 448 449 if (_tableau.getFrame() instanceof BasicGraphFrame) { 450 Object[] selection = _selectionModel.getSelectionAsArray(); 451 452 for (Object element : selection) { 453 if (element instanceof Figure) { 454 Object userObject = ((Figure) element).getUserObject(); 455 NamedObj actual = (NamedObj) _graphModel 456 .getSemanticObject(userObject); 457 458 if (actual instanceof Relation 459 && !relations.contains(actual)) { 460 relations.add((Relation) actual); 461 } 462 } 463 } 464 } 465 466 return relations; 467 } 468 469 /** 470 * 471 */ 472 private void _setSelectedComponents() { 473 // FIXME: Why don't we just set _entities and _relations here? 474 Set<ComponentEntity> entities = _getSelectedNodes(); 475 Set<Relation> relations = _getSelectedRelations(); 476 _entities = new HashSet<ComponentEntity>(entities); 477 _relations = new HashSet<Relation>(relations); 478 479 // for (int i = 0; i < entities.size(); i++) { 480 // _entities.add(entities.elementAt(i)); 481 // } 482 483 // for (int i = 0; i < relations.size(); i++) { 484 // _relations.add(relations.elementAt(i)); 485 // } 486 487 _setToSelectedButton.setEnabled(false); 488 } 489 490 /** 491 * 492 */ 493 private void _showComponents() { 494 _selectionModel.clearSelection(); 495 deAnnotateGraph(); 496 497 Iterator nodes = _graphModel.nodes(_model); 498 499 while (nodes.hasNext()) { 500 Location node = (Location) nodes.next(); 501 NamedObj entity = (NamedObj) _graphModel.getSemanticObject(node); 502 503 if (_entities.contains(entity)) { 504 Figure figure = _controller.getFigure(node); 505 _selectionModel.addSelection(figure); 506 507 Iterator edges = GraphUtilities.partiallyContainedEdges(node, 508 _graphModel); 509 510 while (edges.hasNext()) { 511 Object edge = edges.next(); 512 Object relation = _graphModel.getSemanticObject(edge); 513 514 if (relation instanceof Relation 515 && _relations.contains(relation)) { 516 Figure relationFigure = _controller.getFigure(edge); 517 _selectionModel.addSelection(relationFigure); 518 } 519 } 520 } 521 } 522 } 523 524 /////////////////////////////////////////////////////////////////// 525 //// private variables //// 526 GraphController _controller = null; 527 528 SelectionRenderer _defaultSelectionRenderer = null; 529 530 Set<ComponentEntity> _entities = null; 531 532 JLabel _fullSolutionResult = new JLabel("Not Run"); 533 534 JButton _setToSelectedButton = new JButton("Set To Selected"); 535 536 JButton _showComponentsButton = new JButton("Show Components"); 537 538 TypedCompositeActor _model = null; 539 540 SelectionModel _selectionModel = null; 541 542 AbstractBasicGraphModel _graphModel = null; 543 544 Set<Relation> _relations = null; 545 546 SelectionInteractor _selectionInteractor = null; 547 548 Vector _solutions = new Vector(); 549 550 JList _solutionsList = null; 551 552 SolutionListModel _solutionsListModel = null; 553 554 JButton _runMinimalSpanSolverButton = new JButton("Run"); 555 556 JButton _runFullSolverButton = new JButton("Run"); 557 558 Tableau _tableau = null; 559 560 UnitConstraints _uConstraints = null; 561}