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.Iterator;
008    import javax.swing.JTable;
009    import jigcell.compare.IConfigEditor;
010    import jigcell.compare.IDataElement;
011    import jigcell.compare.IDataGenerator;
012    import jigcell.compare.ITypeChecker;
013    import jigcell.compare.data.DataElement;
014    import jigcell.compare.data.EditableDataGenerator;
015    import jigcell.compare.data.FlippedDataElement;
016    import jigcell.compare.data.IDataGeneratorList;
017    import jigcell.compare.data.SparseTreeDataElement;
018    import jigcell.compare.data.type.TimeSeriesTypeChecker;
019    import jigcell.compare.data.type.TypeChecker;
020    import jigcell.compare.impl.Compare;
021    import jigcell.compare.impl.DataGeneratorEvaluator;
022    import jigcell.compare.objective.ChainedDataGeneratorList;
023    import jigcell.compare.objective.IObjective;
024    import jigcell.compare.objective.Objective;
025    import jigcell.compare.plotter.IPlotter;
026    import jigcell.compare.plotter.PlotException;
027    import jigcell.compare.plotter.Plotter;
028    import jigcell.compare.transform.ITransform;
029    import jigcell.compare.transform.ITransformContext;
030    import jigcell.compare.transform.Transform;
031    import jigcell.compare.transform.TransformContext;
032    import jigcell.compare.ui.BasicTable;
033    import jigcell.compare.ui.ConfigEditor;
034    import jigcell.compare.ui.ViewerDialog;
035    import jigcell.compare.views.EvaluationErrorViewer;
036    import jigcell.compare.views.ObjectiveSeriesView;
037    
038    /**
039     * An editable display for working with objective data.  References model and experiment data in the system.
040     *
041     * <p>
042     * This code is licensed under the DARPA BioCOMP Open Source License.  See LICENSE for more details.
043     * </p>
044     *
045     * @author Nicholas Allen
046     */
047    
048    public class CellCycleObjectiveView extends ObjectiveSeriesView {
049    
050       /**
051        * Error message when generating a report
052        */
053    
054       protected final static String MESSAGE_REPORTERROR = "Unable to create report: ";
055    
056       /**
057        * Displays errors encountered during evaluation
058        */
059    
060       protected EvaluationErrorViewer errorViewer;
061    
062       /**
063        * Context for performing transform evaluations
064        */
065    
066       protected ITransformContext context;
067    
068       /**
069        * Table model for the data in an MEOSummaryView.
070        */
071    
072       protected class ObjectiveModel extends ObjectiveSeriesModel {
073    
074          /**
075           * Prefix for experimental data
076           */
077    
078          protected final static String PREFIX_EXPERIMENT = "Experiment- ";
079    
080          /**
081           * Prefix for transform data
082           */
083    
084          protected final static String PREFIX_TRANSFORM = "Transform- ";
085    
086          /**
087           * Transform value column name
088           */
089    
090          public final Marker COLUMN_MODELVALUE = new Marker ("ObjectiveModel.transformValue", "Transform Value");
091    
092          /**
093           * Type column name
094           */
095    
096          public final Marker COLUMN_TYPE = new Marker ("ObjectiveModel.type", "Value Type");
097    
098          /**
099           * Creates a new table model.
100           */
101    
102          public ObjectiveModel () {
103             super ();
104             COLUMN_VALUE.setName ("Experiment Value");
105             setColumnMarkers (
106                new Marker [] {
107                COLUMN_NAME, COLUMN_VALUE, COLUMN_MODELVALUE, COLUMN_OBJECTIVE, COLUMN_OBJECTIVEVALUE, COLUMN_COMPARISONTYPE, COLUMN_THRESHOLD,
108                COLUMN_TYPE, COLUMN_COMMENT
109             });
110             setColumnWeights (new double [] {3.0, 2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 1.0, 3.0});
111          }
112    
113          /**
114           * A value in the table.
115           *
116           * @param row Row
117           * @param column Column
118           */
119    
120          public Object getValueAt (int row, int column) {
121             if (column == findColumn (COLUMN_MODELVALUE)) {
122                ITransform transform = Transform.getTransformForGenerator ((IDataGenerator) generators.get (row));
123                return transform == null ? VALUE_NOVALUE :
124                   transform.isCached () ? DataElement.toString (transform.getElement (), true, textCutoff) : VALUE_NOTEVALUATED;
125             }
126             if (column == findColumn (COLUMN_TYPE))
127                return ((IDataGenerator) generators.get (row)).getAttribute (ITypeChecker.ATTRIBUTE_TYPE);
128             return super.getValueAt (row, column);
129          }
130    
131          /**
132           * Starts viewing a cell in the table but does not allow editing.
133           *
134           * @param row Row
135           * @param column Column
136           */
137    
138          public void viewCellAt (int row, int column) {
139             if (column == findColumn (COLUMN_VALUE) || column == findColumn (COLUMN_MODELVALUE)) {
140                IDataGenerator generator = (IDataGenerator) generators.get (row);
141                if (generator.getElement ().isScalar ())
142                   new ViewerDialog (compare, generator.getName (), row, column, model).setVisible (true);
143                else
144                   new CellCycleDataDialog (compare, generator, row, column, model).setVisible (true);
145                return;
146             }
147             super.viewCellAt (row, column);
148          }
149    
150          /**
151           * Plots the data contained in a table cell.
152           *
153           * @param row Row
154           * @param column Column
155           */
156    
157          protected void plotCellAt (int row, int column) throws PlotException {
158             IDataGenerator experiment = (IDataGenerator) generators.get (row);
159             ITransform transform = Transform.getTransformForGenerator (experiment);
160             if (transform == null || !transform.isCached ())
161                throw new PlotException (MESSAGE_PLOTNODATAERROR);
162             IDataElement experimentElement = FlippedDataElement.flip (experiment.getElement ());
163             long experimentCount = experimentElement.getLength () - 1;
164             if (experimentCount == -1)
165                throw new PlotException (MESSAGE_PLOTNODATAERROR);
166             experimentElement = Plotter.splitMultipleSeries (experimentElement);
167             IDataElement transformElement = FlippedDataElement.flip (transform.getElement ());
168             long transformCount = transformElement.getLength () - 1;
169             if (transformCount == -1)
170                throw new PlotException (MESSAGE_PLOTNODATAERROR);
171             transformElement = Plotter.splitMultipleSeries (transformElement);
172             TimeSeriesTypeChecker type = computeTypeForPlot (experiment);
173             plotter.setData (new SparseTreeDataElement ());
174             plotter.setSeriesName (1, type.getName (1));
175             for (int experimentIndex = 1; experimentIndex <= experimentCount; experimentIndex++) {
176                plotter.setSeries (experimentIndex, experimentElement.getListValue (experimentIndex));
177                plotter.setSeriesName (experimentIndex + 1, PREFIX_EXPERIMENT + type.getName (experimentIndex + 1));
178             }
179             for (int transformIndex = 1; transformIndex <= transformCount; transformIndex++) {
180                plotter.setSeries (experimentCount + transformIndex, transformElement.getListValue (transformIndex));
181                plotter.setSeriesName (experimentCount + transformIndex + 1, PREFIX_TRANSFORM + type.getName (transformIndex + 1));
182             }
183             plotter.setSeriesCombine (IPlotter.Combine.NONE);
184             plotter.setTitle (experiment.getName ());
185             plotter.plot ();
186          }
187       }
188    
189       /**
190        * Colors cells when a type error is detected.
191        */
192    
193       protected class ObjectiveViewRenderer extends ObjectiveSeriesRenderer {
194    
195          /**
196           * Creates a new view renderer.
197           *
198           * @param centerTextLabels Whether to center text labels
199           */
200    
201          public ObjectiveViewRenderer (boolean centerTextLabels) {
202             super (centerTextLabels);
203          }
204    
205          public Component getTableCellRendererComponent (JTable table, Object value, boolean selected, boolean focus, int row, int column) {
206             Component cell = super.getTableCellRendererComponent (table, value, selected, focus, row, column);
207             IDataGenerator generator = (IDataGenerator) generators.get (row);
208             ITransform transform = Transform.getTransformForGenerator (generator);
209             IObjective objective = Objective.getObjectiveForGenerator (generator);
210             ITypeChecker checker = TypeChecker.getTypeCheckerForGenerator (generator);
211             ITypeChecker transformChecker = transform == null ? null : transform.getOutputTypeChecker ();
212             ITypeChecker objectiveChecker = objective == null ? null : objective.getInputTypeChecker ();
213             if (!TypeChecker.validate (checker, generator) || !TypeChecker.validate (transformChecker, generator) ||
214                !TypeChecker.validate (objectiveChecker, generator) || !TypeChecker.isCompatible (objectiveChecker, checker) ||
215                !TypeChecker.isCompatible (objectiveChecker, transformChecker))
216                cell.setBackground (getColor ("CellCycleObjectiveView.backgroundTypeError"));
217             return cell;
218          }
219    
220          /**
221           * {@inheritDoc}
222           */
223    
224          public void readConfiguration (String state) {
225             super.readConfiguration (state);
226             putColor ("CellCycleObjectiveView.backgroundTypeError", getColorFromConfig (CellCycleExperimentView.CONFIG_BACKGROUNDTYPEERROR,
227                CellCycleExperimentView.DEFAULT_BACKGROUNDTYPEERROR));
228          }
229       }
230    
231       /**
232        * Creates a new table view with the ability to display objective, model, and experiment data.
233        *
234        * @param compare Comparator backend to interface with
235        * @param configMarker Marker for retrieving configuration information from Comparator backend
236        */
237    
238       public CellCycleObjectiveView (Compare compare, String configMarker) {
239          super (compare, configMarker);
240          setSelectionGroup (CellCycleExperimentView.SELECTIONGROUP_CELLCYCLE);
241          context = new TransformContext ();
242          if (!compare.addResource (CellCycleTransformView.TRANSFORMCONTEXT_CELLCYCLE, context))
243             context = (ITransformContext) compare.getResource (CellCycleTransformView.TRANSFORMCONTEXT_CELLCYCLE);
244          errorViewer = new EvaluationErrorViewer (compare, this);
245          errorViewer.add (context);
246       }
247    
248       /**
249        * {@inheritDoc}
250        */
251    
252       public IConfigEditor createConfigEditor () {
253          IConfigEditor editor = new ConfigEditor (compare, this, configMarkers, getConfigForView ());
254          editor.addOption (CONFIG_TABNAME, "Name", String.class);
255          editor.addOption (CONFIG_RECENTSOURCECOUNT, "File History Size", Integer.class);
256          editor.addOption (CONFIG_PLOTTER, "Plotter", Class.class);
257          editor.addOption (CONFIG_TEXTCUTOFF, "Text Display Cutoff", Integer.class);
258          editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDEDITABLE, "Editable Cell Background Color", Color.class);
259          editor.addOption (BasicTable.BasicRenderer.CONFIG_BACKGROUNDUNEDITABLE, "Uneditable Cell Background Color", Color.class);
260          editor.addOption (BasicTable.BasicEditor.CONFIG_FOREGROUNDMODIFIED, "Modified Cell Foreground Color", Color.class);
261          editor.addOption (CONFIG_BACKGROUNDUNKNOWNTHRESHOLD, "Not Evaluated Background Color", Color.class);
262          editor.addOption (CONFIG_BACKGROUNDOVERTHRESHOLD, "Flagged Background Color", Color.class);
263          editor.addOption (CellCycleExperimentView.CONFIG_BACKGROUNDTYPEERROR, "Type Error Background Color", Color.class);
264          return editor;
265       }
266    
267       /**
268        * Produces a report containing the results of the comparison.
269        */
270    
271       public void generateReport () {
272          CellCycleReportGenerator report = new CellCycleReportGenerator (compare, generators);
273          try {
274             if (!report.configure ())
275                return;
276             report.write (generators);
277          } catch (Exception e) {
278             compare.shellHandleException (Compare.MESSAGE_ERROR, MESSAGE_REPORTERROR + e.getMessage (), e);
279          }
280       }
281    
282       /**
283        * {@inheritDoc}
284        */
285    
286       public IDataGenerator processGenerator (IDataGenerator generator) {
287          IObjective objective = Objective.getObjectiveForGenerator (generator);
288          if (objective == null)
289             return null;
290          Sync sync = objective.getEvaluationLock ();
291          if (!Compare.attemptSync (sync))
292             return null;
293          try {
294             objective.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, IDataGenerator.Option.COPYONLY);
295             objective.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONNAME, generator.getName ());
296             objective.addOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, IDataGenerator.Option.COPYONLY);
297             objective.setOption (DataGeneratorEvaluator.OPTION_EVALUATIONTARGET, generator);
298             IDataGeneratorList data = new ChainedDataGeneratorList (generators);
299             ITransform transform = Transform.getTransformForGenerator (generator);
300             Sync _sync = transform == null ? null : transform.getEvaluationLock ();
301             if (_sync == null || !Compare.attemptSync (_sync)) {
302                objective.setFunction (generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID));
303                objective.setData (data);
304                return objective;
305             }
306             try {
307                transform.setEvaluationContext (context);
308                objective.setFunction (generator.getAttribute (IDataGenerator.ATTRIBUTE_GUID) + EditableDataGenerator.SEPARATOR_PAIR +
309                   transform.getAttribute (IDataGenerator.ATTRIBUTE_GUID));
310                data.add (transform);
311                objective.setData (data);
312             } finally {
313                _sync.release ();
314             }
315             objective.removeEvaluationListener (errorViewer);
316             objective.addEvaluationListener (errorViewer);
317          } finally {
318             sync.release ();
319          }
320          return objective;
321       }
322    
323       public void propertyChange (PropertyChangeEvent e) {
324          String name = e.getPropertyName ();
325          if (IDataGenerator.PROPERTY_GENERATOR_EDIT.equals (name)) {
326             boolean clear = false;
327             for (Iterator iterator = generators.iterator (); iterator.hasNext (); ) {
328                IDataGenerator generator = (IDataGenerator) iterator.next ();
329                IObjective objective = Objective.getObjectiveForGenerator (generator);
330                if (objective == null || !objective.isCached ())
331                   continue;
332                ITransform transform = Transform.getTransformForGenerator (generator);
333                if (transform == null || !transform.isCached ()) {
334                   Sync sync = objective.getEvaluationLock ();
335                   try {
336                      if (!Compare.attemptSync (sync))
337                         continue;
338                      objective.clear ();
339                      clear = true;
340                   } finally {
341                      sync.release ();
342                   }
343                }
344             }
345             model.fireTableDataChanged ();
346             if (clear)
347                compare.firePropertyChange (IDataGenerator.PROPERTY_GENERATOR_EDIT);
348             return;
349          }
350          super.propertyChange (e);
351       }
352    
353       /**
354        * {@inheritDoc}
355        */
356    
357       protected void createUI () {
358          createUI (new ObjectiveModel ());
359       }
360    
361       /**
362        * @see jigcell.compare.views.BasicTableView#createUI(jigcell.compare.ui.BasicTable.BasicTableModel)
363        */
364    
365       protected void createUI (ObjectiveModel model) {
366          super.createUI (model);
367          table.getColumnModel ().getColumn (table.findColumn (model.COLUMN_TYPE)).setCellRenderer (new ObjectiveViewRenderer (false));
368       }
369    }