001    package jigcell.compare.cellcycle;
002    
003    import EDU.oswego.cs.dl.util.concurrent.Sync;
004    import java.awt.Color;
005    import java.awt.Component;
006    import java.beans.PropertyChangeEvent;
007    import java.util.Arrays;
008    import java.util.HashSet;
009    import java.util.Iterator;
010    import java.util.LinkedHashMap;
011    import java.util.List;
012    import java.util.Map;
013    import javax.swing.JComboBox;
014    import javax.swing.JFileChooser;
015    import javax.swing.JTable;
016    import javax.swing.table.TableColumnModel;
017    import jigcell.compare.IConfigEditor;
018    import jigcell.compare.IDataElement;
019    import jigcell.compare.IDataGenerator;
020    import jigcell.compare.IEditableDataGenerator;
021    import jigcell.compare.IMultipleDataSource;
022    import jigcell.compare.ITypeChecker;
023    import jigcell.compare.IWriteableDataSource;
024    import jigcell.compare.data.DataElement;
025    import jigcell.compare.data.DataGenerator;
026    import jigcell.compare.data.DataGeneratorList;
027    import jigcell.compare.data.DataGeneratorMap;
028    import jigcell.compare.data.FlippedDataElement;
029    import jigcell.compare.data.IDataGeneratorCollection;
030    import jigcell.compare.data.IDataGeneratorList;
031    import jigcell.compare.data.IDataGeneratorMap;
032    import jigcell.compare.data.SparseTreeDataElement;
033    import jigcell.compare.data.type.TimeSeriesTypeChecker;
034    import jigcell.compare.data.type.TypeChecker;
035    import jigcell.compare.impl.Compare;
036    import jigcell.compare.impl.DataGeneratorEvaluator;
037    import jigcell.compare.impl.FileDataSource;
038    import jigcell.compare.impl.SuffixFileFilter;
039    import jigcell.compare.plotter.IPlotter;
040    import jigcell.compare.plotter.PlotException;
041    import jigcell.compare.plotter.Plotter;
042    import jigcell.compare.transform.ITransform;
043    import jigcell.compare.transform.ITransformContext;
044    import jigcell.compare.transform.Transform;
045    import jigcell.compare.transform.TransformContext;
046    import jigcell.compare.ui.BasicTable;
047    import jigcell.compare.ui.ConfigEditor;
048    import jigcell.compare.ui.IResultTab;
049    import jigcell.compare.ui.InterfaceBuilder;
050    import jigcell.compare.ui.ListComboBoxModel;
051    import jigcell.compare.ui.ProgressMonitor;
052    import jigcell.compare.ui.ViewerDialog;
053    import jigcell.compare.views.EditableSeriesView;
054    import jigcell.compare.views.EvaluationErrorViewer;
055    
056    /**
057     * An editable display for working with model data.
058     *
059     * <p>
060     * This code is licensed under the DARPA BioCOMP Open Source License.  See LICENSE for more details.
061     * </p>
062     *
063     * @author Nicholas Allen
064     */
065    
066    public class CellCycleTransformView extends EditableSeriesView implements IResultTab, DataGeneratorEvaluator.IProcessor {
067    
068       /**
069        * Transform evaluation context for the cellcycle components
070        */
071    
072       public final static String TRANSFORMCONTEXT_CELLCYCLE = "jigcell_cellcycle_transformcontext";
073    
074       /**
075        * Display value for an unevaluated value
076        */
077    
078       protected final static String VALUE_NOTEVALUATED = "Not Evaluated";
079    
080       /**
081        * Display value for a non-existent value
082        */
083    
084       protected final static String VALUE_NOVALUE = "No Value";
085    
086       /**
087        * Error message when load data is invalid
088        */
089    
090       protected final static String MESSAGE_LOADDATAERROR = "Unable to attach transform: ";
091    
092       /**
093        * Error message when load data contains an unbound transform
094        */
095    
096       protected final static String MESSAGE_TARGETNOTFOUNDERROR = "Unable to find experiment: ";
097    
098       /**
099        * File filter for transform files
100        */
101    
102       protected final static SuffixFileFilter FILTER_TRANSFORM = new SuffixFileFilter (".mss", "Transform Set (*.mss)");
103    
104       /**
105        * File filter for transform result set files
106        */
107    
108       protected final static SuffixFileFilter FILTER_TRANSFORMRESULT = new SuffixFileFilter (".trs", "Transform Result Set (*.trs)");
109    
110       /**
111        * Displays errors encountered during evaluation
112        */
113    
114       protected EvaluationErrorViewer errorViewer;
115    
116       /**
117        * List of known transforms
118        */
119    
120       protected IDataGeneratorList transforms;
121    
122       /**
123        * Context for performing transform evaluations
124        */
125    
126       protected ITransformContext context;
127    
128       /**
129        * Display for list of known transforms
130        */
131    
132       protected ListComboBoxModel transformModel;
133    
134       /**
135        * Data model of the generators
136        */
137    
138       protected TransformModel model;
139    
140       /**
141        * Table model for the data in an ModelDataSeriesView.
142        */
143    
144       protected class TransformModel extends EditableSeriesModel {
145    
146          /**
147           * Prefix for experimental data
148           */
149    
150          protected final static String PREFIX_EXPERIMENT = "Experiment- ";
151    
152          /**
153           * Prefix for transform data
154           */
155    
156          protected final static String PREFIX_TRANSFORM = "Transform- ";
157    
158          /**
159           * Error message when plotting a cell with no data
160           */
161    
162          protected final static String MESSAGE_PLOTNODATAERROR = "No data to plot";
163    
164          /**
165           * Transform value column
166           */
167    
168          public final Marker COLUMN_MODELVALUE = new Marker ("TransformModel.transformValue", "Transform Value");
169    
170          /**
171           * Transform column
172           */
173    
174          public final Marker COLUMN_TRANSFORM = new Marker ("TransformModel.transform", "Transform");
175    
176          /**
177           * Type column
178           */
179    
180          public final Marker COLUMN_TYPE = new Marker ("TransformModel.type", "Value Type");
181    
182          /**
183           * Creates a new table model.
184           */
185    
186          public TransformModel () {
187             super ();
188             COLUMN_VALUE.setName ("Experiment Value");
189             setColumnMarkers (new Marker [] {COLUMN_NAME, COLUMN_VALUE, COLUMN_TRANSFORM, COLUMN_MODELVALUE, COLUMN_TYPE, COLUMN_COMMENT});
190             setColumnWeights (new double [] {3.0, 2.0, 3.0, 2.0, 1.0, 3.0});
191          }
192    
193          /**
194           * Starts editing a cell in the table.
195           *
196           * @param row Row
197           * @param column Column
198           */
199    
200          public void editCellAt (int row, int column) {
201             if (!isCellEditable (row, column))
202                return;
203             if (column == findColumn (COLUMN_TRANSFORM)) {
204                setValueAt (manager.showInputDialog ("Choose a Transform", transforms.toArray (), getValueAt (row, column), "Set"), row, column);
205                return;
206             }
207             super.editCellAt (row, column);
208          }
209    
210          /**
211           * Fills along a column.
212           *
213           * @param row Row
214           * @param column Column
215           * @param startRow First row
216           * @param endRow Last row
217           */
218    
219          public void fillRangeAt (int row, int column, int startRow, int endRow) {
220             if (column == findColumn (COLUMN_TRANSFORM)) {
221                fillRange (column, startRow, endRow, getTransformForGenerator (row));
222                return;
223             }
224             super.fillRangeAt (row, column, startRow, endRow);
225          }
226    
227          /**
228           * A value in the table.
229           *
230           * @param row Row
231           * @param column Column
232           */
233    
234          public Object getValueAt (int row, int column) {
235             if (column == findColumn (COLUMN_MODELVALUE)) {
236                ITransform transform = getTransformForGenerator (row);
237                return transform == null ? VALUE_NOVALUE :
238                   transform.isCached () ? DataElement.toString (transform.getElement (), true, textCutoff) : VALUE_NOTEVALUATED;
239             }
240             if (column == findColumn (COLUMN_TRANSFORM)) {
241                ITransform transform = getTransformForGenerator (row);
242                return transform == null ? (Object) VALUE_NOVALUE : transform;
243             }
244             if (column == findColumn (COLUMN_TYPE))
245                return ((IDataGenerator) generators.get (row)).getAttribute (ITypeChecker.ATTRIBUTE_TYPE);
246             return super.getValueAt (row, column);
247          }
248    
249          /**
250           * Whether a value in the table is editable.
251           *
252           * @param row Row
253           * @param column Column
254           */
255    
256          public boolean isCellEditable (int row, int column) {
257             return row >= 0 && row < getRowCount () && generators.get (row) instanceof IEditableDataGenerator &&
258                (column == findColumn (COLUMN_COMMENT) || column == findColumn (COLUMN_TRANSFORM));
259          }
260    
261          /**
262           * Sets a value in the table.
263           *
264           * @param value Value
265           * @param row Row
266           * @param column Column
267           */
268    
269          public void setValueAt (Object value, int row, int column) {
270             if (!isCellEditable (row, column))
271                return;
272             if (column == findColumn (COLUMN_TRANSFORM)) {
273                if (value == null || !(value instanceof ITransform))
274                   return;
275                IEditableDataGenerator generator = (IEditableDataGenerator) generators.get (row);
276                generator.addOption (ITransform.OPTION_TRANSFORM, IDataGenerator.Option.COPYONLY);
277                generator.setOption (ITransform.OPTION_TRANSFORM, (ITransform) value);
278                model.fireTableDataChanged ();
279                return;
280             }
281             super.setValueAt (value, row, column);
282          }
283    
284          /**
285           * Starts viewing a cell in the table but does not allow editing.
286           *
287           * @param row Row
288           * @param column Column
289           */
290    
291          public void viewCellAt (int row, int column) {
292             if (column == findColumn (COLUMN_VALUE) || column == findColumn (COLUMN_MODELVALUE)) {
293                IDataGenerator generator = (IDataGenerator) generators.get (row);
294                if (generator.getElement ().isScalar ())
295                   new ViewerDialog (compare, generator.getName (), row, column, model).setVisible (true);
296                else
297                   new CellCycleDataDialog (compare, generator, row, column, model).setVisible (true);
298                return;
299             }
300             super.viewCellAt (row, column);
301          }
302    
303          /**
304           * Plots the data contained in a table cell.
305           *
306           * @param row Row
307           * @param column Column
308           */
309    
310          protected void plotCellAt (int row, int column) throws PlotException {
311             IDataGenerator experiment = (IDataGenerator) generators.get (row);
312             ITransform transform = Transform.getTransformForGenerator (experiment);
313             if (transform == null || !transform.isCached ())
314                throw new PlotException (MESSAGE_PLOTNODATAERROR);
315             IDataElement experimentElement = FlippedDataElement.flip (experiment.getElement ());
316             long experimentCount = experimentElement.getLength () - 1;
317             if (experimentCount == -1)
318                throw new PlotException (MESSAGE_PLOTNODATAERROR);
319             experimentElement = Plotter.splitMultipleSeries (experimentElement);
320             IDataElement transformElement = FlippedDataElement.flip (transform.getElement ());
321             long transformCount = transformElement.getLength () - 1;
322             if (transformCount == -1)
323                throw new PlotException (MESSAGE_PLOTNODATAERROR);
324             transformElement = Plotter.splitMultipleSeries (transformElement);
325             TimeSeriesTypeChecker type = computeTypeForPlot (experiment);
326             plotter.setData (new SparseTreeDataElement ());
327             plotter.setSeriesName (1, type.getName (1));
328             for (int experimentIndex = 1; experimentIndex <= experimentCount; experimentIndex++) {
329                plotter.setSeries (experimentIndex, experimentElement.getListValue (experimentIndex));
330                plotter.setSeriesName (experimentIndex + 1, PREFIX_EXPERIMENT + type.getName (experimentIndex + 1));
331             }
332             for (int transformIndex = 1; transformIndex <= transformCount; transformIndex++) {
333                plotter.setSeries (experimentCount + transformIndex, transformElement.getListValue (transformIndex));
334                plotter.setSeriesName (experimentCount + transformIndex + 1, PREFIX_TRANSFORM + type.getName (transformIndex + 1));
335             }
336             plotter.setSeriesCombine (IPlotter.Combine.NONE);
337             plotter.setTitle (experiment.getName ());
338             plotter.plot ();
339          }
340       }
341    
342       /**
343        * Colors cells when a type error is detected.
344        */
345    
346       protected class TransformViewRenderer extends BasicTable.BasicRenderer {
347    
348          /**
349           * Creates a new view renderer.
350           */
351    
352          public TransformViewRenderer () {
353             super (CellCycleTransformView.this);
354          }
355    
356          public Component getTableCellRendererComponent (JTable table, Object value, boolean selected, boolean focus, int row, int column) {
357             Component cell = super.getTableCellRendererComponent (table, value, selected, focus, row, column);
358             IDataGenerator generator = (IDataGenerator) generators.get (row);
359             ITransform transform = Transform.getTransformForGenerator (generator);
360             ITypeChecker checker = TypeChecker.getTypeCheckerForGenerator (generator);
361             ITypeChecker transformChecker = transform == null ? null : transform.getOutputTypeChecker ();
362             if (!TypeChecker.validate (checker, generator) || !TypeChecker.validate (transformChecker, generator) ||
363                !TypeChecker.isCompatible (transformChecker, checker))
364                cell.setBackground (getColor ("CellCycleTransformView.backgroundTypeError"));
365             return cell;
366          }
367    
368          /**
369           * {@inheritDoc}
370           */
371    
372          public void readConfiguration (String state) {
373             super.readConfiguration (state);
374             putColor ("CellCycleTransformView.backgroundTypeError", getColorFromConfig (CellCycleExperimentView.CONFIG_BACKGROUNDTYPEERROR,
375                CellCycleExperimentView.DEFAULT_BACKGROUNDTYPEERROR));
376          }
377       }
378    
379       /**
380        * Flushes a transform.
381        *
382        * @param transform Transform
383        */
384    
385       protected static void flushTransform (ITransform transform) {
386          if (transform == null)
387             return;
388          Sync sync = transform.getEvaluationLock ();
389          if (!Compare.attemptSync (sync))
390             return;
391          try {
392             transform.flush ();
393          } finally {
394             sync.release ();
395          }
396       }
397    
398       /**
399        * Creates a new table view with the ability to display model and experiment data.
400        *
401        * @param compare Comparator backend to interface with
402        * @param configMarker Marker for retrieving configuration information from Comparator backend
403        */
404    
405       public CellCycleTransformView (Compare compare, String configMarker) {
406          super (compare, configMarker);
407          setSelectionGroup (CellCycleExperimentView.SELECTIONGROUP_CELLCYCLE);
408          context = new TransformContext ();
409          if (!compare.addResource (TRANSFORMCONTEXT_CELLCYCLE, context))
410             context = (ITransformContext) compare.getResource (TRANSFORMCONTEXT_CELLCYCLE);
411          errorViewer = new EvaluationErrorViewer (compare, this);
412          errorViewer.add (context);
413       }
414    
415       /**
416        * {@inheritDoc}
417        */
418    
419       public void addRow () {
420          throw new UnsupportedOperationException ();
421       }
422    
423       /**
424        * {@inheritDoc}
425        */
426    
427       public void addRows (int count) {
428          throw new UnsupportedOperationException ();
429       }
430    
431       /**
432        * {@inheritDoc}
433        */
434    
435       public void clear () {
436          for (Iterator iterator = generators.iterator (); iterator.hasNext (); )
437             ((IEditableDataGenerator) iterator.next ()).setOption (ITransform.OPTION_TRANSFORM, null);
438          List list = (List) compare.getResourceMap (ITransform.RESOURCE_TRANSFORMS).get (this);
439          if (list != null)
440             list.clear ();
441          model.fireTableDataChanged ();
442          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
443          compare.firePropertyChange (ITransform.RESOURCE_TRANSFORMS);
444       }
445    
446       /**
447        * {@inheritDoc}
448        */
449    
450       public void clipboardCut () {
451          throw new UnsupportedOperationException ();
452       }
453    
454       /**
455        * {@inheritDoc}
456        */
457    
458       public void clipboardPaste () {
459          throw new UnsupportedOperationException ();
460       }
461    
462       /**
463        * {@inheritDoc}
464        */
465    
466       public IConfigEditor createConfigEditor () {
467          IConfigEditor editor = new ConfigEditor (compare, this, configMarkers, getConfigForView ());
468          editor.addOption (CONFIG_TABNAME, "Name", String.class);
469          editor.addOption (CONFIG_RECENTSOURCECOUNT, "File History Size", Integer.class);
470          editor.addOption (CONFIG_PLOTTER, "Plotter", Class.class);
471          editor.addOption (CONFIG_TEXTCUTOFF, "Text Display Cutoff", Integer.class);
472          editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDEDITABLE, "Editable Cell Background Color", Color.class);
473          editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDUNEDITABLE, "Uneditable Cell Background Color", Color.class);
474          editor.addOption (BasicTable.BasicEditor.CONFIG_FOREGROUNDMODIFIED, "Modified Cell Foreground Color", Color.class);
475          editor.addOption (CellCycleExperimentView.CONFIG_BACKGROUNDTYPEERROR, "Type Error Background Color", Color.class);
476          return editor;
477       }
478    
479       /**
480        * {@inheritDoc}
481        */
482    
483       public void deleteRow (int row) {
484          ((IEditableDataGenerator) generators.get (row)).setOption (ITransform.OPTION_TRANSFORM, null);
485          model.fireTableDataChanged ();
486          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
487       }
488    
489       /**
490        * {@inheritDoc}
491        */
492    
493       public void deleteRows (int rows []) {
494          if (rows.length == 0)
495             return;
496          Arrays.sort (rows);
497          for (int i = rows.length - 1; i >= 0; i--)
498             ((IEditableDataGenerator) generators.get (rows [i])).setOption (ITransform.OPTION_TRANSFORM, null);
499          model.fireTableDataChanged ();
500          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
501       }
502    
503       /**
504        * {@inheritDoc}
505        */
506    
507       public void evaluate () {
508          evaluate (generators.toArray ());
509       }
510    
511       /**
512        * {@inheritDoc}
513        */
514    
515       public void evaluate (int rows []) {
516          int l = rows.length;
517          IDataGenerator tasks [] = new IDataGenerator [l];
518          for (int i = 0; i < l; i++)
519             tasks [i] = (IDataGenerator) generators.get (rows [i]);
520          evaluate (tasks);
521       }
522    
523       /**
524        * {@inheritDoc}
525        */
526    
527       public void insertRow (int row) {
528          throw new UnsupportedOperationException ();
529       }
530    
531       /**
532        * {@inheritDoc}
533        */
534    
535       public void insertRows (int row, int count) {
536          throw new UnsupportedOperationException ();
537       }
538    
539       /**
540        * {@inheritDoc}
541        */
542    
543       public void moveRowsDown (int rows []) {
544          throw new UnsupportedOperationException ();
545       }
546    
547       /**
548        * {@inheritDoc}
549        */
550    
551       public void moveRowsUp (int rows []) {
552          throw new UnsupportedOperationException ();
553       }
554    
555       /**
556        * {@inheritDoc}
557        */
558    
559       public IDataGenerator processGenerator (IDataGenerator generator) {
560          ITransform transform = Transform.getTransformForGenerator (generator);
561          if (transform == null)
562             return null;
563          Sync sync = transform.getEvaluationLock ();
564          if (!Compare.attemptSync (sync))
565             return null;
566          try {
567             transform.setEvaluationContext (context);
568             transform.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, IDataGenerator.Option.COPYONLY);
569             transform.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, generator.getName ());
570             transform.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, IDataGenerator.Option.COPYONLY);
571             transform.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, generator);
572          } finally {
573             sync.release ();
574          }
575          return transform;
576       }
577    
578       public void propertyChange (PropertyChangeEvent e) {
579          String name = e.getPropertyName ();
580          if (IDataGenerator.RESOURCE_GENERATORS.equals (name)) {
581             generators.clear ();
582             generators.addAll (createGenerators ());
583             model.fireTableDataChanged ();
584          } else if (IDataGenerator.PROPERTY_GENERATOR_EDIT.equals (name))
585             model.fireTableDataChanged ();
586          else if (ITransform.RESOURCE_TRANSFORMS.equals (name) || ITransform.PROPERTY_TRANSFORM_EDIT.equals (name)) {
587             transforms.clear ();
588             transforms.addAll (createTransforms ());
589             transforms.sort (DataGenerator.COMPARATOR_NAME);
590             transformModel.replaceAll (transforms.asList ());
591             for (Iterator iterator = transforms.iterator (); iterator.hasNext (); ) {
592                ITransform transform = (ITransform) iterator.next ();
593                if (transform.getEvaluationContext () != context)
594                   transform.setEvaluationContext (context);
595             }
596             model.fireTableDataChanged ();
597             compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
598          } else if (DataGeneratorEvaluator.PROPERTY_EVALUATIONUPDATE.equals (name))
599             compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
600          else if (DataGeneratorEvaluator.PROPERTY_EVALUATIONFINISHED.equals (name))
601             ((DataGeneratorEvaluator) e.getSource ()).removePropertyChangeListener (this);
602          else
603             super.propertyChange (e);
604       }
605    
606       /**
607        * {@inheritDoc}
608        */
609    
610       public void readConfiguration (String state) {
611          super.readConfiguration (state);
612          if (state == STATE_INITIALIZE)
613             JigCellRunManagerTransform.initializeSimulators (compare.getConfig ());
614       }
615    
616       /**
617        * {@inheritDoc}
618        */
619    
620       public void reset () {
621          for (Iterator iterator = generators.iterator (); iterator.hasNext (); )
622             flushTransform (Transform.getTransformForGenerator ((IDataGenerator) iterator.next ()));
623          model.fireTableDataChanged ();
624          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
625       }
626    
627       /**
628        * {@inheritDoc}
629        */
630    
631       public void reset (int rows []) {
632          int l = rows.length;
633          if (l == 0)
634             return;
635          for (int i = 0; i < l; i++)
636             flushTransform (getTransformForGenerator (rows [i]));
637          model.fireTableDataChanged ();
638          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
639       }
640    
641       /**
642        * {@inheritDoc}
643        */
644    
645       public void saveResults (IWriteableDataSource source) {
646          if (source instanceof FileDataSource) {
647             FileDataSource fileSource = (FileDataSource) source;
648             fileSource.setExceptionListenerOption (exception);
649             fileSource.setFileChooserOption (createFileChooserResults ());
650             fileSource.setFileChooserSelectOption (OPTION_CHOOSERSAVE);
651          }
652          try {
653             if (!source.configure ())
654                return;
655             saveResultsDirect (source);
656          } catch (Exception e) {
657             compare.shellHandleException (Compare.MESSAGE_ERROR, MESSAGE_SAVEERROR + e.getMessage (), e);
658          }
659       }
660    
661       /**
662        * {@inheritDoc}
663        */
664    
665       public void saveResultsDirect (IWriteableDataSource source) {
666          try {
667             writeResults (source);
668          } catch (Exception e) {
669             compare.shellHandleException (Compare.MESSAGE_ERROR, MESSAGE_SAVEERROR + e.getMessage (), e);
670          } finally {
671             if (source instanceof IMultipleDataSource)
672                ((IMultipleDataSource) source).finish ();
673          }
674       }
675    
676       /**
677        * {@inheritDoc}
678        */
679    
680       protected JFileChooser createFileChooser () {
681          return InterfaceBuilder.createFileChooser (FILTER_TRANSFORM);
682       }
683    
684       /**
685        * A file chooser specialized for the view results.
686        */
687    
688       protected JFileChooser createFileChooserResults () {
689          return InterfaceBuilder.createFileChooser (FILTER_TRANSFORMRESULT);
690       }
691    
692       /**
693        * {@inheritDoc}
694        */
695    
696       protected IDataGeneratorList createGenerators () {
697          return DataGeneratorList.createList (compare.scanResourceCatalog (IDataGenerator.RESOURCE_GENERATORS));
698       }
699    
700       /**
701        * A list of transforms for the view.
702        */
703    
704       protected List createTransforms () {
705          return compare.scanResourceCatalog (ITransform.RESOURCE_TRANSFORMS);
706       }
707    
708       /**
709        * {@inheritDoc}
710        */
711    
712       protected void createUI () {
713          createUI (new TransformModel ());
714       }
715    
716       /**
717        * @see jigcell.compare.views.BasicTableView#createUI(jigcell.compare.ui.BasicTable.BasicTableModel)
718        */
719    
720       protected void createUI (TransformModel model) {
721          super.createUI (model);
722          this.model = model;
723          transformModel = new ListComboBoxModel (transforms.asList ());
724          TableColumnModel columnModel = table.getColumnModel ();
725          columnModel.getColumn (table.findColumn (model.COLUMN_TRANSFORM)).setCellEditor (new BasicTable.BasicEditor (this,
726             new JComboBox (transformModel)));
727          columnModel.getColumn (table.findColumn (model.COLUMN_TYPE)).setCellRenderer (new TransformViewRenderer ());
728       }
729    
730       /**
731        * Evaluates a collection of data generators on a separate thread.
732        *
733        * @param generators Data generators to evaluate
734        */
735    
736       protected void evaluate (IDataGenerator generators []) {
737          ProgressMonitor progress = new ProgressMonitor (compare.getDisplayFrame (), "Not started", 0, generators.length);
738          DataGeneratorEvaluator evaluator = new DataGeneratorEvaluator (generators, this);
739          evaluator.addPropertyChangeListener (this);
740          evaluator.addPropertyChangeListener (progress);
741          progress.addPropertyChangeListener (evaluator);
742          evaluator.execute ();
743       }
744    
745       /**
746        * The transform of a generator.
747        *
748        * @param index Index of generator in generator list
749        */
750    
751       protected ITransform getTransformForGenerator (int index) {
752          return Transform.getTransformForGenerator ((IDataGenerator) generators.get (index));
753       }
754    
755       /**
756        * {@inheritDoc}
757        */
758    
759       protected void initializeData () {
760          generators = createGenerators ();
761          transforms = new DataGeneratorList ();
762       }
763    
764       /**
765        * {@inheritDoc}
766        */
767    
768       protected void readInternal (Object readResult) throws Exception {
769          Iterator iterator = DataGeneratorMap.createMap (readResult).iterator ();
770          transforms.clear ();
771          HashSet used = new HashSet ();
772          generators.createIndex ();
773          try {
774             while (iterator.hasNext ())
775                try {
776                   Map.Entry entry = (Map.Entry) iterator.next ();
777                   ITransform transform = (ITransform) entry.getValue ();
778                   ITransform original = transform.isCopy () ? (ITransform) transform.getCopiedFrom () : transform;
779                   if (used.add (original))
780                      transforms.add (original);
781                   IDataGeneratorCollection.Key key = (IDataGeneratorCollection.Key) entry.getKey ();
782                   IDataGenerator target = generators.get (key);
783                   if (target == null) {
784                      compare.shellHandleException (Compare.MESSAGE_WARNING, MESSAGE_TARGETNOTFOUNDERROR + key);
785                      continue;
786                   }
787                   target.addOption (ITransform.OPTION_TRANSFORM, IDataGenerator.Option.COPYONLY);
788                   target.setOption (ITransform.OPTION_TRANSFORM, original);
789                } catch (Exception e) {
790                   compare.shellHandleException (Compare.MESSAGE_WARNING, MESSAGE_LOADDATAERROR + e.getMessage (), e);
791                }
792          } finally {
793             generators.flushIndex ();
794          }
795          compare.updateResourceMap (ITransform.RESOURCE_TRANSFORMS, this, ((IDataGeneratorList) transforms.clone ()).asList ());
796          compare.firePropertyChange (ITransform.RESOURCE_TRANSFORMS);
797       }
798    
799       /**
800        * {@inheritDoc}
801        */
802    
803       protected void readNotify () {
804          model.fireTableDataChanged ();
805          compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
806       }
807    
808       /**
809        * {@inheritDoc}
810        */
811    
812       protected void write (IWriteableDataSource source) throws Exception {
813          IDataGeneratorMap map = new DataGeneratorMap (1 + (transforms.size () << 2), 1);
814          for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) {
815             IDataGenerator generator = (IDataGenerator) iterator.next ();
816             ITransform transform = Transform.getTransformForGenerator (generator);
817             if (transform != null)
818                map.put (generator.getName (), generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID), transform);
819          }
820          source.write (map);
821       }
822    
823       /**
824        * Writes results data to some external source.
825        *
826        * @param source Data source to write to
827        */
828    
829       protected void writeResults (IWriteableDataSource source) throws Exception {
830          Map map = new LinkedHashMap (1 + (transforms.size () << 2), 1);
831          for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) {
832             IDataGenerator generator = (IDataGenerator) iterator.next ();
833             ITransform transform = Transform.getTransformForGenerator (generator);
834             if (transform != null && transform.isCached ())
835                map.put (generator.getName (), String.valueOf (transform.getElement ()));
836          }
837          source.write (map);
838       }
839    }