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.gui; 031 032import java.awt.Dimension; 033import java.awt.Frame; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.util.Iterator; 037import java.util.Vector; 038 039import javax.swing.BorderFactory; 040import javax.swing.Box; 041import javax.swing.BoxLayout; 042import javax.swing.DefaultCellEditor; 043import javax.swing.JButton; 044import javax.swing.JComboBox; 045import javax.swing.JLabel; 046import javax.swing.JOptionPane; 047import javax.swing.JPanel; 048import javax.swing.JScrollPane; 049import javax.swing.JTable; 050import javax.swing.ListSelectionModel; 051import javax.swing.event.TableModelEvent; 052import javax.swing.table.AbstractTableModel; 053import javax.swing.table.TableColumn; 054 055import org.kepler.sms.NamedOntClass; 056import org.kepler.sms.NamedOntModel; 057import org.kepler.sms.OntologyCatalog; 058import org.kepler.sms.SemanticType; 059 060import ptolemy.kernel.util.NamedObj; 061 062/** 063 * 064 * @author Shawn Bowers 065 */ 066public class SemanticLinkTable extends JPanel { 067 068 /** 069 * This is the default constructor 070 * 071 * @param owner 072 * The frame that owns the dialog. 073 */ 074 public SemanticLinkTable(Frame owner) { 075 super(); 076 _owner = owner; 077 _catalog = OntologyCatalog.instance(); 078 // set up pane 079 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 080 add(_createTable()); 081 add(Box.createRigidArea(new Dimension(5, 0))); 082 add(_createButtons()); 083 // set size 084 setSize(450, 285); 085 } 086 087 /** 088 * Add an object to the set of objects being annotated within this panel. 089 * 090 * @param obj 091 * The object to add. 092 */ 093 public void addLinkDomainObject(NamedObj obj) { 094 if (obj == null) 095 return; 096 097 for (Iterator iter = _linkDomainObjects.iterator(); iter.hasNext();) { 098 Object[] entry = (Object[]) iter.next(); 099 if (entry[0].equals(obj)) 100 return; 101 } 102 Object[] entry = new Object[2]; 103 entry[0] = obj; 104 entry[1] = _initializeNamedObj(obj); 105 _linkDomainObjects.add(entry); 106 } 107 108 /** 109 * @return The set of linkDomain objects being annotated with the panel. 110 */ 111 public Vector getLinkDomainObjects() { 112 Vector result = new Vector(); 113 for (Iterator iter = _linkDomainObjects.iterator(); iter.hasNext();) { 114 Object[] entry = (Object[]) iter.next(); 115 result.add(entry[0]); 116 } 117 return result; 118 } 119 120 /** 121 * Causes the given object to become visible in the given display. The given 122 * linkDomain object is added if it is not currently one of the linkDomain 123 * objects of the panel. 124 * 125 * @param obj 126 * The linkDomain object to make visible. 127 */ 128 public void setLinkDomainObjectVisible(NamedObj obj) { 129 // add it if it doesn't exist 130 addLinkDomainObject(obj); 131 _SemLinkTableModel model = null; 132 for (Iterator iter = _linkDomainObjects.iterator(); iter.hasNext();) { 133 Object[] entry = (Object[]) iter.next(); 134 if (entry[0].equals(obj)) { 135 model = (_SemLinkTableModel) entry[1]; 136 break; 137 } 138 } 139 if (model == null) 140 return; 141 _table.setModel(model); 142 } 143 144 /** 145 * FIXME: Fill in... 146 * 147 * @return The set of linkDomain objects whose semantic types that have been 148 * modified. 149 */ 150 public Vector getModifiedLinkDomainObjects() { 151 return getLinkDomainObjects(); 152 } 153 154 /** 155 * FIXME: Fill in... 156 */ 157 public boolean commitLinkDomainObjects() { 158 return true; 159 } 160 161 /** 162 * Initialize the table 163 */ 164 private JPanel _createTable() { 165 // text label 166 JPanel txtPane = new JPanel(); 167 txtPane.setLayout(new BoxLayout(txtPane, BoxLayout.LINE_AXIS)); 168 txtPane.add(new JLabel("Semantic Links")); 169 txtPane.add(Box.createHorizontalGlue()); 170 171 // set up the table 172 _table = new JTable(new _SemLinkTableModel()); // 0 row and 3 columns 173 _table.setPreferredScrollableViewportSize(new Dimension(325, 80)); 174 175 // set up where the column draws ontologies from 176 TableColumn ontoColumn = _table.getColumnModel().getColumn(1); 177 JComboBox comboBox = new JComboBox(); 178 comboBox.setEditable(true); 179 for (Iterator iter = _catalog.getOntologyNames(); iter.hasNext();) 180 comboBox.addItem("" + iter.next()); 181 ontoColumn.setCellEditor(new DefaultCellEditor(comboBox)); 182 183 // misc. config. 184 _table.setColumnSelectionAllowed(false); 185 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 186 187 // set up the overall pane 188 JPanel pane = new JPanel(); 189 pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); 190 pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 191 pane.add(txtPane); 192 pane.add(Box.createRigidArea(new Dimension(0, 5))); 193 pane.add(new JScrollPane(_table)); 194 195 // return the pane 196 return pane; 197 } 198 199 /** 200 * Initialize the bottom buttons (close) 201 */ 202 private JPanel _createButtons() { 203 JPanel pane = new JPanel(); 204 pane.setLayout(new BoxLayout(pane, BoxLayout.LINE_AXIS)); 205 pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 206 pane.add(Box.createHorizontalGlue()); 207 pane.add(_addBtn); 208 pane.add(Box.createRigidArea(new Dimension(10, 0))); 209 pane.add(_removeBtn); 210 pane.add(Box.createRigidArea(new Dimension(10, 0))); 211 212 // init buttons 213 _addBtn.setActionCommand("add"); 214 _addBtn.setToolTipText("Add new row for semantic types"); 215 _addBtn.addActionListener(_buttonListener); 216 _addBtn.setEnabled(false); 217 _removeBtn.setActionCommand("remove"); 218 _removeBtn.setToolTipText("Remove selected semantic type"); 219 _removeBtn.addActionListener(_buttonListener); 220 _removeBtn.setEnabled(false); 221 222 return pane; 223 } 224 225 /** 226 * anonymous class to handle button events 227 */ 228 private ActionListener _buttonListener = new ActionListener() { 229 public void actionPerformed(ActionEvent e) { 230 if (e.getActionCommand().equals("add")) { 231 // add a new row to the table 232 _SemLinkTableModel model = (_SemLinkTableModel) _table 233 .getModel(); 234 model.insertEmptyRow(); 235 } else if (e.getActionCommand().equals("remove")) { 236 // remove current row 237 int rowIndex = _table.getSelectedRow(); 238 if (rowIndex == -1) 239 return; 240 _SemLinkTableModel model = (_SemLinkTableModel) _table 241 .getModel(); 242 model.removeRow(rowIndex); 243 } 244 } 245 }; 246 247 /** 248 * inner class for managing the table data 249 */ 250 private class _SemLinkTableModel extends AbstractTableModel { 251 // private members 252 private String[] tableHeader = { "Ontology", "Property", "Range", 253 "Conditions" }; 254 private Vector tableData = new Vector(); // vector of arrays 255 256 /** 257 * get the column count 258 */ 259 public int getColumnCount() { 260 return tableHeader.length; 261 } 262 263 /** 264 * get the row cound 265 */ 266 public int getRowCount() { 267 return tableData.size(); 268 } 269 270 /** 271 * get the column name 272 */ 273 public String getColumnName(int columnIndex) { 274 return tableHeader[columnIndex]; 275 } 276 277 /** 278 * get the value of a cell 279 */ 280 public Object getValueAt(int rowIndex, int columnIndex) { 281 Object[] row = (Object[]) tableData.elementAt(rowIndex); 282 return row[columnIndex]; 283 } 284 285 /** 286 * everything is editable 287 */ 288 public boolean isCellEditable(int rowIndex, int columnIndex) { 289 return true; 290 } 291 292 /** 293 * sets the value in the column. checks that the term is valid? 294 */ 295 public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 296 if (!validRowIndex(rowIndex)) 297 return; 298 Object[] row = (Object[]) tableData.elementAt(rowIndex); 299 row[columnIndex] = aValue; 300 fireTableChanged(new TableModelEvent(this)); // change event 301 } 302 303 /** 304 * Insert a new named ontology class into the model 305 */ 306 public void insertRow(NamedOntClass cls) { 307 Object[] row = new Object[2]; 308 row[1] = cls.getOntologyName(); 309 row[2] = cls.getName(); 310 if (rowExists(row)) // if exists, return 311 return; 312 // make sure there are no empty rows (if so, to first one) 313 int index = firstEmptyRow(); 314 if (index != -1) 315 tableData.setElementAt(row, index); 316 else 317 tableData.add(row); 318 fireTableChanged(new TableModelEvent(this)); 319 } 320 321 /** 322 * @return True if the table contains the given class, and false 323 * otherwise. 324 */ 325 public boolean containsRow(NamedOntClass cls) { 326 Object[] tmpRow = new Object[2]; 327 tmpRow[0] = cls.getOntologyName(); 328 tmpRow[1] = cls.getName(); 329 return rowExists(tmpRow); 330 } 331 332 /** 333 * @return a list of rows of non-empty Object arrays of arity 2 334 * (Object[2]) 335 */ 336 public Iterator getRows() { 337 Vector results = new Vector(); 338 for (Iterator iter = tableData.iterator(); iter.hasNext();) { 339 Object[] row = (Object[]) iter.next(); 340 if (row[0] != null || row[1] != null || row[2] != null) 341 results.add(row); 342 } 343 return results.iterator(); 344 } 345 346 /** 347 * insert an empty row 348 */ 349 public void insertEmptyRow() { 350 tableData.addElement(new Object[3]); 351 fireTableChanged(new TableModelEvent(this)); // change event 352 } 353 354 /** 355 * @return the first empty row or -1 if no empties 356 */ 357 private int firstEmptyRow() { 358 int index = 0; 359 for (Iterator iter = tableData.iterator(); iter.hasNext(); index++) { 360 Object[] row = (Object[]) iter.next(); 361 if (row[0] == null && row[1] == null && row[2] == null) 362 return index; 363 } 364 return -1; 365 } 366 367 /** 368 * @return true if the row already exists 369 */ 370 private boolean rowExists(Object[] newrow) { 371 for (Iterator iter = tableData.iterator(); iter.hasNext();) { 372 Object[] row = (Object[]) iter.next(); 373 if (newrow[0].equals(row[0]) && newrow[1].equals(row[1]) 374 && newrow[2].equals(row[2])) 375 return true; 376 } 377 return false; 378 } 379 380 /** 381 * remove selected row 382 */ 383 public void removeRow(int rowIndex) { 384 if (!validRowIndex(rowIndex)) 385 return; 386 tableData.removeElementAt(rowIndex); 387 fireTableChanged(new TableModelEvent(this)); // change event 388 } 389 390 /** 391 * check that we are at a valid row 392 */ 393 private boolean validRowIndex(int rowIndex) { 394 if (rowIndex >= 0 && rowIndex < getRowCount()) 395 return true; 396 return false; 397 } 398 }; 399 400 /** 401 * intializes the table with the named objects current semantic types 402 */ 403 private _SemLinkTableModel _initializeNamedObj(NamedObj obj) { 404 // create a new model 405 _SemLinkTableModel model = new _SemLinkTableModel(); 406 // add rows to it (named ontology classes of the item) 407 // for(Iterator iter = _getObjectsNamedOntClasses(obj); iter.hasNext();) 408 // { 409 // NamedOntClass cls = (NamedOntClass)iter.next(); 410 // model.insertRow(cls); 411 // } 412 return model; 413 } 414 415 /** 416 * @return A list of all named ontology classes for the current named object 417 * (if one exists) 418 */ 419 private Iterator _getObjectsNamedOntClasses(NamedObj obj) { 420 Vector result = new Vector(); 421 if (obj == null) 422 return result.iterator(); 423 for (Iterator iter = obj.attributeList(SemanticType.class).iterator(); iter 424 .hasNext();) { 425 SemanticType st = (SemanticType) iter.next(); 426 NamedOntClass cls = _catalog.getNamedOntClass(st); 427 if (cls != null) 428 result.add(cls); 429 } 430 return result.iterator(); 431 } 432 433 /** 434 * Performs the close button operation. 435 */ 436 // protected boolean _doClose() { 437 // for(Iterator iter = getLinkDomainObjects().iterator(); iter.hasNext();) { 438 // NamedObj obj = (NamedObj)iter.next(); 439 // if(_semTypesChanged(obj)) { 440 // Object[] options = {"Yes", "No", "Cancel"}; 441 // String msg = "Would you like to save the changes you made to '" + 442 // obj.getName() + "'?"; 443 // int n = JOptionPane.showOptionDialog(this, msg, "Message", 444 // JOptionPane.YES_NO_CANCEL_OPTION, 445 // JOptionPane.QUESTION_MESSAGE, null, options, options[2]); 446 // if(n == 0 && _saveSemLinks()) { 447 // _close(); 448 // return true; 449 // } 450 // else if(n ==1) { 451 // _close(); 452 // return true; 453 // } 454 // return false; 455 // } 456 // _close(); 457 // return true; 458 // } 459 /** 460 * Performs the commit button operation. 461 */ 462 // protected void _doCommit() { 463 // if(_semTypesChanged()) 464 // _saveSemLinks(); 465 // } 466 467 /** 468 * Saves the semantic types in the table to the named object. 469 * 470 * @return True if the semantic types are well-formed and the save 471 * succeeded, and false otherwise. 472 */ 473 // private boolean _saveSemLinks() { 474 // String msg; 475 // if(!_wellFormedSemanticTypes()) 476 // return false; 477 // if(!_accessibleSemanticTypes()) 478 // return false; 479 // // remove current semtypes 480 // _removeNamedObjSemtypes(); 481 // // add new ones (make sure to remove dups) 482 // _addSemLinks(); 483 // // save if in actor library (has id) ... ? 484 // return true; 485 // } 486 /** 487 * Adds the semantic types in the dialog to the entity. 488 */ 489 private void _addSemLinks(NamedObj obj, _SemLinkTableModel model) { 490 Vector result = new Vector(); 491 492 for (Iterator iter = model.getRows(); iter.hasNext();) { 493 String namespace = ""; 494 String classname = ""; 495 // get the row 496 Object[] row = (Object[]) iter.next(); 497 boolean foundModel = false, foundClass = false; 498 // search for namespace 499 for (Iterator models = _catalog.getNamedOntModels(); models 500 .hasNext();) { 501 NamedOntModel m = (NamedOntModel) models.next(); 502 if (row[0].equals(m.getName())) { 503 namespace = m.getNameSpace(); 504 foundModel = true; 505 // search for classname 506 for (Iterator classes = m.getNamedClasses(); classes 507 .hasNext();) { 508 NamedOntClass c = (NamedOntClass) classes.next(); 509 if (row[1].equals(c.getName())) { 510 classname = c.getLocalName(); 511 foundClass = true; 512 break; 513 } 514 } 515 break; 516 } 517 } 518 if (!foundModel) { 519 namespace = row[0].toString(); 520 classname = row[1].toString(); 521 } else if (!foundClass) { 522 classname = row[1].toString(); 523 } 524 // create id 525 if ((namespace + classname).split("#").length != 2) { 526 String[] ns_array = namespace.split("#"); 527 namespace = ""; 528 for (int i = 0; i < ns_array.length; i++) 529 namespace = namespace + ns_array[i]; 530 namespace = namespace + "#"; 531 String[] cl_array = classname.split("#"); 532 classname = ""; 533 for (int i = 0; i < cl_array.length; i++) 534 classname = classname + cl_array[i]; 535 } 536 String id = namespace + classname; 537 if (!result.contains(id)) 538 result.add(id); 539 } 540 // add the semantic type 541 int i = 0; 542 for (Iterator iter = result.iterator(); iter.hasNext();) { 543 try { 544 SemanticType st = new SemanticType(obj, "semanticType" + i++); 545 st.setExpression((String) iter.next()); 546 } catch (Exception e) { 547 e.printStackTrace(); 548 } 549 } 550 } 551 552 /** 553 * @return True if every semantic type in the table has an ontology value 554 * and class value. 555 */ 556 private boolean _wellFormedSemanticTypes(_SemLinkTableModel model) { 557 String msg; 558 for (Iterator iter = model.getRows(); iter.hasNext();) { 559 Object[] row = (Object[]) iter.next(); 560 if (row[0] == null) { 561 msg = "Commit Error: Every semantic type must have an ontology value."; 562 JOptionPane.showMessageDialog(this, msg, "Message", 563 JOptionPane.ERROR_MESSAGE); 564 return false; 565 } 566 if (row[1] == null) { 567 msg = "Commit Error: Every semantic type must have a class value."; 568 JOptionPane.showMessageDialog(this, msg, "Message", 569 JOptionPane.ERROR_MESSAGE); 570 return false; 571 } 572 } 573 return true; 574 } 575 576 /** 577 * @return True if all the semantic types are "known" to the local version 578 * of kepler. 579 */ 580 private boolean _accessibleSemanticTypes(_SemLinkTableModel model) { 581 String msg; 582 for (Iterator iter = model.getRows(); iter.hasNext();) { 583 boolean classFound = false; 584 Object[] row = (Object[]) iter.next(); 585 for (Iterator iter2 = _catalog.getNamedOntModels(); iter2.hasNext();) { 586 NamedOntModel ontmodel = (NamedOntModel) iter2.next(); 587 if (row[0].equals(ontmodel.getName()) 588 || row[0].equals(ontmodel.getNameSpace())) { 589 for (Iterator iter3 = ontmodel.getNamedClasses(); iter3 590 .hasNext();) { 591 NamedOntClass cls = (NamedOntClass) iter3.next(); 592 if (row[1].equals(cls.getName()) 593 || row[1].equals(cls.getLocalName())) 594 classFound = true; 595 } 596 } 597 } 598 if (!classFound) { 599 msg = "Unable to find a matching class for at least one semantic type. \n" 600 + "Do you wish to save anyway?"; 601 int n = JOptionPane.showConfirmDialog(this, msg, "Message", 602 JOptionPane.YES_NO_OPTION); 603 if (n == 1) 604 return false; 605 break; 606 } 607 } 608 return true; 609 } 610 611 /** 612 * Removes the current semtypes on the named object 613 */ 614 private void _removeNamedObjSemtypes(NamedObj obj) { 615 if (obj == null) 616 return; 617 618 Vector semtypes = new Vector(); 619 for (Iterator iter = obj.attributeList(SemanticType.class).iterator(); iter 620 .hasNext();) 621 semtypes.add((SemanticType) obj); 622 623 for (Iterator iter = semtypes.iterator(); iter.hasNext();) { 624 SemanticType st = (SemanticType) iter.next(); 625 try { 626 st.setContainer(null); 627 } catch (Exception e) { 628 e.printStackTrace(); 629 } 630 } 631 } 632 633 /** 634 * Really shut the thing down. 635 */ 636 private void _close() { 637 } 638 639 /** 640 * @return True if the semantic types have changed since the last commit; 641 * false otherwise 642 */ 643 private boolean _semLinksChanged(NamedObj obj, _SemLinkTableModel model) { 644 // each namedObject semantic type should be in the dialog 645 Vector types = new Vector(); 646 for (Iterator iter = _getObjectsNamedOntClasses(obj); iter.hasNext();) { 647 NamedOntClass cls = (NamedOntClass) iter.next(); 648 if (!model.containsRow(cls)) 649 return true; 650 types.add(cls); 651 } 652 653 // there shouldn't be more rows 654 Vector rows = new Vector(); 655 for (Iterator iter = model.getRows(); iter.hasNext();) 656 rows.add(iter.next()); 657 658 return rows.size() != types.size(); 659 } 660 661 // private members 662 private Vector _linkDomainObjects = new Vector(); 663 private JTable _table = null; // the ontology, class table 664 private JButton _addBtn = new JButton("Add"); // button for adding rows to 665 // table 666 private JButton _removeBtn = new JButton("Remove"); // button removing items 667 private Frame _owner; // the owner of this dialog 668 private OntologyCatalog _catalog; // holds the ontologies 669}