001 package jigcell.compare.views; 002 003 import EDU.oswego.cs.dl.util.concurrent.Sync; 004 import java.awt.Color; 005 import java.awt.Component; 006 import java.beans.DefaultPersistenceDelegate; 007 import java.beans.Encoder; 008 import java.beans.Expression; 009 import java.beans.PropertyChangeEvent; 010 import java.text.DecimalFormat; 011 import java.util.ArrayList; 012 import java.util.Arrays; 013 import java.util.HashSet; 014 import java.util.Iterator; 015 import java.util.List; 016 import java.util.Map; 017 import javax.swing.JComboBox; 018 import javax.swing.JFileChooser; 019 import javax.swing.JLabel; 020 import javax.swing.JTable; 021 import javax.swing.ListCellRenderer; 022 import javax.swing.SwingConstants; 023 import javax.swing.filechooser.FileFilter; 024 import javax.swing.table.TableColumn; 025 import javax.swing.table.TableColumnModel; 026 import jigcell.compare.IConfigEditor; 027 import jigcell.compare.IDataGenerator; 028 import jigcell.compare.IEditableDataGenerator; 029 import jigcell.compare.IMultipleDataSource; 030 import jigcell.compare.IWriteableDataSource; 031 import jigcell.compare.data.DataElement; 032 import jigcell.compare.data.DataGenerator; 033 import jigcell.compare.data.DataGeneratorList; 034 import jigcell.compare.data.DataGeneratorMap; 035 import jigcell.compare.data.IDataGeneratorCollection; 036 import jigcell.compare.data.IDataGeneratorList; 037 import jigcell.compare.data.IDataGeneratorMap; 038 import jigcell.compare.data.IResultSetMap; 039 import jigcell.compare.data.ResultSetMap; 040 import jigcell.compare.data.SparseTreeDataElement; 041 import jigcell.compare.impl.Compare; 042 import jigcell.compare.impl.DataGeneratorEvaluator; 043 import jigcell.compare.impl.FileDataSource; 044 import jigcell.compare.impl.SuffixFileFilter; 045 import jigcell.compare.objective.IObjective; 046 import jigcell.compare.objective.Objective; 047 import jigcell.compare.ui.BasicTable; 048 import jigcell.compare.ui.ConfigEditor; 049 import jigcell.compare.ui.IResultTab; 050 import jigcell.compare.ui.InterfaceBuilder; 051 import jigcell.compare.ui.ListComboBoxModel; 052 import jigcell.compare.ui.ProgressMonitor; 053 054 /** 055 * An editable display for working with objective data. 056 * 057 * <p> 058 * This code is licensed under the DARPA BioCOMP Open Source License. See LICENSE for more details. 059 * </p> 060 * 061 * @author Nicholas Allen 062 */ 063 064 public class ObjectiveSeriesView extends EditableSeriesView implements IResultTab, DataGeneratorEvaluator.IProcessor { 065 066 /** 067 * Default background color for cells over the threshold value 068 */ 069 070 public final static Color DEFAULT_BACKGROUNDOVERTHRESHOLD = new Color (255, 96, 96); 071 072 /** 073 * Default background color for cells that cannot be compared to the threshold value 074 */ 075 076 public final static Color DEFAULT_BACKGROUNDUNKNOWNTHRESHOLD = new Color (255, 192, 0); 077 078 /** 079 * Attribute key for the comparison type 080 */ 081 082 public final static String ATTRIBUTE_COMPARISONTYPE = "ObjectiveSeriesView.comparisonType"; 083 084 /** 085 * Attribute key for the objective threshold 086 */ 087 088 public final static String ATTRIBUTE_THRESHOLD = "ObjectiveSeriesView.threshold"; 089 090 /** 091 * Property key for the threshold exceeded background 092 */ 093 094 public final static String CONFIG_BACKGROUNDOVERTHRESHOLD = "ObjectiveSeriesView.backgroundOverThreshold"; 095 096 /** 097 * Property key for the threshold not comparable background 098 */ 099 100 public final static String CONFIG_BACKGROUNDUNKNOWNTHRESHOLD = "ObjectiveSeriesView.backgroundUnknownThreshold"; 101 102 /** 103 * File filter for objective result set files 104 */ 105 106 public final static FileFilter FILTER_OBJECTIVERESULT = new SuffixFileFilter (".res", "Objective Result Set (*.res)"); 107 108 /** 109 * File filter for objective files 110 */ 111 112 public final static FileFilter FILTER_OBJECTIVESET = new SuffixFileFilter (".obs", "Objective Set (*.obs)"); 113 114 /** 115 * Display value for an unevaluated value 116 */ 117 118 protected final static String VALUE_NOTEVALUATED = "Not Evaluated"; 119 120 /** 121 * Display value for a non-existent value 122 */ 123 124 protected final static String VALUE_NOVALUE = "No Value"; 125 126 /** 127 * List of known objectives 128 */ 129 130 protected IDataGeneratorList objectives; 131 132 /** 133 * Display for list of known objectives 134 */ 135 136 protected ListComboBoxModel objectiveModel; 137 138 /** 139 * Data model of the generators 140 */ 141 142 protected ObjectiveSeriesModel model; 143 144 /** 145 * Comparison type for threshold flagging. 146 */ 147 148 public final static class Comparison { 149 150 /** 151 * Accept equivalent values only 152 */ 153 154 public final static Comparison EQUIVALENT = new Comparison ("="); 155 156 /** 157 * Accept values greater than the threshold 158 */ 159 160 public final static Comparison GREATERTHAN = new Comparison (">"); 161 162 /** 163 * Accept values greater than or equal to the threshold 164 */ 165 166 public final static Comparison GREATERTHANEQUAL = new Comparison (">="); 167 168 /** 169 * Ignore the value of this comparison 170 */ 171 172 public final static Comparison IGNORE = new Comparison ("Ignore"); 173 174 /** 175 * Accept values less than the threshold 176 */ 177 178 public final static Comparison LESSTHAN = new Comparison ("<"); 179 180 /** 181 * Accept values less than or equal to the threshold 182 */ 183 184 public final static Comparison LESSTHANEQUAL = new Comparison ("<="); 185 186 /** 187 * List of available types 188 */ 189 190 private final static List types = new ArrayList (); 191 192 /** 193 * Name of this type 194 */ 195 196 private final String name; 197 198 /** 199 * Looks up the singleton value instead of creating a new instance. 200 */ 201 202 protected static class ComparisonDelegate extends DefaultPersistenceDelegate { 203 protected Expression instantiate (Object o, Encoder encoder) { 204 return new Expression (o, Comparison.class, "findInstance", new Object [] {((Comparison) o).toString ()}); 205 } 206 } 207 208 static { 209 types.add (EQUIVALENT); 210 types.add (LESSTHAN); 211 types.add (LESSTHANEQUAL); 212 types.add (GREATERTHAN); 213 types.add (GREATERTHANEQUAL); 214 types.add (IGNORE); 215 Compare.addDelegate (Comparison.class, new ComparisonDelegate ()); 216 } 217 218 /** 219 * Finds an instance of this class based on a given name. 220 * 221 * @param name Name 222 */ 223 224 public static Comparison findInstance (String name) { 225 if (name == null || IGNORE.name.equals (name)) 226 return IGNORE; 227 if (GREATERTHAN.name.equals (name)) 228 return GREATERTHAN; 229 if (GREATERTHANEQUAL.name.equals (name)) 230 return GREATERTHANEQUAL; 231 if (LESSTHAN.name.equals (name)) 232 return LESSTHAN; 233 if (LESSTHANEQUAL.name.equals (name)) 234 return LESSTHANEQUAL; 235 return EQUIVALENT; 236 } 237 238 /** 239 * List of possible types. 240 */ 241 242 public static List getTypes () { 243 return types; 244 } 245 246 /** 247 * Tests whether the value is acceptable for this comparison. 248 * 249 * @param value Value 250 * @param threshold Threshold 251 */ 252 253 public boolean testAcceptable (double value, double threshold) { 254 if (this == IGNORE) 255 return true; 256 if (this == LESSTHAN) 257 return value < threshold; 258 if (this == LESSTHANEQUAL) 259 return value <= threshold; 260 if (this == GREATERTHAN) 261 return value > threshold; 262 if (this == GREATERTHANEQUAL) 263 return value >= threshold; 264 return value == 0.0; 265 } 266 267 /** 268 * Whether the second value is better than the first value for this comparison. 269 * 270 * @param value1 First value 271 * @param value2 Second value 272 */ 273 274 public boolean testImproving (double value1, double value2) { 275 if (this == IGNORE) 276 return false; 277 if (this == GREATERTHAN || this == GREATERTHANEQUAL) 278 return value2 > value1; 279 return value2 < value1; 280 } 281 282 public String toString () { 283 return name; 284 } 285 286 /** 287 * Creates a new type of objective comparison. 288 * 289 * @param name Display name 290 */ 291 292 private Comparison (String name) { 293 this.name = name; 294 } 295 } 296 297 /** 298 * Table model for an ObjectiveSummaryView. 299 */ 300 301 protected class ObjectiveSeriesModel extends EditableSeriesModel { 302 303 /** 304 * Prompt to choose an objective 305 */ 306 307 protected final static String MESSAGE_CHOOSERCOMPARISON = "Choose a Comparison Type"; 308 309 /** 310 * Prompt to choose an objective 311 */ 312 313 protected final static String MESSAGE_CHOOSEROBJECTIVE = "Choose an Objective"; 314 315 /** 316 * Threshold display for equivalent values 317 */ 318 319 protected final static String THRESHOLD_EQUIVALENT = "Equivalent"; 320 321 /** 322 * Comparison type column 323 */ 324 325 public final Marker COLUMN_COMPARISONTYPE = new Marker ("ObjectiveSeriesModel.comparisonType", "Criterion"); 326 327 /** 328 * Objective column 329 */ 330 331 public final Marker COLUMN_OBJECTIVE = new Marker ("ObjectiveSeriesModel.objective", "Objective"); 332 333 /** 334 * Objective value column 335 */ 336 337 public final Marker COLUMN_OBJECTIVEVALUE = new Marker ("ObjectiveSeriesModel.objectiveValue", "Objective Result"); 338 339 /** 340 * Threshold column 341 */ 342 343 public final Marker COLUMN_THRESHOLD = new Marker ("ObjectiveSeriesModel.threshold", "Acceptable"); 344 345 /** 346 * Formatter for objective result 347 */ 348 349 protected DecimalFormat objectiveResultFormat; 350 351 /** 352 * Creates a new table model. 353 */ 354 355 public ObjectiveSeriesModel () { 356 super (); 357 setColumnMarkers ( 358 new Marker [] {COLUMN_NAME, COLUMN_OBJECTIVE, COLUMN_OBJECTIVEVALUE, COLUMN_COMPARISONTYPE, COLUMN_THRESHOLD, COLUMN_COMMENT}); 359 setColumnWeights (new double [] {3.0, 2.0, 0.0, 0.0, 0.0, 3.0}); 360 objectiveResultFormat = new DecimalFormat ("##0.0####E0"); 361 objectiveResultFormat.setDecimalSeparatorAlwaysShown (true); 362 } 363 364 /** 365 * Starts editing a cell in the table. 366 * 367 * @param row Row 368 * @param column Column 369 */ 370 371 public void editCellAt (int row, int column) { 372 if (!isCellEditable (row, column)) 373 return; 374 if (column == findColumn (COLUMN_OBJECTIVE)) { 375 setValueAt (manager.showInputDialog (MESSAGE_CHOOSEROBJECTIVE, objectives.toArray (), getValueAt (row, column), "Set"), row, 376 column); 377 return; 378 } 379 if (column == findColumn (COLUMN_COMPARISONTYPE)) { 380 setValueAt (manager.showInputDialog (MESSAGE_CHOOSERCOMPARISON, Comparison.getTypes ().toArray (new Comparison [0]), 381 getValueAt (row, column), "Set"), row, column); 382 return; 383 } 384 super.editCellAt (row, column); 385 } 386 387 /** 388 * Fills along a column. 389 * 390 * @param row Row 391 * @param column Column 392 * @param startRow First row 393 * @param endRow Last row 394 */ 395 396 public void fillRangeAt (int row, int column, int startRow, int endRow) { 397 if (column == findColumn (COLUMN_OBJECTIVE)) { 398 fillRange (column, startRow, endRow, getObjectiveForGenerator (row)); 399 return; 400 } 401 super.fillRangeAt (row, column, startRow, endRow); 402 } 403 404 /** 405 * A value in the table. 406 * 407 * @param row Row 408 * @param column Column 409 */ 410 411 public Object getValueAt (int row, int column) { 412 if (column == findColumn (COLUMN_OBJECTIVEVALUE)) { 413 IObjective objective = getObjectiveForGenerator (row); 414 return objective == null ? VALUE_NOVALUE : 415 objective.isCached () ? objectiveResultFormat.format (objective.getElement ().getRealValue ()) : VALUE_NOTEVALUATED; 416 } 417 if (column == findColumn (COLUMN_OBJECTIVE)) { 418 IObjective objective = getObjectiveForGenerator (row); 419 return objective == null ? (Object) VALUE_NOVALUE : objective; 420 } 421 if (column == findColumn (COLUMN_THRESHOLD)) { 422 IObjective objective = getObjectiveForGenerator (row); 423 if (objective == null) 424 return null; 425 Comparison type = Comparison.findInstance (objective.getAttribute (ATTRIBUTE_COMPARISONTYPE)); 426 if (type == Comparison.IGNORE) 427 return null; 428 if (type == Comparison.EQUIVALENT) 429 return THRESHOLD_EQUIVALENT; 430 String value = objective.getAttribute (ATTRIBUTE_THRESHOLD); 431 return value == null ? VALUE_NOVALUE : value; 432 } 433 if (column == findColumn (COLUMN_COMPARISONTYPE)) { 434 IObjective objective = getObjectiveForGenerator (row); 435 if (objective == null) 436 return null; 437 return Comparison.findInstance (objective.getAttribute (ATTRIBUTE_COMPARISONTYPE)); 438 } 439 return super.getValueAt (row, column); 440 } 441 442 /** 443 * Whether a value in the table is editable. 444 * 445 * @param row Row 446 * @param column Column 447 */ 448 449 public boolean isCellEditable (int row, int column) { 450 if (row < 0 || row >= getRowCount ()) 451 return false; 452 IDataGenerator generator = (IDataGenerator) generators.get (row); 453 if (!(generator instanceof IEditableDataGenerator)) 454 return false; 455 if (column == findColumn (COLUMN_OBJECTIVE) || column == findColumn (COLUMN_COMMENT)) 456 return true; 457 IObjective objective = Objective.getObjectiveForGenerator (generator); 458 if (objective == null) 459 return false; 460 if (column == findColumn (COLUMN_COMPARISONTYPE)) 461 return true; 462 if (column == findColumn (COLUMN_THRESHOLD)) { 463 Comparison type = Comparison.findInstance (objective.getAttribute (ATTRIBUTE_COMPARISONTYPE)); 464 return type != Comparison.IGNORE && type != Comparison.EQUIVALENT; 465 } 466 return false; 467 } 468 469 /** 470 * Sets a value in the table. 471 * 472 * @param value Value 473 * @param row Row 474 * @param column Column 475 */ 476 477 public void setValueAt (Object value, int row, int column) { 478 if (!isCellEditable (row, column)) 479 return; 480 if (column == findColumn (COLUMN_OBJECTIVE)) { 481 if (!(value instanceof IObjective) || value == null) 482 return; 483 IEditableDataGenerator generator = (IEditableDataGenerator) generators.get (row); 484 IObjective objective = (IObjective) ((IObjective) value).copy (true); 485 objective.setCopyName (true); 486 generator.addOption (IObjective.OPTION_OBJECTIVE, IDataGenerator.Option.COPYONLY); 487 generator.setOption (IObjective.OPTION_OBJECTIVE, objective); 488 model.fireTableDataChanged (); 489 return; 490 } 491 if (column == findColumn (COLUMN_THRESHOLD)) { 492 if (!(value instanceof String) || value == null) 493 return; 494 IObjective objective = getObjectiveForGenerator (row); 495 if (objective == null) 496 return; 497 String item = ((String) value).trim (); 498 if (item.length () == 0 || DataElement.isSpecialNonNumeric (item)) 499 objective.setAttribute (ATTRIBUTE_THRESHOLD, null); 500 else 501 try { 502 objective.setAttribute (ATTRIBUTE_THRESHOLD, String.valueOf (Double.parseDouble (item))); 503 } catch (Exception e) { 504 objective.setAttribute (ATTRIBUTE_THRESHOLD, null); 505 Compare.assertion ("Unable to parse threshold value.", e); 506 } 507 model.fireTableDataChanged (); 508 return; 509 } 510 if (column == findColumn (COLUMN_COMPARISONTYPE)) { 511 if (!(value instanceof Comparison) || value == null) 512 return; 513 IObjective objective = getObjectiveForGenerator (row); 514 if (objective == null) 515 return; 516 objective.setAttribute (ATTRIBUTE_COMPARISONTYPE, value.toString ()); 517 model.fireTableDataChanged (); 518 return; 519 } 520 super.setValueAt (value, row, column); 521 } 522 } 523 524 /** 525 * Cell renderer for a ObjectiveSummaryView. 526 */ 527 528 protected class ObjectiveSeriesRenderer extends BasicTable.BasicRenderer { 529 530 /** 531 * Whether to center a text label 532 */ 533 534 protected boolean centerTextLabels; 535 536 /** 537 * Creates a new view renderer. 538 * 539 * @param centerTextLabels Whether to center text labels 540 */ 541 542 public ObjectiveSeriesRenderer (boolean centerTextLabels) { 543 super (ObjectiveSeriesView.this); 544 this.centerTextLabels = centerTextLabels; 545 } 546 547 public Component getTableCellRendererComponent (JTable table, Object value, boolean selected, boolean focus, int row, int column) { 548 Component cell = super.getTableCellRendererComponent (table, value, selected, focus, row, column); 549 if (centerTextLabels) { 550 JLabel label = null; 551 if (cell instanceof JLabel) 552 label = (JLabel) cell; 553 else if (cell instanceof JComboBox) { 554 ListCellRenderer renderer = ((JComboBox) cell).getRenderer (); 555 if (renderer instanceof JLabel) 556 label = (JLabel) renderer; 557 } 558 if (label != null) 559 label.setHorizontalAlignment (SwingConstants.CENTER); 560 } 561 if (selected || model.getValueAt (row, model.findColumn (model.COLUMN_OBJECTIVE)) == VALUE_NOVALUE) 562 return cell; 563 int valueColumn = model.findColumn (model.COLUMN_OBJECTIVEVALUE); 564 int viewValueColumn = table.convertColumnIndexToView (valueColumn); 565 try { 566 String entry = (String) model.getValueAt (row, valueColumn); 567 if (entry == VALUE_NOVALUE || entry == VALUE_NOTEVALUATED) { 568 if (column == viewValueColumn) 569 cell.setBackground (getColor ("ObjectiveSeriesView.backgroundUnknownThreshold")); 570 return cell; 571 } 572 Comparison type = (Comparison) model.getValueAt (row, model.findColumn (model.COLUMN_COMPARISONTYPE)); 573 if (type == Comparison.IGNORE) 574 return cell; 575 double objective = Double.parseDouble (entry); 576 if (Double.isNaN (objective) || Double.isInfinite (objective)) { 577 cell.setBackground (getColor ("ObjectiveSeriesView.backgroundOverThreshold")); 578 return cell; 579 } 580 if (!type.testAcceptable (objective, type == Comparison.EQUIVALENT ? 0.0 : 581 SparseTreeDataElement.createElementSafe ((String) model.getValueAt (row, 582 model.findColumn (model.COLUMN_THRESHOLD))).getRealValue ())) 583 cell.setBackground (getColor ("ObjectiveSeriesView.backgroundOverThreshold")); 584 return cell; 585 } catch (Exception e) { 586 if (column == viewValueColumn) 587 cell.setBackground (getColor ("ObjectiveSeriesView.backgroundUnknownThreshold")); 588 Compare.assertion ("Unable to compute cell color.", e); 589 } 590 return cell; 591 } 592 593 /** 594 * {@inheritDoc} 595 */ 596 597 public void readConfiguration (String state) { 598 super.readConfiguration (state); 599 putColor ("ObjectiveSeriesView.backgroundOverThreshold", getColorFromConfig (CONFIG_BACKGROUNDOVERTHRESHOLD, 600 DEFAULT_BACKGROUNDOVERTHRESHOLD)); 601 putColor ("ObjectiveSeriesView.backgroundUnknownThreshold", getColorFromConfig (CONFIG_BACKGROUNDUNKNOWNTHRESHOLD, 602 DEFAULT_BACKGROUNDUNKNOWNTHRESHOLD)); 603 } 604 } 605 606 /** 607 * Clears an objective. 608 * 609 * @param objective Objective 610 */ 611 612 protected static void clearObjective (IObjective objective) { 613 if (objective == null) 614 return; 615 Sync sync = objective.getEvaluationLock (); 616 if (!Compare.attemptSync (sync)) 617 return; 618 try { 619 objective.clear (); 620 } finally { 621 sync.release (); 622 } 623 } 624 625 /** 626 * Creates a new table view with the ability to display experimental and objective data. 627 * 628 * @param compare Comparator backend to interface with 629 * @param configMarker Marker for retrieving configuration information from Comparator backend 630 */ 631 632 public ObjectiveSeriesView (Compare compare, String configMarker) { 633 super (compare, configMarker); 634 } 635 636 /** 637 * {@inheritDoc} 638 */ 639 640 public void addRow () { 641 throw new UnsupportedOperationException (); 642 } 643 644 /** 645 * {@inheritDoc} 646 */ 647 648 public void addRows (int count) { 649 throw new UnsupportedOperationException (); 650 } 651 652 /** 653 * {@inheritDoc} 654 */ 655 656 public void clear () { 657 for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) 658 ((IEditableDataGenerator) iterator.next ()).setOption (IObjective.OPTION_OBJECTIVE, null); 659 List list = (List) compare.getResourceMap (Objective.RESOURCE_OBJECTIVES).get (this); 660 if (list != null) 661 list.clear (); 662 model.fireTableDataChanged (); 663 compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT); 664 compare.firePropertyChange (Objective.RESOURCE_OBJECTIVES); 665 } 666 667 /** 668 * {@inheritDoc} 669 */ 670 671 public void clipboardCut () { 672 throw new UnsupportedOperationException (); 673 } 674 675 /** 676 * {@inheritDoc} 677 */ 678 679 public void clipboardPaste () { 680 throw new UnsupportedOperationException (); 681 } 682 683 /** 684 * {@inheritDoc} 685 */ 686 687 public IConfigEditor createConfigEditor () { 688 IConfigEditor editor = new ConfigEditor (compare, this, configMarkers, getConfigForView ()); 689 editor.addOption (CONFIG_TABNAME, "Name", String.class); 690 editor.addOption (CONFIG_RECENTSOURCECOUNT, "File History Size", Integer.class); 691 editor.addOption (CONFIG_PLOTTER, "Plotter", Class.class); 692 editor.addOption (CONFIG_TEXTCUTOFF, "Text Display Cutoff", Integer.class); 693 editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDEDITABLE, "Editable Cell Background Color", Color.class); 694 editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDUNEDITABLE, "Uneditable Cell Background Color", Color.class); 695 editor.addOption (BasicTable.BasicEditor.CONFIG_FOREGROUNDMODIFIED, "Modified Cell Foreground Color", Color.class); 696 editor.addOption (CONFIG_BACKGROUNDUNKNOWNTHRESHOLD, "Not Evaluated Background Color", Color.class); 697 editor.addOption (CONFIG_BACKGROUNDOVERTHRESHOLD, "Flagged Background Color", Color.class); 698 return editor; 699 } 700 701 /** 702 * {@inheritDoc} 703 */ 704 705 public void deleteRow (int row) { 706 ((IEditableDataGenerator) generators.get (row)).setOption (IObjective.OPTION_OBJECTIVE, null); 707 model.fireTableDataChanged (); 708 compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT); 709 } 710 711 /** 712 * {@inheritDoc} 713 */ 714 715 public void deleteRows (int rows []) { 716 if (rows.length == 0) 717 return; 718 Arrays.sort (rows); 719 for (int i = rows.length - 1; i >= 0; i--) 720 ((IEditableDataGenerator) generators.get (rows [i])).setOption (IObjective.OPTION_OBJECTIVE, null); 721 model.fireTableDataChanged (); 722 compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT); 723 } 724 725 /** 726 * {@inheritDoc} 727 */ 728 729 public void evaluate () { 730 evaluate (generators.toArray ()); 731 } 732 733 /** 734 * {@inheritDoc} 735 */ 736 737 public void evaluate (int rows []) { 738 int l = rows.length; 739 IDataGenerator tasks [] = new IDataGenerator [l]; 740 for (int i = 0; i < l; i++) 741 tasks [i] = (IDataGenerator) generators.get (rows [i]); 742 evaluate (tasks); 743 } 744 745 /** 746 * {@inheritDoc} 747 */ 748 749 public void insertRow (int row) { 750 throw new UnsupportedOperationException (); 751 } 752 753 /** 754 * {@inheritDoc} 755 */ 756 757 public void insertRows (int row, int count) { 758 throw new UnsupportedOperationException (); 759 } 760 761 /** 762 * {@inheritDoc} 763 */ 764 765 public void moveRowsDown (int rows []) { 766 throw new UnsupportedOperationException (); 767 } 768 769 /** 770 * {@inheritDoc} 771 */ 772 773 public void moveRowsUp (int rows []) { 774 throw new UnsupportedOperationException (); 775 } 776 777 /** 778 * {@inheritDoc} 779 */ 780 781 public IDataGenerator processGenerator (IDataGenerator generator) { 782 IObjective objective = Objective.getObjectiveForGenerator (generator); 783 if (objective == null) 784 return null; 785 Sync sync = objective.getEvaluationLock (); 786 if (!Compare.attemptSync (sync)) 787 return null; 788 try { 789 objective.setFunction (generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID)); 790 objective.setData (generators); 791 objective.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, IDataGenerator.Option.COPYONLY); 792 objective.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, generator.getName ()); 793 objective.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, IDataGenerator.Option.COPYONLY); 794 objective.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, generator); 795 } finally { 796 sync.release (); 797 } 798 return objective; 799 } 800 801 public void propertyChange (PropertyChangeEvent e) { 802 String name = e.getPropertyName (); 803 if (IDataGenerator.RESOURCE_GENERATORS.equals (name)) { 804 generators.clear (); 805 generators.addAll (createGenerators ()); 806 model.fireTableDataChanged (); 807 } else if (IDataGenerator.PROPERTY_GENERATOR_EDIT.equals (name)) 808 model.fireTableDataChanged (); 809 else if (Objective.RESOURCE_OBJECTIVES.equals (name) || IObjective.PROPERTY_OBJECTIVE_EDIT.equals (name)) { 810 objectives.clear (); 811 objectives.addAll (createObjectives ()); 812 objectives.sort (DataGenerator.COMPARATOR_NAME); 813 objectiveModel.replaceAll (objectives.asList ()); 814 model.fireTableDataChanged (); 815 } else if (DataGeneratorEvaluator.PROPERTY_EVALUATIONUPDATE.equals (name)) 816 model.fireTableDataChanged (); 817 else if (DataGeneratorEvaluator.PROPERTY_EVALUATIONFINISHED.equals (name)) 818 ((DataGeneratorEvaluator) e.getSource ()).removePropertyChangeListener (this); 819 else 820 super.propertyChange (e); 821 } 822 823 /** 824 * {@inheritDoc} 825 */ 826 827 public void reset () { 828 for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) 829 clearObjective (Objective.getObjectiveForGenerator ((IDataGenerator) iterator.next ())); 830 model.fireTableDataChanged (); 831 } 832 833 /** 834 * {@inheritDoc} 835 */ 836 837 public void reset (int rows []) { 838 int l = rows.length; 839 if (l == 0) 840 return; 841 for (int i = 0; i < l; i++) 842 clearObjective (getObjectiveForGenerator (rows [i])); 843 model.fireTableDataChanged (); 844 } 845 846 /** 847 * {@inheritDoc} 848 */ 849 850 public void saveResults (IWriteableDataSource source) { 851 if (source instanceof FileDataSource) { 852 FileDataSource fileSource = (FileDataSource) source; 853 fileSource.setExceptionListenerOption (exception); 854 fileSource.setFileChooserOption (createFileChooserResults ()); 855 fileSource.setFileChooserSelectOption (OPTION_CHOOSERSAVE); 856 } 857 try { 858 if (!source.configure ()) 859 return; 860 saveResultsDirect (source); 861 } catch (Exception e) { 862 compare.shellHandleException (Compare.MESSAGE_ERROR, MESSAGE_SAVEERROR + e.getMessage (), e); 863 } 864 } 865 866 /** 867 * {@inheritDoc} 868 */ 869 870 public void saveResultsDirect (IWriteableDataSource source) { 871 try { 872 writeResults (source); 873 } catch (Exception e) { 874 compare.shellHandleException (Compare.MESSAGE_ERROR, MESSAGE_SAVEERROR + e.getMessage (), e); 875 } finally { 876 if (source instanceof IMultipleDataSource) 877 ((IMultipleDataSource) source).finish (); 878 } 879 } 880 881 /** 882 * {@inheritDoc} 883 */ 884 885 protected JFileChooser createFileChooser () { 886 return InterfaceBuilder.createFileChooser (FILTER_OBJECTIVESET); 887 } 888 889 /** 890 * A file chooser specialized for the view results. 891 */ 892 893 protected JFileChooser createFileChooserResults () { 894 return InterfaceBuilder.createFileChooser (FILTER_OBJECTIVERESULT); 895 } 896 897 /** 898 * {@inheritDoc} 899 */ 900 901 protected IDataGeneratorList createGenerators () { 902 return DataGeneratorList.createList (compare.scanResourceCatalog (IDataGenerator.RESOURCE_GENERATORS)); 903 } 904 905 /** 906 * A list of objectives for the view. 907 */ 908 909 protected List createObjectives () { 910 return compare.scanResourceCatalog (Objective.RESOURCE_OBJECTIVES); 911 } 912 913 /** 914 * {@inheritDoc} 915 */ 916 917 protected void createUI () { 918 createUI (new ObjectiveSeriesModel ()); 919 } 920 921 /** 922 * @see jigcell.compare.views.BasicTableView#createUI(jigcell.compare.ui.BasicTable.BasicTableModel) 923 */ 924 925 protected void createUI (ObjectiveSeriesModel model) { 926 super.createUI (model); 927 this.model = model; 928 table.setDefaultRenderer (Object.class, new ObjectiveSeriesRenderer (false)); 929 objectiveModel = new ListComboBoxModel (objectives.asList ()); 930 TableColumnModel columnModel = table.getColumnModel (); 931 columnModel.getColumn (table.findColumn (model.COLUMN_OBJECTIVE)).setCellEditor (new BasicTable.BasicEditor (this, 932 new JComboBox (objectiveModel))); 933 TableColumn comparisonTypeColumn = columnModel.getColumn (table.findColumn (model.COLUMN_COMPARISONTYPE)); 934 comparisonTypeColumn.setCellEditor (new BasicTable.BasicEditor (this, new JComboBox (new ListComboBoxModel ( 935 Comparison.getTypes ())))); 936 comparisonTypeColumn.setCellRenderer (new ObjectiveSeriesRenderer (true)); 937 } 938 939 /** 940 * Evaluates a collection of data generators on a separate thread. 941 * 942 * @param generators Data generators to evaluate 943 */ 944 945 protected void evaluate (IDataGenerator generators []) { 946 ProgressMonitor progress = new ProgressMonitor (compare.getDisplayFrame (), "Not started", 0, generators.length); 947 DataGeneratorEvaluator evaluator = new DataGeneratorEvaluator (generators, this); 948 evaluator.addPropertyChangeListener (this); 949 evaluator.addPropertyChangeListener (progress); 950 progress.addPropertyChangeListener (evaluator); 951 evaluator.execute (); 952 } 953 954 /** 955 * The objective of a generator. 956 * 957 * @param index Index of generator in generator list 958 */ 959 960 protected IObjective getObjectiveForGenerator (int index) { 961 return Objective.getObjectiveForGenerator ((IDataGenerator) generators.get (index)); 962 } 963 964 /** 965 * {@inheritDoc} 966 */ 967 968 protected void initialize () { 969 super.initialize (); 970 } 971 972 /** 973 * {@inheritDoc} 974 */ 975 976 protected void initializeData () { 977 generators = createGenerators (); 978 objectives = new DataGeneratorList (); 979 } 980 981 /** 982 * {@inheritDoc} 983 */ 984 985 protected void readInternal (Object readResult) throws Exception { 986 Iterator iterator = DataGeneratorMap.createMap (readResult).iterator (); 987 objectives.clear (); 988 HashSet used = new HashSet (); 989 generators.createIndex (); 990 while (iterator.hasNext ()) 991 try { 992 Map.Entry entry = (Map.Entry) iterator.next (); 993 IObjective generator = (IObjective) entry.getValue (); 994 IObjective original = generator.isCopy () ? (IObjective) generator.getCopiedFrom () : generator; 995 if (used.add (original)) 996 objectives.add (original); 997 IDataGeneratorCollection.Key key = (IDataGeneratorCollection.Key) entry.getKey (); 998 IDataGenerator target = generators.get (key); 999 if (target == null) { 1000 compare.shellHandleException (Compare.MESSAGE_WARNING, Compare.formatString ("ObjectiveSeriesView.objectiveTargetWarning", 1001 key)); 1002 continue; 1003 } 1004 target.addOption (IObjective.OPTION_OBJECTIVE, IDataGenerator.Option.COPYONLY); 1005 generator = (IObjective) generator.copy (true); 1006 target.setOption (IObjective.OPTION_OBJECTIVE, generator); 1007 generator.setCopyName (true); 1008 } catch (Exception e) { 1009 compare.shellHandleException (Compare.MESSAGE_WARNING, Compare.getString ("ObjectiveSeriesView.objectiveAttachWarning"), e); 1010 } 1011 compare.updateResourceMap (Objective.RESOURCE_OBJECTIVES, this, ((IDataGeneratorList) objectives.clone ()).asList ()); 1012 compare.firePropertyChange (Objective.RESOURCE_OBJECTIVES); 1013 } 1014 1015 /** 1016 * {@inheritDoc} 1017 */ 1018 1019 protected void readNotify () { 1020 model.fireTableDataChanged (); 1021 compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT); 1022 } 1023 1024 /** 1025 * {@inheritDoc} 1026 */ 1027 1028 protected void write (IWriteableDataSource source) throws Exception { 1029 IDataGeneratorMap map = new DataGeneratorMap (1 + (objectives.size () << 2), 1); 1030 for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) { 1031 IDataGenerator generator = (IDataGenerator) iterator.next (); 1032 IObjective objective = Objective.getObjectiveForGenerator (generator); 1033 if (objective != null) 1034 map.put (generator.getName (), generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID), objective); 1035 } 1036 source.write (map); 1037 } 1038 1039 /** 1040 * Writes results data to some external source. 1041 * 1042 * @param source Data source to write to 1043 */ 1044 1045 protected void writeResults (IWriteableDataSource source) throws Exception { 1046 IResultSetMap map = new ResultSetMap (1 + (objectives.size () << 2), 1); 1047 for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) { 1048 IDataGenerator generator = (IDataGenerator) iterator.next (); 1049 IObjective objective = Objective.getObjectiveForGenerator (generator); 1050 if (objective != null && objective.isCached ()) 1051 map.put (generator.getName (), generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID), objective.getElement ()); 1052 } 1053 source.write (map); 1054 } 1055 }