You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ctakes.apache.org by se...@apache.org on 2015/02/19 19:06:17 UTC

svn commit: r1660963 [10/19] - in /ctakes/sandbox/timelanes: META-INF/ edu/ edu/mayo/ edu/mayo/bmi/ edu/mayo/bmi/annotation/ edu/mayo/bmi/annotation/knowtator/ org/ org/chboston/ org/chboston/cnlp/ org/chboston/cnlp/anafora/ org/chboston/cnlp/anafora/a...

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/TlinkComparator.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/TlinkComparator.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/TlinkComparator.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/TlinkComparator.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,92 @@
+package org.chboston.cnlp.timeline.gui.event;
+
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationSpanComparator;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationTextComparator;
+import org.chboston.cnlp.nlp.annotation.attribute.Attribute;
+import org.chboston.cnlp.nlp.annotation.attribute.DefinedAttributeType;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+
+import java.util.Comparator;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 7/8/14
+ */
+public enum TlinkComparator implements Comparator<Relation> {
+   INSTANCE;
+
+   static public TlinkComparator getInstance() {
+      return INSTANCE;
+   }
+
+   public int compare( final Relation tlink1, final Relation tlink2 ) {
+      if ( !tlink1.getFirstEntity().equals( tlink2.getFirstEntity() )
+           && !tlink1.getSecondEntity().equals( tlink2.getSecondEntity() ) ) {
+         return AnnotationSpanComparator.getInstance().compare( tlink1, tlink2 );
+      }
+      final Attribute tlink1Attribute = tlink1.getAttribute( DefinedAttributeType.RELATION_TYPE.getName() );
+      final Attribute tlink2Attribute = tlink2.getAttribute( DefinedAttributeType.RELATION_TYPE.getName() );
+      if ( tlink1Attribute == null ) {
+         if ( tlink2Attribute == null ) {
+            return 0;
+         }
+         return -1;
+      } else if ( tlink2Attribute == null ) {
+         return 1;
+      }
+      // There is currently no default relation type in the thyme schema, but we must have one, so use overlap
+      final String tlinkType1 = tlink1Attribute.getValue();
+      final String tlinkType2 = tlink2Attribute.getValue();
+      if ( tlinkType1.equals( tlinkType2 ) ) {
+         // Sort alphabetically
+         return alphaSort( tlink1, tlink2 );
+      }
+      if ( tlinkType1.equals( "BEFORE" ) ) {
+         return -1;
+      } else if ( tlinkType1.equals( "ENDS-ON" ) ) {
+         if ( tlinkType2.equals( "BEFORE" ) ) {
+            return 1;
+         }
+         return -1;
+      } else if ( tlinkType1.equals( "CONTAINED-BY" ) ) {
+         if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" ) ) {
+            return 1;
+         }
+         return -1;
+      } else if ( tlinkType1.equals( "CONTAINS" ) ) {
+         if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" ) || tlinkType2.equals( "CONTAINED-BY" ) ) {
+            return 1;
+         }
+         return -1;
+      } else if ( tlinkType1.equals( "OVERLAP" ) ) {
+         if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" )
+              || tlinkType2.equals( "CONTAINED-BY" ) || tlinkType2.equals( "CONTAINS" ) ) {
+            return 1;
+         }
+         return -1;
+      } else if ( tlinkType1.equals( "BEGINS-ON" ) ) {
+         if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" )
+              || tlinkType2.equals( "CONTAINED-BY" ) || tlinkType2.equals( "CONTAINS" )
+              || tlinkType2.equals( "OVERLAP" ) ) {
+            return 1;
+         }
+         return -1;
+      } else if ( tlinkType1.equals( "AFTER" ) ) {
+         return 1;
+      }
+      return alphaSort( tlink1, tlink2 );
+   }
+
+   static private int alphaSort( final Relation tlink1, final Relation tlink2 ) {
+      // Sort alphabetically
+      if ( tlink1.getFirstEntity().equals( tlink2.getFirstEntity() ) ) {
+         return AnnotationTextComparator.getInstance().compare( tlink1.getSecondEntity(),
+               tlink2.getSecondEntity() );
+      } else if ( tlink1.getSecondEntity().equals( tlink2.getSecondEntity() ) ) {
+         return AnnotationTextComparator.getInstance().compare( tlink1.getFirstEntity(),
+               tlink2.getFirstEntity() );
+      }
+      return 0;
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListElement.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListElement.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListElement.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListElement.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,81 @@
+package org.chboston.cnlp.timeline.gui.event.list;
+
+import org.chboston.cnlp.nlp.annotation.classtype.SemanticClassType;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.Collection;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/26/13
+ */
+public class EventListElement {
+
+   private final PointedTimeSpan _timeSpan;
+   private final Entity _entity;
+   private final Collection<Relation> _eventEvents;
+   private final SemanticClassType _semanticType;
+   private final Collection<String> _textSelections;
+   private final boolean _isFirstElement;
+
+   public EventListElement( final PointedTimeSpan timeSpan,
+                            final Entity entity,
+                            final Collection<Relation> eventEvents,
+                            final SemanticClassType semanticClass,
+                            final Collection<String> selectionTexts,
+                            final boolean isFirst ) {
+      _timeSpan = timeSpan;
+      _entity = entity;
+      _eventEvents = eventEvents;
+      _semanticType = semanticClass;
+      _textSelections = selectionTexts;
+      _isFirstElement = isFirst;
+   }
+
+   /**
+    * @return TimeSpanPlus
+    */
+   public PointedTimeSpan getTimeSpan() {
+      return _timeSpan;
+   }
+
+   /**
+    * @return entity
+    */
+   public Entity getEntity() {
+      return _entity;
+   }
+
+   /**
+    * @return events that are related to the primary entity / event
+    */
+   public Collection<Relation> getEventEvents() {
+      return _eventEvents;
+   }
+
+   /**
+    * @return semanticClassType
+    */
+   public SemanticClassType getSemanticType() {
+      return _semanticType;
+   }
+
+   /**
+    * @return textSelections
+    */
+   public Collection<String> getTextSelections() {
+      return _textSelections;
+   }
+
+   /**
+    * @return isFirstElement
+    */
+   public boolean getIsFirstElement() {
+      return _isFirstElement;
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListModel.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListModel.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListModel.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListModel.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,163 @@
+package org.chboston.cnlp.timeline.gui.event.list;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationTextComparator;
+import org.chboston.cnlp.nlp.annotation.classtype.SemanticClassType;
+import org.chboston.cnlp.nlp.annotation.classtype.TemporalClassType;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.gui.timespan.selection.DefaultTimeSpanSelectionModel;
+import org.chboston.cnlp.timeline.gui.timespan.selection.TimeSpanSelectionEvent;
+import org.chboston.cnlp.timeline.gui.timespan.selection.TimeSpanSelectionListener;
+import org.chboston.cnlp.timeline.gui.timespan.selection.TimeSpanSelectionModel;
+import org.chboston.cnlp.timeline.timeline.Timeline;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.TimeSpanPlusComparator;
+
+import javax.swing.*;
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/23/13
+ */
+public class EventListModel extends AbstractListModel<EventListElement> {
+
+   private final TimeSpanSelectionListener _selectionListener;
+   private TimeSpanSelectionModel _selectionModel;
+   private Timeline _timeline;
+   private final List<EventListElement> _elements;
+
+   private Comparator<Annotation> _eventComparator;
+   private TimeSpanSelectionEvent _previousEvent;
+
+   public EventListModel( final Timeline timeline ) {
+      _timeline = timeline;
+      _elements = new ArrayList<>();
+      _eventComparator = AnnotationTextComparator.getInstance();
+      _selectionListener = new PrivateSelectionListener();
+      setSelectionModel( new DefaultTimeSpanSelectionModel() );
+   }
+
+   public void setTimeline( final Timeline timeline ) {
+      _timeline = timeline;
+   }
+
+   public void setEventComparator( final Comparator<Annotation> comparator ) {
+      _eventComparator = comparator;
+      if ( _previousEvent != null ) {
+         selectTimeSpans( _previousEvent );
+      }
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int getSize() {
+      return _elements.size();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EventListElement getElementAt( final int index ) {
+      return _elements.get( index );
+   }
+
+   /**
+    * Sets the TimeSpan selection model for this OldJTimeline to <code>newModel</code>
+    * and registers for listener notifications from the new selection model.
+    *
+    * @param newModel the new selection model
+    * @throws IllegalArgumentException if <code>newModel</code> is <code>null</code>
+    * @see #getSelectionModel
+    */
+   public void setSelectionModel( final TimeSpanSelectionModel newModel ) {
+      if ( newModel == null ) {
+         throw new IllegalArgumentException( "Cannot set a null SelectionModel" );
+      }
+      if ( newModel.equals( _selectionModel ) ) {
+         return;
+      }
+      if ( _selectionModel != null ) {
+         _selectionModel.removeSelectionListener( _selectionListener );
+      }
+//      final TimeSpanSelectionModel oldModel = _selectionModel;
+      _selectionModel = newModel;
+      _selectionModel.addSelectionListener( _selectionListener );
+      // TODO - do we actually need this setSelectionModel method
+      //      firePropertyChange( SELECTION_MODEL_PROPERTY, oldModel, newModel );
+      //      repaint();
+      //      fireIntervalRemoved(  );
+   }
+
+   /**
+    * @return the object that provides TimeSpan selection state, <code>null</code>
+    * if selection is not allowed
+    * @see #setSelectionModel
+    */
+   public TimeSpanSelectionModel getSelectionModel() {
+      return _selectionModel;
+   }
+
+//   public Collection<TimeSpanPlus> getSelectedTimeSpans() {
+//      final TimeSpanSelectionModel selectionModel = getSelectionModel();
+//      return selectionModel.getSelectedEntities().keySet();
+//   }
+//
+//   public TimeSpanSelectionListener getSelectionListener() {
+//      return _selectionListener;
+//   }
+
+   private void selectTimeSpans( final TimeSpanSelectionEvent event ) {
+      _previousEvent = event;
+      final int oldSize = getSize();
+      _elements.clear();
+      SemanticClassType semanticType = event.getSemanticType();
+      final Object source = event.getSource();
+      if ( source instanceof TimeSpanSelectionModel ) {
+         // Override with the semantic type of the original source
+         semanticType = ((TimeSpanSelectionModel)source).getSemanticType();
+      }
+      final Collection<String> selectionTexts = event.getSelectionTexts();
+      final Map<PointedTimeSpan, Collection<Entity>> selectedEntities = event.getSelectedEntities();
+      final java.util.List<PointedTimeSpan> timeSpanList = new ArrayList<>( selectedEntities.keySet() );
+      Collections.sort( timeSpanList, TimeSpanPlusComparator.getInstance() );
+      for ( PointedTimeSpan timeSpan : timeSpanList ) {
+         boolean isFirst = true;
+         final List<Entity> entities = new ArrayList<>( selectedEntities.get( timeSpan ) );
+         Collections.sort( entities, _eventComparator );
+         for ( Entity entity : entities ) {
+            if ( entity.isClassType( TemporalClassType.TIMEX ) || entity.isClassType( TemporalClassType.DOCTIME ) ) {
+               continue;
+            }
+            final Collection<Relation> eventEventRelations = _timeline.getEntityEntityRelations( entity );
+            final EventListElement element = new EventListElement( timeSpan, entity, eventEventRelations,
+                  semanticType, selectionTexts, isFirst );
+            _elements.add( element );
+            isFirst = false;
+         }
+      }
+      if ( oldSize > 0 ) {
+         fireIntervalRemoved( this, 0, oldSize );
+      }
+      fireIntervalAdded( this, 0, getSize() );
+   }
+
+   private class PrivateSelectionListener implements TimeSpanSelectionListener {
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public void valueChanged( final TimeSpanSelectionEvent event ) {
+         if ( event == null || event.getSource() == null || event.getValueIsAdjusting() ) {
+            return;
+         }
+         selectTimeSpans( event );
+      }
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,244 @@
+package org.chboston.cnlp.timeline.gui.event.list;
+
+import org.chboston.cnlp.nlp.annotation.classtype.SemanticClassType;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.gui.event.EventHtmlFactory;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+import java.awt.*;
+import java.util.Collection;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/23/13
+ */
+public class EventListRenderer extends JEditorPane implements ListCellRenderer<EventListElement>, Scrollable {
+
+   private JViewport _viewport;
+   private final StyleSheet _styleSheet;
+
+   public EventListRenderer() {
+      final HTMLEditorKit editorKit = new HTMLEditorKit();
+      setEditorKit( editorKit );
+      setDocument( new HTMLDocument() );
+      _styleSheet = editorKit.getStyleSheet();
+      setEditable( false );
+      setBorder( new EmptyBorder( 2, 10, 2, 10 ) );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Component getListCellRendererComponent( final JList<? extends EventListElement> list,
+                                                  final EventListElement element,
+                                                  final int index,
+                                                  final boolean isSelected, final boolean cellHasFocus ) {
+      if ( list != null ) {
+         if ( list.getParent() instanceof JViewport ) {
+            _viewport = (JViewport)list.getParent();
+         }
+         if ( isSelected ) {
+            setBackground( Color.CYAN );
+         } else {
+            if ( cellHasFocus ) {
+               setBackground( Color.LIGHT_GRAY.brighter() );
+            } else {
+               setBackground( list.getBackground() );
+            }
+         }
+      } else {
+         _viewport = null;
+      }
+      if ( element == null ) {
+         setText( "" );
+         return this;
+      }
+      if ( element.getIsFirstElement() ) {
+         displayEntity( element.getTimeSpan(),
+               element.getEntity(), element.getEventEvents(),
+               element.getSemanticType(), element.getTextSelections() );
+      } else {
+         displayEntity( element.getEntity(), element.getEventEvents(),
+               element.getSemanticType(), element.getTextSelections() );
+      }
+      return this;
+   }
+
+   private void displayEntity( final PointedTimeSpan timeSpan,
+                               final Entity entity, final Collection<Relation> eventEvents,
+                               final SemanticClassType semanticType, final Collection<String> searchTerms ) {
+      final String htmlText = EventHtmlFactory.createEventHtml( timeSpan,
+            entity,
+            eventEvents,
+            semanticType,
+            searchTerms );
+      setText( htmlText );
+   }
+
+   private void displayEntity( final Entity entity, final Collection<Relation> eventEvents,
+                               final SemanticClassType semanticType, final Collection<String> searchTerms ) {
+      final String htmlText = EventHtmlFactory.createEventHtml( entity, eventEvents, semanticType, searchTerms );
+      setText( htmlText );
+   }
+
+   public void setFont( final Font font ) {
+      if ( _styleSheet != null ) {
+         final int size = font.getSize();
+         _styleSheet.setBaseFontSize( size );
+      }
+      super.setFont( font );
+   }
+
+   /**
+    * Normally one doesn't want to mess with getParent(), but in this case getParent() is used to size the JEditorPane.
+    * We could screw around with the flow, axis sizing, scrolling, etc. but in the end it would be a mess
+    * and get the same result as the cell renderer doesn't -really- have a parent anyhow.
+    *
+    * @return the JViewport that contains the JList
+    */
+   @Override
+   public JComponent getParent() {
+      return _viewport;
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void validate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void invalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void repaint() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void revalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( long tm, int x, int y, int width, int height ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( Rectangle r ) {
+   }
+
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, byte oldValue, byte newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, char oldValue, char newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, short oldValue, short newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, int oldValue, int newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, long oldValue, long newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, float oldValue, float newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, double oldValue, double newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, boolean oldValue, boolean newValue ) {
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer2.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer2.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer2.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer2.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,489 @@
+package org.chboston.cnlp.timeline.gui.event.list;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationSpanComparator;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationTextComparator;
+import org.chboston.cnlp.nlp.annotation.attribute.Attribute;
+import org.chboston.cnlp.nlp.annotation.attribute.AttributeUtil;
+import org.chboston.cnlp.nlp.annotation.classtype.SemanticClassType;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.gui.search.TimelineSearchUtil;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+import sun.awt.OrientableFlowLayout;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 9/6/13
+ */
+public class EventListRenderer2 extends JPanel implements ListCellRenderer {
+
+   // THIS DOESN'T WORK
+
+   static private final Color SELECTED_COLOR = Color.CYAN.darker();
+   static private final Color PLAIN_GREEN = new Color( 0x7C, 0xE4, 0x40 ); //Color.GREEN;
+   static private final Color PLAIN_ORANGE = Color.ORANGE;// new Color( 0xD2, 0x76, 0x1A );//Color.ORANGE;
+   static private final Color PLAIN_RED = new Color( 0xEC, 0x45, 0x39 );//Color.RED.brighter().brighter();
+   static private final Color PURPLE = Color.MAGENTA.darker();
+
+   private JViewport _viewport;
+
+   public EventListRenderer2() {
+      super( new OrientableFlowLayout( OrientableFlowLayout.VERTICAL ) );
+      setBorder( new EmptyBorder( 2, 10, 2, 10 ) );
+   }
+
+   @Override
+   public Component getListCellRendererComponent( final JList list, final Object value, final int index,
+                                                  final boolean isSelected, final boolean cellHasFocus ) {
+      removeAll();
+      if ( list != null ) {
+         if ( list.getParent() instanceof JViewport ) {
+            _viewport = (JViewport)list.getParent();
+         }
+         if ( isSelected ) {
+            setBackground( list.getSelectionBackground().brighter().brighter() );
+         } else {
+            if ( cellHasFocus ) {
+               setBackground( Color.LIGHT_GRAY.brighter() );
+            } else {
+               setBackground( list.getBackground() );
+            }
+         }
+      } else {
+         _viewport = null;
+      }
+      if ( value == null || !(value instanceof EventListElement) ) {
+         return this;
+      }
+      final EventListElement element = (EventListElement)value;
+      if ( element.getIsFirstElement() ) {
+         addEventLabels( element.getTimeSpan(),
+               element.getEntity(), element.getEventEvents(),
+               element.getSemanticType(), element.getTextSelections() );
+      } else {
+         addEventLabels( element.getEntity(), element.getEventEvents(),
+               element.getSemanticType(), element.getTextSelections() );
+      }
+      return this;
+   }
+
+
+   /**
+    * Normally one doesn't want to mess with getParent(), but in this case getParent() is used to size the JEditorPane.
+    * We could screw around with the flow, axis sizing, scrolling, etc. but in the end it would be a mess
+    * and get the same result as the cell renderer doesn't -really- have a parent anyhow.
+    *
+    * @return the JViewport that contains the JList
+    */
+   @Override
+   public JComponent getParent() {
+      return _viewport;
+   }
+
+
+   private void addEventLabels( final PointedTimeSpan timeSpan,
+                                final Entity entity, final Collection<Relation> eventEvents,
+                                final SemanticClassType semanticType, final Collection<String> searchTerms ) {
+      final JLabel timeSpanLabel = createTimeSpanLabel( timeSpan );
+      if ( timeSpanLabel != null ) {
+         add( timeSpanLabel );
+      }
+      addEventLabels( entity, eventEvents, semanticType, searchTerms );
+   }
+
+
+   private void addEventLabels( final Entity entity, final Collection<Relation> eventEvents,
+                                final SemanticClassType semanticType, final Collection<String> searchTerms ) {
+      final JLabel eventLabel = createEventLabel( entity, semanticType, searchTerms );
+      add( eventLabel );
+      if ( eventEvents != null && !eventEvents.isEmpty() ) {
+         final Collection<JLabel> eventEventLabels = createEventEventLabels( semanticType, eventEvents, searchTerms );
+         for ( JLabel label : eventEventLabels ) {
+            add( label );
+         }
+      }
+   }
+
+
+   private JLabel createLabel() {
+      final JLabel label = new JLabel();
+      final int fontSize = _viewport.getFont().getSize();
+      label.setFont( label.getFont().deriveFont( (float)fontSize ) );
+      return label;
+   }
+
+
+   private JLabel createTimeSpanLabel( final PointedTimeSpan timeSpan ) {
+      final String dateSpanText = timeSpan.toString();
+      if ( dateSpanText != null && !dateSpanText.isEmpty() ) {
+         final JLabel label = createLabel();
+         label.setFont( label.getFont().deriveFont( Font.BOLD ) );
+         label.setText( dateSpanText );
+         return label;
+      }
+      return null;
+   }
+
+   private JLabel createEventLabel( final Entity entity, final SemanticClassType semanticType,
+                                    final Collection<String> searchTerms ) {
+      final boolean isSearchResult = TimelineSearchUtil.hasSearchTerm( entity.getSpannedText(), searchTerms );
+      final boolean isNegative = AttributeUtil.hasNegativePolarity( entity );
+      final boolean isUncertain = AttributeUtil.hasUncertainty( entity );
+      //      final boolean isModifier = isModifierUmls( entity );
+      //      final boolean isMiscUmls = isMiscUmls( entity );
+      final Color color = getEventColor( isSearchResult, isNegative, isUncertain );
+      final JLabel label = createLabel();
+      label.setForeground( color );
+      final StringBuilder sb = new StringBuilder();
+      sb.append( 249 ).append( ' ' );
+      sb.append( getEventPrefix( isSearchResult, isNegative, isUncertain, true ) );
+      sb.append( getNiceText( entity, semanticType ) );
+      sb.append( getEventSuffix( isSearchResult, isNegative, isUncertain, true ) );
+      label.setText( sb.toString() );
+      return label;
+   }
+
+   private java.util.List<JLabel> createEventEventLabels( final SemanticClassType semanticType,
+                                                          final Collection<Relation> tlinks,
+                                                          final Collection<String> searchTerms ) {
+      final java.util.List<Relation> tlinkList = new ArrayList<>( tlinks );
+      Collections.sort( tlinkList, TlinkComparator.INSTANCE );
+      final java.util.List<JLabel> labels = new ArrayList<>();
+      for ( Relation tlink : tlinkList ) {
+         final String tlinkTypeText = createTlinkTypeText( tlink );
+         if ( tlinkTypeText.isEmpty() ) {
+            continue;
+         }
+         final Entity entity = tlink.getSecondEntity();
+         final JLabel label = createLabel();
+         label.setForeground( PURPLE );
+         final Font font = label.getFont();
+         label.setFont( font.deriveFont( Font.ITALIC ) );
+         final StringBuilder sb = new StringBuilder();
+         sb.append( "    -" ).append( tlinkTypeText ).append( " " );
+         final boolean isSearchResult = TimelineSearchUtil.hasSearchTerm( entity.getSpannedText(), searchTerms );
+         final boolean isNegative = AttributeUtil.hasNegativePolarity( entity );
+         final boolean isUncertain = AttributeUtil.hasUncertainty( entity );
+         sb.append( getEventPrefix( isSearchResult, isNegative, isUncertain, false ) );
+         sb.append( getNiceText( entity, semanticType ) );
+         sb.append( getEventSuffix( isSearchResult, isNegative, isUncertain, true ) );
+         label.setText( sb.toString() );
+         //         if ( isNegative ) {
+         //            sb.append( "(No) " );
+         //         }
+         //         if ( isSearchResult ) {
+         //            sb.append( HTML_TAG.BOLD );
+         //         }
+         //         sb.append( getNiceText( entity, semanticType ) );
+         //         if ( isUncertain ) {
+         //            sb.append( " (??)" );
+         //         }
+         //         if ( isSearchResult ) {
+         //            sb.append( HTML_TAG.END_BOLD );
+         //         }
+         labels.add( label );
+      }
+      return labels;
+   }
+
+   static private Color getEventColor( final boolean isSearchResult,
+                                       final boolean isNegative,
+                                       final boolean isUncertain ) {
+      if ( isSearchResult ) {
+         return SELECTED_COLOR;
+      } else if ( isNegative ) {
+         return PLAIN_RED;
+      } else if ( isUncertain ) {
+         return PLAIN_ORANGE;
+      }
+      return PLAIN_GREEN;
+   }
+
+
+   static private String getEventPrefix( final boolean isSearchResult,
+                                         final boolean isNegative,
+                                         final boolean isUncertain, final boolean useItalics ) {
+      if ( isNegative ) {
+         return "(No) ";
+      }
+      return "";
+   }
+
+   static private String getEventSuffix( final boolean isSearchResult,
+                                         final boolean isNegative,
+                                         final boolean isUncertain, final boolean useItalics ) {
+      if ( isUncertain ) {
+         return " (??)";
+      }
+      return "";
+   }
+
+
+   static private String getNiceText( final String fullText ) {
+      return fullText.replaceAll( "\\s\\s\\s+", " ... " );
+   }
+
+
+   static private String getNiceText( final Annotation annotation, final SemanticClassType semanticType ) {
+      if ( semanticType != null && annotation instanceof CoreferenceChain ) {
+         return getCoreferenceText( (CoreferenceChain)annotation, semanticType );
+      }
+      return getNiceText( annotation.getSpannedText() );
+   }
+
+   static private String getCoreferenceText( final CoreferenceChain chain, final SemanticClassType semanticType ) {
+      String semanticText = null;
+      for ( Entity entity : chain ) {
+         if ( entity.getClassType() == semanticType ) {
+            if ( semanticText == null || entity.getSpannedText().length() > semanticText.length() ) {
+               semanticText = entity.getSpannedText();
+            }
+         }
+      }
+      if ( semanticText == null ) {
+         return getNiceText( chain.getSpannedText() );
+      }
+      final String fullText = chain.getSpannedText();
+      final int index = fullText.indexOf( semanticText );
+      if ( index < 0 || index + semanticText.length() > fullText.length() ) {
+         return getNiceText( chain.getSpannedText() );
+      }
+      final String notedText = fullText.replace( semanticText, "[" + semanticText + "]" );
+      return getNiceText( notedText );
+   }
+
+
+   static private String createTlinkTypeText( final Relation tlink ) {
+      final Attribute relationTypeAttribute = tlink.getAttribute( "Relation Type" );
+      if ( relationTypeAttribute == null ) {
+         // assume equality
+         return "occurs at the same time as";
+      }
+      // There is currently no default relation type in the thyme schema, but we must have one, so use overlap
+      final String relationType = relationTypeAttribute.getValue();
+      if ( relationType.equals( "BEFORE" ) ) {
+         return "occurs before";
+      } else if ( relationType.equals( "AFTER" ) ) {
+         return "occurs after";
+      } else if ( relationType.equals( "OVERLAP" ) ) {
+         return "overlaps";
+      } else if ( relationType.equals( "CONTAINS" ) ) {
+         return "contains";
+      } else if ( relationType.equals( "CONTAINED-BY" ) ) {
+         return "is within";
+      } else if ( relationType.equals( "BEGINS-ON" ) ) {
+         return "begins on";
+      } else if ( relationType.equals( "ENDS-ON" ) ) {
+         return "ends on";
+      }
+      return "overlaps";
+   }
+
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void validate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void invalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void repaint() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void revalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( long tm, int x, int y, int width, int height ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( Rectangle r ) {
+   }
+
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, byte oldValue, byte newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, char oldValue, char newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, short oldValue, short newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, int oldValue, int newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, long oldValue, long newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, float oldValue, float newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, double oldValue, double newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, boolean oldValue, boolean newValue ) {
+   }
+
+
+   // todo extract ?
+   static private enum TlinkComparator implements Comparator<Relation> {
+      INSTANCE;
+
+      public int compare( final Relation tlink1, final Relation tlink2 ) {
+         if ( !tlink1.getFirstEntity().equals( tlink2.getFirstEntity() )
+              && !tlink1.getSecondEntity().equals( tlink2.getSecondEntity() ) ) {
+            return AnnotationSpanComparator.getInstance().compare( tlink1, tlink2 );
+         }
+         final Attribute tlink1Attribute = tlink1.getAttribute( "Relation Type" );
+         final Attribute tlink2Attribute = tlink2.getAttribute( "Relation Type" );
+         if ( tlink1Attribute == null ) {
+            if ( tlink2Attribute == null ) {
+               return 0;
+            }
+            return -1;
+         } else if ( tlink2Attribute == null ) {
+            return 1;
+         }
+         // There is currently no default relation type in the thyme schema, but we must have one, so use overlap
+         final String tlinkType1 = tlink1Attribute.getValue();
+         final String tlinkType2 = tlink2Attribute.getValue();
+         if ( tlinkType1.equals( tlinkType2 ) ) {
+            // Sort alphabetically
+            if ( tlink1.getFirstEntity().equals( tlink2.getFirstEntity() ) ) {
+               return AnnotationTextComparator.getInstance().compare( tlink1.getSecondEntity(),
+                     tlink2.getSecondEntity() );
+            } else if ( tlink1.getSecondEntity().equals( tlink2.getSecondEntity() ) ) {
+               return AnnotationTextComparator.getInstance().compare( tlink1.getFirstEntity(),
+                     tlink2.getFirstEntity() );
+            }
+         }
+         if ( tlinkType1.equals( "BEFORE" ) ) {
+            return -1;
+         } else if ( tlinkType1.equals( "ENDS-ON" ) ) {
+            if ( tlinkType2.equals( "BEFORE" ) ) {
+               return 1;
+            }
+            return -1;
+         } else if ( tlinkType1.equals( "CONTAINS" ) ) {
+            if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" ) ) {
+               return 1;
+            }
+            return -1;
+         } else if ( tlinkType1.equals( "OVERLAP" ) ) {
+            if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" ) || tlinkType2.equals( "CONTAINS" ) ) {
+               return 1;
+            }
+            return -1;
+         } else if ( tlinkType1.equals( "BEGINS-ON" ) ) {
+            if ( tlinkType2.equals( "BEFORE" ) || tlinkType2.equals( "ENDS-ON" ) || tlinkType2.equals( "CONTAINS" )
+                 || tlinkType2.equals( "OVERLAP" ) ) {
+               return 1;
+            }
+            return -1;
+         } else if ( tlinkType1.equals( "AFTER" ) ) {
+            return 1;
+         }
+         return 0;
+      }
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer3.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer3.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer3.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/list/EventListRenderer3.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,197 @@
+package org.chboston.cnlp.timeline.gui.event.list;
+
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.timeline.gui.event.text.EventCellRenderer;
+import org.chboston.cnlp.timeline.gui.list.AbstractAnnotationCellRenderer;
+import org.chboston.cnlp.timeline.gui.timespan.list.TimeSpanCellRenderer;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/1/2014
+ */
+public class EventListRenderer3 extends JPanel implements ListCellRenderer<EventListElement> {
+
+   private final TimeSpanCellRenderer _timeSpanLabel;
+   private final AbstractAnnotationCellRenderer<Entity> _entityLabel;
+
+   public EventListRenderer3() {
+      super( new BorderLayout( 4, 4 ) );
+      _timeSpanLabel = new TimeSpanCellRenderer();
+      _entityLabel = new EventCellRenderer();
+      setBorder( new EmptyBorder( 0, 0, 4, 0 ) );
+      add( BorderLayout.NORTH, _timeSpanLabel );
+      add( BorderLayout.WEST, _entityLabel );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Component getListCellRendererComponent( final JList<? extends EventListElement> list,
+                                                  final EventListElement eventListElement,
+                                                  final int index,
+                                                  final boolean isSelected, final boolean cellHasFocus ) {
+      if ( isSelected ) {
+         setBackground( Color.CYAN );
+      } else {
+         if ( cellHasFocus ) {
+            setBackground( Color.LIGHT_GRAY.brighter() );
+         } else {
+            setBackground( list.getBackground() );
+         }
+      }
+      _timeSpanLabel.setBackground( list.getBackground() );
+      if ( eventListElement.getIsFirstElement() ) {
+         _timeSpanLabel.displayTimeSpan( eventListElement.getTimeSpan() );
+      } else {
+         _timeSpanLabel.clearTimeSpan( eventListElement.getTimeSpan() );
+      }
+      _entityLabel.setAnnotation( eventListElement.getEntity() );
+      return this;
+   }
+
+   @Override
+   public String getToolTipText( final MouseEvent event ) {
+      return _entityLabel.getToolTipText() + " " + _timeSpanLabel.getToolTipText();
+   }
+
+
+//      /**
+//       * Overridden for performance reasons.
+//       * See the <a href="#override">Implementation Note</a>
+//       * for more information.
+//       */
+//   @Override
+//   public void validate() {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    *
+//    * @since 1.5
+//    */
+//   @Override
+//   public void invalidate() {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    *
+//    * @since 1.5
+//    */
+//   @Override
+//   public void repaint() {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void revalidate() {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void repaint( long tm, int x, int y, int width, int height ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void repaint( Rectangle r ) {
+//   }
+//
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, byte oldValue, byte newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, char oldValue, char newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, short oldValue, short newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, int oldValue, int newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, long oldValue, long newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, float oldValue, float newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, double oldValue, double newValue ) {
+//   }
+//
+//   /**
+//    * Overridden for performance reasons.
+//    * See the <a href="#override">Implementation Note</a>
+//    * for more information.
+//    */
+//   @Override
+//   public void firePropertyChange( String propertyName, boolean oldValue, boolean newValue ) {
+//   }
+//
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/AsteriskPainter.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/AsteriskPainter.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/AsteriskPainter.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/AsteriskPainter.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,17 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class AsteriskPainter implements HighlightPainter {
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y;
+      final int x = bounds.x + bounds.width - 2;
+      g.fillRect( x, y, 4, 4 );
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashUnderliner.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashUnderliner.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashUnderliner.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashUnderliner.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,20 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class DashUnderliner implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + bounds.height;
+      for ( int x = bounds.x; x < bounds.x + bounds.width - 2; x += 4 ) {
+         g.drawLine( x, y - 1, x + 2, y - 1 );
+         g.drawLine( x, y, x + 2, y );
+      }
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashWaveUnderliner.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashWaveUnderliner.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashWaveUnderliner.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/DashWaveUnderliner.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,22 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/23/2014
+ */
+public class DashWaveUnderliner implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + bounds.height;
+      for ( int x = bounds.x; x < bounds.x + bounds.width - 3; x += 5 ) {
+         g.drawLine( x, y - 2, x + 1, y - 1 );
+         g.drawLine( x + 1, y - 2, x + 2, y - 1 );
+         g.drawLine( x + 2, y, x + 3, y - 1 );
+         g.drawLine( x + 3, y, x + 4, y - 1 );
+      }
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/EventCellRenderer.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/EventCellRenderer.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/EventCellRenderer.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/EventCellRenderer.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,125 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.classtype.ClassType;
+import org.chboston.cnlp.nlp.annotation.classtype.SemanticClassType;
+import org.chboston.cnlp.nlp.annotation.classtype.TemporalClassType;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.timeline.gui.event.EventColor;
+import org.chboston.cnlp.timeline.gui.event.EventStatus;
+import org.chboston.cnlp.timeline.gui.list.AbstractAnnotationCellRenderer;
+
+import java.awt.*;
+import java.util.regex.Pattern;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/1/2014
+ */
+final public class EventCellRenderer extends AbstractAnnotationCellRenderer<Entity> {
+   static private final HighlightPainter TWO_UNDERLINE_PAINTER = new TwoUnderliner();
+   static private final HighlightPainter UNDERLINE_PAINTER = new UnderlinePainter();
+   static private final HighlightPainter WAVE_PAINTER = new WaveUnderliner();
+   static private final HighlightPainter DASH_PAINTER = new DashUnderliner();
+   static private final HighlightPainter DASH_WAVE_PAINTER = new DashWaveUnderliner();
+   static private final HighlightPainter ASTERISK_PAINTER = new AsteriskPainter();
+   static private final Pattern SPACE_PATTERN = Pattern.compile( "\\s\\s\\s+" );
+   private EventColor _semanticColor;
+   private boolean _isTimex;
+   private EventStatus _eventStatus;
+
+   public EventCellRenderer() {
+      setForeground( Color.BLACK );
+      setFont( getFont().deriveFont( Font.BOLD ) );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void setAnnotation( final Entity entity ) {
+      final SemanticClassType semanticClassType = getSemanticClassType( entity );
+      _semanticColor = EventColor.getSemanticColor( semanticClassType );
+      if ( entity.isClassType( TemporalClassType.TIMEX ) || entity.isClassType( TemporalClassType.DOCTIME ) ) {
+         _isTimex = true;
+         _eventStatus = EventStatus.NORMAL;
+         final String text = getNiceText( entity.getSpannedText() );
+         setText( text );
+         setToolTipText( "\"" + text + "\"" );
+      } else {
+         _isTimex = false;
+         if ( entity.isClassType( TemporalClassType.EVENT ) ) {
+            _eventStatus = EventStatus.getEventStatus( entity );
+         } else {
+            _eventStatus = EventStatus.UNKNOWN;
+         }
+         final String niceText = getNiceText( entity.getSpannedText() );
+         setText( niceText );
+         setToolTipText( getDescriptiveText( entity, semanticClassType, _eventStatus, niceText ) );
+      }
+   }
+
+
+   static private SemanticClassType getSemanticClassType( final Annotation annotation ) {
+      for ( SemanticClassType type : SemanticClassType.values() ) {
+         if ( annotation.isClassType( type ) ) {
+            return type;
+         }
+      }
+      return SemanticClassType.UNKNOWN;
+   }
+
+   static public String getDescriptiveText( final Annotation annotation ) {
+      final SemanticClassType semanticClassType = getSemanticClassType( annotation );
+      return getDescriptiveText( annotation, semanticClassType, EventStatus.getEventStatus( annotation ),
+            getNiceText( annotation.getSpannedText() ) );
+   }
+
+
+   static public String getDescriptiveText( final Annotation annotation, final ClassType semanticClassType,
+                                            final EventStatus eventStatus, final String niceText ) {
+      final StringBuilder sb = new StringBuilder();
+      if ( eventStatus == EventStatus.UNCERTAIN ) {
+         sb.append( "(Uncertain) " );
+      } else if ( eventStatus == EventStatus.NEGATED ) {
+         sb.append( "(Negated) " );
+      } else if ( eventStatus == EventStatus.UNCERTAIN_NEGATED ) {
+         sb.append( "(Uncertain negated) " );
+      }
+      if ( semanticClassType != SemanticClassType.UNKNOWN ) {
+         sb.append( semanticClassType.getName() ).append( " " );
+      }
+      sb.append( "\"" ).append( niceText ).append( "\"" );
+      return sb.toString();
+   }
+
+   static private String getNiceText( final String fullText ) {
+      return SPACE_PATTERN.matcher( fullText ).replaceAll( " ... " );
+   }
+
+   @Override
+   public void paint( final Graphics g ) {
+      super.paint( g );
+      final Rectangle bounds = getInnerBounds();
+      if ( _isTimex ) {
+         TWO_UNDERLINE_PAINTER.paintHighlight( g, bounds, EventColor.TIMEX.getColor() );
+      } else if ( _eventStatus != EventStatus.UNKNOWN ) {
+         final Color color = EventColor.getEventColor( _eventStatus ).getColor();
+         if ( _eventStatus == EventStatus.UNCERTAIN_NEGATED ) {
+            DASH_WAVE_PAINTER.paintHighlight( g, bounds, color );
+         } else if ( _eventStatus == EventStatus.UNCERTAIN ) {
+            WAVE_PAINTER.paintHighlight( g, bounds, color );
+         } else if ( _eventStatus == EventStatus.NEGATED ) {
+            DASH_PAINTER.paintHighlight( g, bounds, color );
+         } else {
+            UNDERLINE_PAINTER.paintHighlight( g, bounds, color );
+         }
+      }
+//      if ( _semanticColor != null && !_semanticColor.equals( EventColor.UNKNOWN ) ) {
+      if ( _semanticColor != null && !_semanticColor.equals( EventColor.NONE ) ) {
+         ASTERISK_PAINTER.paintHighlight( g, bounds, _semanticColor.getColor() );
+      }
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/FillPainter.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/FillPainter.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/FillPainter.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/FillPainter.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,16 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class FillPainter implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/HighlightPainter.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/HighlightPainter.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/HighlightPainter.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/HighlightPainter.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,12 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public interface HighlightPainter {
+   void paintHighlight( Graphics g, Rectangle bounds, final Color color );
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TrianglePainter.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TrianglePainter.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TrianglePainter.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TrianglePainter.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,35 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class TrianglePainter implements HighlightPainter {
+   private int __xStart;
+   private int __yStart;
+   private int __xOffset;
+   private int __yOffset;
+
+   // X : 0,4 UL ; 0,4  LL ; 4,-4 UR ; 4,-4 LR
+// Y : 0,4 UL ; 4,-4 LL ; 0,4  UR ; 4,-4 LR
+   private void setCorners( final int xStart, final int yStart, final int xOffset, final int yOffset ) {
+      __xStart = xStart;
+      __yStart = yStart;
+      __xOffset = xOffset;
+      __yOffset = yOffset;
+   }
+
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + __yStart;
+//         final int x = bounds.x + bounds.width-2 + __xStart;
+      final int x = bounds.x + bounds.width - 4 + __xStart;
+      final int[] xArray = { x, x + __xOffset, x, x };
+      final int[] yArray = { y, y, y + __yOffset, y };
+      g.fillPolygon( xArray, yArray, 4 );
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TwoUnderliner.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TwoUnderliner.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TwoUnderliner.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/TwoUnderliner.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,18 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class TwoUnderliner implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + bounds.height;
+      g.drawLine( bounds.x, y - 2, bounds.x + bounds.width, y - 2 );
+      g.drawLine( bounds.x, y, bounds.x + bounds.width, y );
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/UnderlinePainter.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/UnderlinePainter.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/UnderlinePainter.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/UnderlinePainter.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,18 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class UnderlinePainter implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + bounds.height;
+      g.drawLine( bounds.x, y - 1, bounds.x + bounds.width, y - 1 );
+      g.drawLine( bounds.x, y, bounds.x + bounds.width, y );
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/WaveUnderliner.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/WaveUnderliner.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/WaveUnderliner.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/event/text/WaveUnderliner.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,22 @@
+package org.chboston.cnlp.timeline.gui.event.text;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 9/24/2014
+ */
+public class WaveUnderliner implements HighlightPainter {
+   @Override
+   public void paintHighlight( final Graphics g, final Rectangle bounds, final Color color ) {
+      g.setColor( color );
+      final int y = bounds.y + bounds.height;
+      for ( int x = bounds.x; x < bounds.x + bounds.width - 2; x += 4 ) {
+         g.drawLine( x, y - 2, x + 1, y - 1 );
+         g.drawLine( x + 1, y - 2, x + 2, y - 1 );
+         g.drawLine( x + 2, y, x + 3, y - 1 );
+         g.drawLine( x + 3, y, x + 4, y - 1 );
+      }
+   }
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AbstractAnnotationCellRenderer.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AbstractAnnotationCellRenderer.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AbstractAnnotationCellRenderer.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AbstractAnnotationCellRenderer.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,164 @@
+package org.chboston.cnlp.timeline.gui.list;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/1/2014
+ */
+abstract public class AbstractAnnotationCellRenderer<T extends Annotation> extends JLabel
+      implements AnnotationCellRenderer<T> {
+
+   static private final int BOTTOM_SPACE = 2;
+   static private final int RIGHT_SPACE = 4;
+
+   public AbstractAnnotationCellRenderer() {
+      setBorder( new EmptyBorder( 0, RIGHT_SPACE, BOTTOM_SPACE, RIGHT_SPACE ) );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   final public Rectangle getInnerBounds() {
+      return new Rectangle( RIGHT_SPACE, 0, getWidth() - RIGHT_SPACE * 2, getHeight() - BOTTOM_SPACE );
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void validate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void invalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    *
+    * @since 1.5
+    */
+   @Override
+   public void repaint() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void revalidate() {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( long tm, int x, int y, int width, int height ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void repaint( Rectangle r ) {
+   }
+
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, byte oldValue, byte newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, char oldValue, char newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, short oldValue, short newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, int oldValue, int newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, long oldValue, long newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, float oldValue, float newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, double oldValue, double newValue ) {
+   }
+
+   /**
+    * Overridden for performance reasons.
+    * See the <a href="#override">Implementation Note</a>
+    * for more information.
+    */
+   @Override
+   public void firePropertyChange( String propertyName, boolean oldValue, boolean newValue ) {
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AnnotationCellRenderer.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AnnotationCellRenderer.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AnnotationCellRenderer.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/list/AnnotationCellRenderer.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,18 @@
+package org.chboston.cnlp.timeline.gui.list;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/1/2014
+ */
+public interface AnnotationCellRenderer<T extends Annotation> {
+
+   public void setAnnotation( final T annotation );
+
+   public Rectangle getInnerBounds();
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,83 @@
+package org.chboston.cnlp.timeline.gui.main;
+
+import org.chboston.cnlp.timeline.gui.event.EventHtmlFactory;
+
+import javax.swing.*;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+import java.awt.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 4/24/14
+ */
+public class EventLegendPanel extends JEditorPane {
+
+   private FontSizingStyleSheet _styleSheet;
+
+   public EventLegendPanel() {
+      final HTMLEditorKit kit = new HTMLEditorKit();
+      if ( _styleSheet == null ) {
+         _styleSheet = new FontSizingStyleSheet();
+      }
+      kit.setStyleSheet( _styleSheet );
+      setEditorKit( kit );
+      setDocument( new HTMLDocument() );
+      setEditable( false );
+      setText( EventHtmlFactory.createColorLegend() );
+      setBorder( new CompoundBorder( new LineBorder( Color.GRAY, 1 ), new EmptyBorder( 5, 10, 10, 10 ) ) );
+   }
+
+   /**
+    * overridden to allow automatic font resizing
+    * {@inheritDoc}
+    */
+   @Override
+   public void setFont( final Font font ) {
+      if ( _styleSheet == null ) {
+         _styleSheet = new FontSizingStyleSheet();
+      }
+      final int fontSize = _styleSheet.getFontSize();
+      if ( fontSize > 0 ) {
+         final int sizeDelta = font.getSize() - getFont().getSize();
+         if ( sizeDelta != 0 ) {
+            _styleSheet.setFontSize( fontSize + sizeDelta );
+            setText( EventHtmlFactory.createColorLegend() );
+         }
+      }
+      super.setFont( font );
+   }
+
+   /**
+    * Used for automatic font resizing
+    */
+   final static private class FontSizingStyleSheet extends StyleSheet {
+      private int __fontSize;
+      private boolean __fontSizeSet = false;
+
+      public void setFontSize( final int size ) {
+         __fontSize = size;
+      }
+
+      public int getFontSize() {
+         return __fontSize;
+      }
+
+      public Font getFont( final AttributeSet attributeSet ) {
+         final Font superFont = super.getFont( attributeSet );
+         if ( !__fontSizeSet ) {
+            __fontSize = superFont.getSize();
+            __fontSizeSet = true;
+            return superFont;
+         }
+         return superFont.deriveFont( (float)__fontSize );
+      }
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel2.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel2.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel2.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/gui/main/EventLegendPanel2.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,85 @@
+package org.chboston.cnlp.timeline.gui.main;
+
+import org.chboston.cnlp.nlp.annotation.attribute.DefaultAttribute;
+import org.chboston.cnlp.nlp.annotation.attribute.DefinedAttributeType;
+import org.chboston.cnlp.nlp.annotation.attribute.EventAttributeValue;
+import org.chboston.cnlp.nlp.annotation.classtype.TemporalClassType;
+import org.chboston.cnlp.nlp.annotation.entity.DefaultEntity;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.timeline.gui.event.text.EventCellRenderer;
+
+import javax.swing.*;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+import java.awt.*;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 10/8/2014
+ */
+final public class EventLegendPanel2 {
+
+
+   private EventLegendPanel2() {
+   }
+
+   static public JComponent createLegend() {
+      final JComponent legend = new JPanel();
+      final LayoutManager layout = new BoxLayout( legend, BoxLayout.Y_AXIS );
+      legend.setLayout( layout );
+      legend.setBorder( new CompoundBorder( new LineBorder( Color.GRAY, 1 ), new EmptyBorder( 2, 5, 2, 5 ) ) );
+
+      final Entity timex = new DefaultEntity( 0, 11, "Time / Date", TemporalClassType.TIMEX );
+      final EventCellRenderer timexLabel = new EventCellRenderer();
+      timexLabel.setAnnotation( timex );
+      legend.add( timexLabel );
+
+      final Entity normalEvent = new DefaultEntity( 0, 12, "Normal Event", TemporalClassType.EVENT );
+      final EventCellRenderer normalLabel = new EventCellRenderer();
+      normalLabel.setAnnotation( normalEvent );
+      legend.add( normalLabel );
+
+      final Entity uncertainEvent = new DefaultEntity( 0, 15, "Uncertain Event", TemporalClassType.EVENT,
+            new DefaultAttribute( DefinedAttributeType.CONTEXT_MODALITY, EventAttributeValue.HYPOTHETICAL.getName() ) );
+      final EventCellRenderer uncertainLabel = new EventCellRenderer();
+      uncertainLabel.setAnnotation( uncertainEvent );
+      legend.add( uncertainLabel );
+
+      final Entity negatedEvent = new DefaultEntity( 0, 13, "Negated Event", TemporalClassType.EVENT,
+            new DefaultAttribute( DefinedAttributeType.POLARITY, "NEG" ) );
+      final EventCellRenderer negatedLabel = new EventCellRenderer();
+      negatedLabel.setAnnotation( negatedEvent );
+      legend.add( negatedLabel );
+
+      final Entity uncertainNegatedEvent = new DefaultEntity( 0, 17, "Uncertain Negated", TemporalClassType.EVENT,
+            new DefaultAttribute( DefinedAttributeType.CONTEXT_MODALITY, EventAttributeValue.HYPOTHETICAL.getName() ),
+            new DefaultAttribute( DefinedAttributeType.POLARITY, "NEG" ) );
+      final EventCellRenderer uncertainNegatedLabel = new EventCellRenderer();
+      uncertainNegatedLabel.setAnnotation( uncertainNegatedEvent );
+      legend.add( uncertainNegatedLabel );
+
+      final JLabel tlinkLabel = new JLabel( "Event Relation" );
+      final Color RELATION_COLOR = new Color( 122, 39, 112 );
+      tlinkLabel.setForeground( RELATION_COLOR );
+      tlinkLabel.setBorder( new EmptyBorder( 0, 4, 2, 4 ) );
+
+      tlinkLabel.setFont( tlinkLabel.getFont().deriveFont( Font.ITALIC + Font.BOLD ) );
+      tlinkLabel.setToolTipText( "Event occurs relative to some other Time or Event" );
+      legend.add( tlinkLabel );
+
+      final JLabel titleLabel = new JLabel( "LEGEND" );
+      titleLabel.setHorizontalAlignment( JLabel.CENTER );
+      titleLabel.setForeground( Color.BLACK );
+      titleLabel.setFont( titleLabel.getFont().deriveFont( Font.BOLD, titleLabel.getFont().getSize() + 2 ) );
+
+      final JComponent mainPanel = new JPanel( new BorderLayout() );
+      mainPanel.setBorder( new CompoundBorder( new LineBorder( Color.GRAY, 1 ), new EmptyBorder( 5, 0, 0, 0 ) ) );
+      mainPanel.add( titleLabel, BorderLayout.NORTH );
+      mainPanel.add( legend, BorderLayout.CENTER );
+      return mainPanel;
+   }
+
+
+}