001/* 002 * Copyright (c) 2005-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 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.sms.actors; 031 032import java.awt.Component; 033import java.awt.Dimension; 034import java.awt.Frame; 035import java.awt.event.ActionEvent; 036import java.awt.event.ActionListener; 037import java.util.Iterator; 038import java.util.Vector; 039 040import javax.swing.BorderFactory; 041import javax.swing.Box; 042import javax.swing.BoxLayout; 043import javax.swing.JButton; 044import javax.swing.JComboBox; 045import javax.swing.JDialog; 046import javax.swing.JLabel; 047import javax.swing.JOptionPane; 048import javax.swing.JPanel; 049import javax.swing.JScrollPane; 050import javax.swing.JTable; 051import javax.swing.ScrollPaneConstants; 052import javax.swing.SwingConstants; 053import javax.swing.table.AbstractTableModel; 054 055import ptolemy.actor.IOPort; 056import ptolemy.kernel.util.NamedObj; 057 058public class MappingRefinementDialog extends JDialog { 059 060 /** 061 * Note: Only entities may have ports 062 */ 063 public static void showDialog(Frame aFrame, MergeActor mergeActor, 064 MergeEditorDialog parent) { 065 MappingRefinementDialog d = new MappingRefinementDialog(aFrame, 066 mergeActor, parent); 067 } 068 069 /** 070 * 071 */ 072 protected MappingRefinementDialog(Frame aFrame, MergeActor mergeActor, 073 MergeEditorDialog parent) { 074 super(aFrame, true); 075 setTitle("Refine Input-Output Mappings"); 076 077 _mergeActor = mergeActor; 078 _parent = parent; 079 080 // load all the given mappings for the merge actor 081 _loadMappings(); 082 083 JPanel pane = new JPanel(); 084 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 085 pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 086 087 pane.add(_createInputPortList()); 088 pane.add(Box.createRigidArea(new Dimension(0, 10))); 089 pane.add(_createOutputPortList()); 090 pane.add(Box.createRigidArea(new Dimension(0, 10))); 091 pane.add(_createButtons()); 092 093 // set up the dialog 094 this.setContentPane(pane); 095 this.setResizable(false); 096 this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 097 this.pack(); 098 this.show(); 099 } 100 101 /** 102 * 103 */ 104 private JPanel _createInputPortList() { 105 JPanel pane = new JPanel(); 106 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 107 108 // get the list of actors 109 Vector actors = new Vector(); 110 Iterator iter = _mergeActor.getActors().iterator(); 111 while (iter.hasNext()) { 112 NamedObj obj = (NamedObj) iter.next(); 113 actors.add(new _ActorWrapper(obj)); 114 } 115 116 _cbActors = new JComboBox(actors); 117 _cbActors.setEditable(false); 118 _cbActors.setSelectedIndex(-1); 119 _cbActors.setPreferredSize(new Dimension(250, 20)); 120 _cbActors.setMaximumSize(new Dimension(250, 20)); 121 _cbActors.addActionListener(new ActionListener() { 122 public void actionPerformed(ActionEvent e) { 123 _actorChoiceChanged(); 124 } 125 }); 126 pane.add(_labelComponent("Source Actor", _cbActors, 250, 50)); 127 pane.add(Box.createRigidArea(new Dimension(0, 5))); 128 129 _cbPorts = new JComboBox(); 130 _cbPorts.setEditable(false); 131 _cbPorts.setSelectedIndex(-1); 132 _cbPorts.setPreferredSize(new Dimension(250, 20)); 133 _cbPorts.setMaximumSize(new Dimension(250, 20)); 134 _cbPorts.addActionListener(new ActionListener() { 135 public void actionPerformed(ActionEvent e) { 136 _portChoiceChanged(); 137 } 138 }); 139 pane.add(_labelComponent("Source Actor Port", _cbPorts, 250, 50)); 140 141 return pane; 142 } 143 144 /** 145 * 146 */ 147 private JPanel _createOutputPortList() { 148 JPanel pane = new JPanel(); 149 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 150 151 _tblPortList = new JTable(_model); 152 _tblPortList.setCellSelectionEnabled(false); 153 _tblPortList.setColumnSelectionAllowed(false); 154 _tblPortList.setRowSelectionAllowed(false); 155 _tblPortList.setShowGrid(false); 156 Iterator<IOPort> iter = _parent.getTargetPorts().iterator(); 157 while (iter.hasNext()) { 158 IOPort p = iter.next(); 159 _model.insertRow(new _IOPortWrapper(p), new Boolean(false)); 160 } 161 JScrollPane view = new JScrollPane(_tblPortList, 162 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 163 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 164 view.setPreferredSize(new Dimension(260, 150)); 165 view.setMaximumSize(new Dimension(260, 150)); 166 pane.add(view); 167 168 return pane; 169 } 170 171 /** 172 * 173 */ 174 private JPanel _createButtons() { 175 JPanel pane = new JPanel(); 176 pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS)); 177 pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 178 179 _btnOK = new JButton("OK"); 180 _btnCancel = new JButton("Cancel"); 181 182 pane.add(Box.createHorizontalGlue()); 183 pane.add(_btnOK); 184 pane.add(Box.createRigidArea(new Dimension(15, 0))); 185 pane.add(_btnCancel); 186 187 // add listeners to the buttons 188 _btnOK.addActionListener(new ActionListener() { 189 public void actionPerformed(ActionEvent ev) { 190 _doOK(); 191 } 192 }); 193 194 _btnCancel.addActionListener(new ActionListener() { 195 public void actionPerformed(ActionEvent ev) { 196 dispose(); 197 } 198 }); 199 200 return pane; 201 } 202 203 public void _actorChoiceChanged() { 204 _ActorWrapper w = (_ActorWrapper) _cbActors.getSelectedItem(); 205 if (w == null) 206 return; 207 NamedObj actor = w.getActor(); 208 // clear the old ports 209 _cbPorts.removeAllItems(); 210 // populate the port combo box 211 Iterator<IOPort> ports = _mergeActor.getActorPorts(actor).iterator(); 212 while (ports.hasNext()) { 213 IOPort p = ports.next(); 214 _cbPorts.addItem(new _IOPortWrapper(p)); 215 }// end while 216 } 217 218 public void _portChoiceChanged() { 219 // get the actor 220 _ActorWrapper aw = (_ActorWrapper) _cbActors.getSelectedItem(); 221 // get the new port 222 _IOPortWrapper pw = (_IOPortWrapper) _cbPorts.getSelectedItem(); 223 if (aw == null || pw == null) 224 return; 225 //NamedObj actor = aw.getActor(); 226 IOPort port = pw.getPort(); 227 Vector<IOPort> targets = _getCurrentTargetPorts(port); 228 for (int i = 0; i < _model.getRowCount(); i++) { 229 _IOPortWrapper tw = (_IOPortWrapper) _model.getValueAt(i, 0); 230 IOPort target = tw.getPort(); 231 if (targets.contains(target)) 232 _model.setValueAt(new Boolean(true), i, 1); 233 else 234 _model.setValueAt(new Boolean(false), i, 1); 235 }// end for 236 } 237 238 private Vector<IOPort> _getCurrentTargetPorts(IOPort port) { 239 Vector<IOPort> results = new Vector<IOPort>(); 240 String actorName = port.getContainer().getName(); 241 String portName = port.getName(); 242 Iterator<SimpleMergeMapping> maps = _mappings.iterator(); 243 while (maps.hasNext()) { 244 SimpleMergeMapping m = maps.next(); 245 if (actorName.equals(m.getSourceActor()) 246 && portName.equals(m.getSourceActorPort())) { 247 String outName = m.getTargetPort(); 248 Iterator<IOPort> ports = _parent.getTargetPorts().iterator(); 249 while (ports.hasNext()) { 250 IOPort p = ports.next(); 251 if (outName.equals(p.getName())) 252 results.add(p); 253 }// end while 254 } 255 }// end while 256 return results; 257 } 258 259 /** 260 * Given a label string, component, height, and width, creates a new panel 261 * with a label and the component of size height and width. The label is 262 * positioned above the component and is left justified. 263 */ 264 private JPanel _labelComponent(String str, Component component, int width, 265 int height) { 266 // output pane 267 JPanel pane = new JPanel(); 268 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 269 // pane for label only 270 JPanel labelPane = new JPanel(); 271 labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS)); 272 labelPane.add(new JLabel(str, SwingConstants.LEFT)); 273 labelPane.add(Box.createHorizontalGlue()); 274 // add label 275 pane.add(labelPane); 276 // add space 277 pane.add(Box.createRigidArea(new Dimension(0, 5))); 278 // add component 279 pane.add(component); 280 // set sizes 281 pane.setMaximumSize(new Dimension(width, height)); 282 pane.setMinimumSize(new Dimension(width, height)); 283 pane.setPreferredSize(new Dimension(width, height)); 284 // return outer pane 285 return pane; 286 } 287 288 private void _loadMappings() { 289 Iterator<SimpleMergeMapping> iter = _parent.getMappings().iterator(); 290 while (iter.hasNext()) { 291 SimpleMergeMapping mapping = iter.next(); 292 String actor = mapping.getSourceActor(); 293 String actorPort = mapping.getSourceActorPort(); 294 String target = mapping.getTargetPort(); 295 try { 296 SimpleMergeMapping m = new SimpleMergeMapping(actor, actorPort, 297 target); 298 _mappings.add(m); 299 } catch (Exception e) { 300 e.printStackTrace(); 301 } 302 }// end while 303 } 304 305 private void _addMapping(IOPort target) { 306 _ActorWrapper aw = (_ActorWrapper) _cbActors.getSelectedItem(); 307 _IOPortWrapper pw = (_IOPortWrapper) _cbPorts.getSelectedItem(); 308 if (aw == null || pw == null) 309 return; 310 NamedObj actor = aw.getActor(); 311 IOPort port = pw.getPort(); 312 try { 313 SimpleMergeMapping m = new SimpleMergeMapping(actor.getName(), port 314 .getName(), target.getName()); 315 if (!_mappings.contains(m)) 316 _mappings.add(m); 317 } catch (Exception e) { 318 e.printStackTrace(); 319 } 320 } 321 322 private void _removeMapping(IOPort target) { 323 _ActorWrapper aw = (_ActorWrapper) _cbActors.getSelectedItem(); 324 _IOPortWrapper pw = (_IOPortWrapper) _cbPorts.getSelectedItem(); 325 if (aw == null || pw == null) 326 return; 327 NamedObj actor = aw.getActor(); 328 IOPort port = pw.getPort(); 329 try { 330 SimpleMergeMapping m = new SimpleMergeMapping(actor.getName(), port 331 .getName(), target.getName()); 332 _mappings.remove(m); 333 } catch (Exception e) { 334 e.printStackTrace(); 335 } 336 } 337 338 /** 339 * 340 */ 341 private void _doOK() { 342 // we don't care about the current one ... 343 // we want to look at all and check that they each have targets 344 Iterator actors = _mergeActor.getActors().iterator(); 345 while (actors.hasNext()) { 346 NamedObj actor = (NamedObj) actors.next(); 347 String actorName = actor.getName(); 348 Iterator<IOPort> ports = _mergeActor.getActorPorts(actor).iterator(); 349 while (ports.hasNext()) { 350 IOPort port = ports.next(); 351 String portName = port.getName(); 352 // check if well formed 353 if (!_hasTarget(actorName, portName)) { 354 String msg = "Actor '" + actorName 355 + "' is missing an output port target for " 356 + "port '" + portName + "'"; 357 JOptionPane.showMessageDialog(this, msg, "Message", 358 JOptionPane.ERROR_MESSAGE); 359 return; 360 } 361 }// end while 362 if (!_hasAllowableMappings(actor)) { 363 String msg = "Multiple ports for Actor '" + actorName 364 + "' are mapped " + "to the same output port target"; 365 JOptionPane.showMessageDialog(this, msg, "Message", 366 JOptionPane.ERROR_MESSAGE); 367 return; 368 } 369 } 370 // commit the mappings (prune unused ports, etc.) 371 _doCommit(); 372 } 373 374 private void _doCommit() { 375 // copy the parent mappings 376 Vector parentMappings = new Vector(); 377 Iterator iter = _parent.getMappings().iterator(); 378 while (iter.hasNext()) 379 parentMappings.add(iter.next()); 380 381 // keep the same mappings in mergeActor, delete the "old ones" 382 iter = parentMappings.iterator(); 383 while (iter.hasNext()) { 384 try { 385 SimpleMergeMapping m = (SimpleMergeMapping) iter.next(); 386 SimpleMergeMapping mcurr = _getMapping(m.getSourceActor(), m 387 .getSourceActorPort(), m.getTargetPort()); 388 if (mcurr == null) 389 _parent.removeMapping(m); // this mapping was removed in the 390 // refinement 391 else 392 _mappings.remove(mcurr); // this mapping existed, so remove 393 // from current 394 } catch (Exception e) { 395 e.printStackTrace(); 396 } 397 }// end while 398 399 // add the rest of the current mappings to mergeActor 400 iter = _mappings.iterator(); 401 while (iter.hasNext()) { 402 SimpleMergeMapping m = (SimpleMergeMapping) iter.next(); 403 _parent.addMapping(m); 404 } 405 dispose(); 406 } 407 408 /** 409 * @return A mapping from the local mappings that matches the input 410 */ 411 private SimpleMergeMapping _getMapping(String actor, String port, 412 String target) { 413 Iterator iter = _mappings.iterator(); 414 while (iter.hasNext()) { 415 SimpleMergeMapping m = (SimpleMergeMapping) iter.next(); 416 if (actor.equals(m.getSourceActor()) 417 && port.equals(m.getSourceActorPort()) 418 && target.equals(m.getTargetPort())) 419 return m; 420 }// end while 421 return null; 422 } 423 424 private boolean _hasTarget(String actorName, String portName) { 425 Iterator mappings = _mappings.iterator(); 426 boolean found = false; 427 while (mappings.hasNext()) { 428 SimpleMergeMapping m = (SimpleMergeMapping) mappings.next(); 429 if (actorName.equals(m.getSourceActor()) 430 && portName.equals(m.getSourceActorPort())) { 431 found = true; 432 break; 433 } 434 }// end while 435 return found; 436 } 437 438 /** 439 * Given one input and one output port, determines whether they can be an 440 * input-output mapping according to the existing mappings. Currently, the 441 * only mapping not allowed is when the an actor has multiple output ports 442 * mapped to the same target port. Note that a mapping is different than a 443 * "match", which is between input ports (e.g., of different source actors). 444 */ 445 private boolean _hasAllowableMappings(NamedObj actor) { 446 // get all the output port names for the actor 447 Vector<String> ports = new Vector<String>(); 448 Iterator<IOPort> iter = _mergeActor.getActorPorts(actor).iterator(); 449 while (iter.hasNext()) { 450 IOPort p = iter.next(); 451 ports.add(p.getName()); 452 }// end while 453 454 // iterator through the target ports, obtaining their mappings 455 iter = _parent.getTargetPorts().iterator(); 456 while (iter.hasNext()) { 457 IOPort target = iter.next(); 458 // store the actor input ports for the target 459 Vector<String> targetInputs = new Vector<String>(); 460 Iterator<SimpleMergeMapping> mappings = _mappings.iterator(); 461 while (mappings.hasNext()) { 462 SimpleMergeMapping m = mappings.next(); 463 if (m.getTargetPort().equals(target.getName()) 464 && m.getSourceActor().equals(actor.getName())) 465 targetInputs.add(m.getSourceActorPort()); 466 } 467 // check if multiple target inputs 468 if (targetInputs.size() > 1) 469 return false; 470 }// end while 471 472 return true; 473 } 474 475 private void _printMappings() { 476 Iterator iter = _mappings.iterator(); 477 while (iter.hasNext()) { 478 SimpleMergeMapping m = (SimpleMergeMapping) iter.next(); 479 String actor = m.getSourceActor(); 480 String actorPort = m.getSourceActorPort(); 481 String target = m.getTargetPort(); 482 System.out.println("... mapping: " + actor + ", " + actorPort 483 + ", " + target); 484 } 485 } 486 487 /** 488 * 489 */ 490 private class _IOPortWrapper { 491 private IOPort _port; 492 493 public _IOPortWrapper(IOPort port) { 494 _port = port; 495 } 496 497 public IOPort getPort() { 498 return _port; 499 } 500 501 public String toString() { 502 if (_port != null) 503 return _port.getName(); 504 else 505 return ""; 506 } 507 }; 508 509 /** 510 * 511 */ 512 private class _ActorWrapper { 513 private NamedObj _actor; 514 515 public _ActorWrapper(NamedObj actor) { 516 _actor = actor; 517 } 518 519 public NamedObj getActor() { 520 return _actor; 521 } 522 523 public String toString() { 524 if (_actor != null) 525 return _actor.getName(); 526 else 527 return ""; 528 } 529 }; 530 531 private class _PortListTableModel extends AbstractTableModel { 532 private String[] columnNames = { "Output Port", "Target" }; 533 private Vector data = new Vector(); 534 535 public int getColumnCount() { 536 return columnNames.length; 537 } 538 539 public int getRowCount() { 540 return data.size(); 541 } 542 543 public String getColumnName(int col) { 544 return columnNames[col]; 545 } 546 547 public void insertRow(_IOPortWrapper p, Boolean checked) { 548 Object[] row = new Object[2]; 549 row[0] = p; 550 row[1] = checked; 551 addRow(row); 552 } 553 554 public void addRow(Object[] row) { 555 data.add(row); 556 fireTableRowsInserted(getRowCount(), getRowCount()); 557 } 558 559 public void clearRows() { 560 data = new Vector(); 561 fireTableDataChanged(); 562 } 563 564 public Object getValueAt(int row, int col) { 565 Object[] obj = (Object[]) data.elementAt(row); 566 return obj[col]; 567 } 568 569 /* 570 * JTable uses this method to determine the default renderer/ editor for 571 * each cell. If we didn't implement this method, then the last column 572 * would contain text ("true"/"false"), rather than a check box. 573 */ 574 public Class getColumnClass(int c) { 575 if (getColumnName(c).equals(columnNames[0])) 576 return _IOPortWrapper.class; 577 else if (getColumnName(c).equals(columnNames[1])) 578 return Boolean.class; 579 else 580 return Object.class; 581 } 582 583 public void setValueAt(Object value, int row, int col) { 584 Object[] obj = (Object[]) data.elementAt(row); 585 // update the mappings 586 if (col == 1) { 587 _IOPortWrapper w = (_IOPortWrapper) obj[0]; 588 IOPort p = (IOPort) w.getPort(); 589 if (((Boolean) value).booleanValue() == true) 590 _addMapping(p); 591 else if (((Boolean) value).booleanValue() == false) 592 _removeMapping(p); 593 } 594 // change the value 595 obj[col] = value; 596 fireTableCellUpdated(row, col); 597 } 598 599 public boolean rowSelected(int row) { 600 Object[] obj = (Object[]) data.elementAt(row); 601 Boolean sel = (Boolean) obj[1]; 602 if (sel.equals(Boolean.TRUE)) 603 return true; 604 return false; 605 } 606 607 public boolean isCellEditable(int row, int col) { 608 if (getColumnName(col).equals(columnNames[1])) 609 return true; 610 return false; 611 } 612 613 }; 614 615 /** Private members */ 616 private MergeActor _mergeActor; 617 private JButton _btnOK; 618 private JButton _btnCancel; 619 private JComboBox _cbActors; 620 private JComboBox _cbPorts; 621 private JTable _tblPortList; 622 private _PortListTableModel _model = new _PortListTableModel(); 623 private Vector<SimpleMergeMapping> _mappings = new Vector<SimpleMergeMapping>(); 624 private MergeEditorDialog _parent; 625 626}