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 [17/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/oldUI/SpiralledScrollPaneLayout.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/SpiralledScrollPaneLayout.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/SpiralledScrollPaneLayout.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/SpiralledScrollPaneLayout.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,516 @@
+package org.chboston.cnlp.timeline.oldUI;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/13/12
+ */
+public class SpiralledScrollPaneLayout extends ScrollPaneLayout {
+
+ static public final String SPIRAL_COMPONENT = "SpiralComponent";
+ static public final String ROW_FOOTER_COMPONENT = "RowFooterComponent";
+
+ // TODO constructor that takes SpiralUIDelegate and sues it for sizing
+
+
+ public void addLayoutComponent( String s, Component c ) {
+ if ( s.equals( SPIRAL_COMPONENT ) ) {
+ super.addLayoutComponent( LOWER_LEFT_CORNER, c );
+ return;
+ }
+ if ( s.equals( ROW_FOOTER_COMPONENT ) ) {
+ super.addLayoutComponent( LOWER_RIGHT_CORNER, c );
+ return;
+ }
+
+ super.addLayoutComponent( s, c );
+ }
+
+
+ /**
+ * The preferred size of a <code>ScrollPane</code> is the size of the insets,
+ * plus the preferred size of the viewport, plus the preferred size of
+ * the visible headers, plus the preferred size of the scrollbars
+ * that will appear given the current view and the current
+ * scrollbar displayPolicies.
+ * <p>Note that the rowHeader is calculated as part of the preferred width
+ * and the colHeader is calculated as part of the preferred size.
+ *
+ * @param parent the <code>Container</code> that will be laid out
+ * @return a <code>Dimension</code> object specifying the preferred size of the
+ * viewport and any scrollbars
+ * @see ViewportLayout
+ * @see LayoutManager
+ */
+ public Dimension preferredLayoutSize( Container parent ) {
+ final Component spiralComponent = lowerLeft;
+ final Dimension preferredSize = super.preferredLayoutSize( parent );
+ if ( spiralComponent == null ) {
+ return preferredSize;
+ }
+ final int spiralDiameter = spiralComponent.getHeight();
+ final int leftIndent = getLeftIndentation();
+ final int rightIndent = spiralDiameter / 2;
+ return new Dimension( preferredSize.width + leftIndent + rightIndent, preferredSize.height + spiralDiameter );
+ // return new Dimension( preferredSize.width + 2 * spiralDiameter, preferredSize.height + spiralDiameter );
+ }
+
+
+ /**
+ * The minimum size of a <code>ScrollPane</code> is the size of the insets
+ * plus minimum size of the viewport, plus the scrollpane's
+ * viewportBorder insets, plus the minimum size
+ * of the visible headers, plus the minimum size of the
+ * scrollbars whose displayPolicy isn't NEVER.
+ *
+ * @param parent the <code>Container</code> that will be laid out
+ * @return a <code>Dimension</code> object specifying the minimum size
+ */
+ public Dimension minimumLayoutSize( Container parent ) {
+ final Component spiralComponent = lowerLeft;
+ final Dimension minimumSize = super.minimumLayoutSize( parent );
+ if ( spiralComponent == null ) {
+ return minimumSize;
+ }
+ final int spiralDiameter = spiralComponent.getHeight();
+ final int leftIndent = getLeftIndentation();
+ final int rightIndent = spiralDiameter / 2;
+ return new Dimension( minimumSize.width + leftIndent + rightIndent, minimumSize.height + spiralDiameter );
+ // return new Dimension( minimumSize.width + 2 * spiralDiameter, minimumSize.height + spiralDiameter );
+ }
+
+ private int getLeftIndentation() {
+ final Component spiralComponent = lowerLeft;
+ final int spiralRadius = (spiralComponent == null) ? 0 : spiralComponent.getHeight() / 2;
+ if ( (rowHead != null) && (rowHead.isVisible()) ) {
+ int rowHeadWidth = rowHead.getPreferredSize().width;
+ return Math.max( spiralRadius, rowHeadWidth );
+ }
+ return spiralRadius;
+ }
+
+
+ /**
+ * Lays out the scrollpane. The positioning of components depends on
+ * the following constraints:
+ * <ul>
+ * <li> The row header, if present and visible, gets its preferred
+ * width and the viewport's height.
+ * <p/>
+ * <li> The column header, if present and visible, gets its preferred
+ * height and the viewport's width.
+ * <p/>
+ * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
+ * height is smaller than its view height or if the <code>displayPolicy</code>
+ * is ALWAYS, it's treated like the row header with respect to its
+ * dimensions and is made visible.
+ * <p/>
+ * <li> If a horizontal scrollbar is needed, it is treated like the
+ * column header (see the paragraph above regarding the vertical scrollbar).
+ * <p/>
+ * <li> If the scrollpane has a non-<code>null</code>
+ * <code>viewportBorder</code>, then space is allocated for that.
+ * <p/>
+ * <li> The viewport gets the space available after accounting for
+ * the previous constraints.
+ * <p/>
+ * <li> The corner components, if provided, are aligned with the
+ * ends of the scrollbars and headers. If there is a vertical
+ * scrollbar, the right corners appear; if there is a horizontal
+ * scrollbar, the lower corners appear; a row header gets left
+ * corners, and a column header gets upper corners.
+ * </ul>
+ *
+ * @param parent the <code>Container</code> to lay out
+ */
+ public void layoutContainer( Container parent ) {
+ final Component spiralComponent = lowerLeft;
+ if ( spiralComponent == null ) {
+ super.layoutContainer( parent );
+ return;
+ }
+ final int spiralDiameter = spiralComponent.getHeight();
+ final int spiralRadius = spiralDiameter / 2;
+ final int leftIndent = getLeftIndentation();
+ final int rightIndent = spiralRadius;
+
+ /* Sync the (now obsolete) policy fields with the
+ * JScrollPane.
+ */
+ final JScrollPane scrollPane = (JScrollPane)parent;
+ final Rectangle scrollPaneBounds = scrollPane.getBounds();
+ vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
+ hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
+
+ Rectangle availR = scrollPane.getBounds();
+ availR.x = availR.y = 0;
+
+ final Insets insets = parent.getInsets();
+ availR.x = insets.left;
+ availR.y = insets.top;
+ availR.width -= insets.left + insets.right;
+ availR.height -= insets.top + insets.bottom;
+
+ /* Get the scrollPane's orientation.
+ */
+ boolean leftToRight = true;//SwingUtilities.isLeftToRight(scrollPane);
+
+ /* If there's a visible column header remove the space it
+ * needs from the top of availR. The column header is treated
+ * as if it were fixed height, arbitrary width.
+ */
+
+ Rectangle colHeadR = new Rectangle( 0, availR.y, 0, 0 );
+
+ if ( (colHead != null) && (colHead.isVisible()) ) {
+ int colHeadHeight = Math.min( availR.height,
+ colHead.getPreferredSize().height );
+ colHeadR.height = colHeadHeight;
+ availR.y += colHeadHeight;
+ availR.height -= colHeadHeight;
+ }
+
+ /* If there's a visible row header remove the space it needs
+ * from the left or right of availR. The row header is treated
+ * as if it were fixed width, arbitrary height.
+ */
+
+ Rectangle rowHeadR = new Rectangle( 0, 0, 0, 0 );
+
+ if ( (rowHead != null) && (rowHead.isVisible()) ) {
+ // int rowHeadWidth = Math.min(availR.width,
+ // rowHead.getPreferredSize().width);
+ // int rowHeadWidth = Math.min(leftIndent,
+ // rowHead.getPreferredSize().width);
+ // rowHeadR.width = rowHeadWidth;
+ rowHeadR.x = insets.left;
+ rowHeadR.width = leftIndent - insets.left;
+ // availR.width -= rowHeadWidth;
+ // if ( leftToRight ) {
+ // rowHeadR.x = availR.x;
+ // availR.x += rowHeadWidth;
+ // } else {
+ // rowHeadR.x = availR.x + availR.width;
+ // }
+ }
+
+ // Account for the left indentation caused by the larger of 1/2 spiral or rowheader
+ availR.width -= leftIndent;
+ availR.x += leftIndent;
+ // Account for the right indentation caused by 1/2 spiral
+ availR.width -= rightIndent;
+ availR.height -= spiralDiameter;
+
+
+ /* If there's a JScrollPane.viewportBorder, remove the
+ * space it occupies for availR.
+ */
+ // We don't want to allow borders
+ // Border viewportBorder = scrollPane.getViewportBorder();
+ Insets vpbInsets;
+ // if (viewportBorder != null) {
+ // vpbInsets = viewportBorder.getBorderInsets(parent);
+ // availR.x += vpbInsets.left;
+ // availR.y += vpbInsets.top;
+ // availR.width -= vpbInsets.left + vpbInsets.right;
+ // availR.height -= vpbInsets.top + vpbInsets.bottom;
+ // }
+ // else {
+ vpbInsets = new Insets( 0, 0, 0, 0 );
+ // }
+
+
+ /* At this point availR is the space available for the viewport
+ * and scrollbars. rowHeadR is correct except for its height and y
+ * and colHeadR is correct except for its width and x. Once we're
+ * through computing the dimensions of these three parts we can
+ * go back and set the dimensions of rowHeadR.height, rowHeadR.y,
+ * colHeadR.width, colHeadR.x and the bounds for the corners.
+ *
+ * We'll decide about putting up scrollbars by comparing the
+ * viewport views preferred size with the viewports extent
+ * size (generally just its size). Using the preferredSize is
+ * reasonable because layout proceeds top down - so we expect
+ * the viewport to be laid out next. And we assume that the
+ * viewports layout manager will give the view it's preferred
+ * size. One exception to this is when the view implements
+ * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
+ * methods return true. If the view is tracking the viewports
+ * width we don't bother with a horizontal scrollbar, similarly
+ * if view.getViewTracksViewport(Height) is true we don't bother
+ * with a vertical scrollbar.
+ */
+
+ final Component view = (viewport != null) ? viewport.getView() : null;
+ Dimension viewPrefSize =
+ (view != null) ? view.getPreferredSize()
+ : new Dimension( 0, 0 );
+
+ Dimension extentSize =
+ (viewport != null) ? viewport.toViewCoordinates( availR.getSize() )
+ : new Dimension( 0, 0 );
+
+ boolean viewTracksViewportWidth = false;
+ boolean viewTracksViewportHeight = false;
+ boolean isEmpty = (availR.width < 0 || availR.height < 0);
+ Scrollable sv;
+ // Don't bother checking the Scrollable methods if there is no room
+ // for the viewport, we aren't going to show any scrollbars in this
+ // case anyway.
+ if ( !isEmpty && view instanceof Scrollable ) {
+ sv = (Scrollable)view;
+ viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
+ viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
+ } else {
+ sv = null;
+ }
+
+ /* If there's a vertical scrollbar and we need one, allocate
+ * space for it (we'll make it visible later). A vertical
+ * scrollbar is considered to be fixed width, arbitrary height.
+ */
+
+ Rectangle vsbR = new Rectangle( 0, availR.y - vpbInsets.top, 0, 0 );
+
+ boolean vsbNeeded;
+ if ( isEmpty ) {
+ vsbNeeded = false;
+ } else if ( vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS ) {
+ vsbNeeded = true;
+ } else if ( vsbPolicy == VERTICAL_SCROLLBAR_NEVER ) {
+ vsbNeeded = false;
+ } else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
+ vsbNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
+ }
+
+ if ( (vsb != null) && vsbNeeded ) {
+ adjustForVSB( true, availR, vsbR, vpbInsets, leftToRight );
+ extentSize = viewport.toViewCoordinates( availR.getSize() );
+ }
+
+ /* If there's a horizontal scrollbar and we need one, allocate
+ * space for it (we'll make it visible later). A horizontal
+ * scrollbar is considered to be fixed height, arbitrary width.
+ */
+
+ // Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
+ final int Scrollbar_Spacer = 3;
+ Rectangle hsbR = new Rectangle( availR.x - vpbInsets.left + spiralRadius + Scrollbar_Spacer, 0, 0, 0 );
+ boolean hsbNeeded;
+ if ( isEmpty ) {
+ hsbNeeded = false;
+ } else if ( hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS ) {
+ hsbNeeded = true;
+ } else if ( hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER ) {
+ hsbNeeded = false;
+ } else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
+ hsbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
+ }
+
+ if ( (hsb != null) && hsbNeeded ) {
+ adjustForHSB( true, availR, hsbR, vpbInsets );
+ /* If we added the horizontal scrollbar then we've implicitly
+ * reduced the vertical space available to the viewport.
+ * As a consequence we may have to add the vertical scrollbar,
+ * if that hasn't been done so already. Of course we
+ * don't bother with any of this if the vsbPolicy is NEVER.
+ */
+ if ( (vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER) ) {
+ extentSize = viewport.toViewCoordinates( availR.getSize() );
+ vsbNeeded = viewPrefSize.height > extentSize.height;
+ if ( vsbNeeded ) {
+ adjustForVSB( true, availR, vsbR, vpbInsets, leftToRight );
+ }
+ }
+ }
+
+ /* Set the size of the viewport first, and then recheck the Scrollable
+ * methods. Some components base their return values for the Scrollable
+ * methods on the size of the Viewport, so that if we don't
+ * ask after resetting the bounds we may have gotten the wrong
+ * answer.
+ */
+
+ if ( viewport != null ) {
+ viewport.setBounds( availR );
+ if ( sv != null ) {
+ extentSize = viewport.toViewCoordinates( availR.getSize() );
+ boolean oldHSBNeeded = hsbNeeded;
+ boolean oldVSBNeeded = vsbNeeded;
+ viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
+ viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
+ if ( vsb != null && vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED ) {
+ boolean newVSBNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
+ if ( newVSBNeeded != vsbNeeded ) {
+ vsbNeeded = newVSBNeeded;
+ adjustForVSB( vsbNeeded, availR, vsbR, vpbInsets, leftToRight );
+ extentSize = viewport.toViewCoordinates( availR.getSize() );
+ }
+ }
+ if ( hsb != null && hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED ) {
+ boolean newHSBbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
+ if ( newHSBbNeeded != hsbNeeded ) {
+ hsbNeeded = newHSBbNeeded;
+ adjustForHSB( hsbNeeded, availR, hsbR, vpbInsets );
+ if ( (vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER) ) {
+ extentSize = viewport.toViewCoordinates( availR.getSize() );
+ vsbNeeded = viewPrefSize.height > extentSize.height;
+ if ( vsbNeeded ) {
+ adjustForVSB( true, availR, vsbR, vpbInsets, leftToRight );
+ }
+ }
+ }
+ }
+ if ( oldHSBNeeded != hsbNeeded || oldVSBNeeded != vsbNeeded ) {
+ viewport.setBounds( availR );
+ // You could argue that we should recheck the
+ // Scrollable methods again until they stop changing,
+ // but they might never stop changing, so we stop here
+ // and don't do any additional checks.
+ }
+ }
+ }
+
+ /* We now have the final size of the viewport: availR.
+ * Now fixup the header and scrollbar widths/heights.
+ */
+ vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
+ // hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
+ hsbR.width = availR.width + vpbInsets.left + vpbInsets.right - spiralDiameter - 2 * Scrollbar_Spacer;
+ rowHeadR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
+ rowHeadR.y = availR.y - vpbInsets.top;
+ colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right;
+ colHeadR.x = availR.x - vpbInsets.left;
+
+ /* Set the bounds of the remaining components. The scrollbars
+ * are made invisible if they're not needed.
+ */
+
+ if ( rowHead != null ) {
+ rowHead.setBounds( rowHeadR );
+ }
+
+ if ( colHead != null ) {
+ colHead.setBounds( colHeadR );
+ }
+
+ if ( vsb != null ) {
+ if ( vsbNeeded ) {
+ vsb.setVisible( true );
+ vsbR.x = Math.max( vsbR.x, scrollPaneBounds.width - insets.right - vsbR.width );
+ vsb.setBounds( vsbR );
+ } else {
+ vsb.setVisible( false );
+ }
+ }
+
+ if ( hsb != null ) {
+ if ( hsbNeeded ) {
+ hsb.setVisible( true );
+ hsb.setBounds( hsbR );
+ } else {
+ hsb.setVisible( false );
+ }
+ }
+
+ if ( upperLeft != null ) {
+ upperLeft.setBounds( leftToRight ? rowHeadR.x : vsbR.x,
+ colHeadR.y,
+ leftToRight ? rowHeadR.width : vsbR.width,
+ colHeadR.height );
+ }
+
+ if ( upperRight != null ) {
+ upperRight.setBounds( leftToRight ? vsbR.x : rowHeadR.x,
+ colHeadR.y,
+ leftToRight ? vsbR.width : rowHeadR.width,
+ colHeadR.height );
+ }
+ // lower right is used for row footer - spiral obscures the lower right
+ if ( lowerRight != null ) {
+ final int rowFooterWidth = scrollPane.getBounds().width - (availR.x + availR.width) - insets.right - 2;
+ int lrWidth = Math.min( lowerRight.getPreferredSize().width, rowFooterWidth );
+ final Rectangle viewBounds = viewport.getBounds();
+ int lrX = viewBounds.x + viewBounds.width + 2;
+ if ( vsbNeeded ) {
+ lrWidth = Math.min( lowerRight.getPreferredSize().width, rowFooterWidth - vsbR.width );
+ }
+ lowerRight.setBounds( leftToRight ? lrX : rowHeadR.x,
+ viewBounds.y,
+ leftToRight ? lrWidth : insets.left,
+ vsbR.height );
+ }
+
+ // lower left is used for spiral
+ final int spiralX = insets.left + leftIndent - spiralRadius;
+ final int spiralWidth = scrollPane.getBounds().width - leftIndent + spiralRadius - insets.left - insets.right;
+ // final int width = scrollPane.getBounds().width - insets.left - insets.right;
+ // spiralComponent.setBounds( insets.left, availR.y + availR.height, width, spiralDiameter );
+ spiralComponent.setBounds( spiralX, availR.y + availR.height, spiralWidth, spiralDiameter );
+
+ }
+
+ /**
+ * Adjusts the <code>Rectangle</code> <code>available</code> based on if
+ * the vertical scrollbar is needed (<code>wantsVSB</code>).
+ * The location of the vsb is updated in <code>vsbR</code>, and
+ * the viewport border insets (<code>vpbInsets</code>) are used to offset
+ * the vsb. This is only called when <code>wantsVSB</code> has
+ * changed, eg you shouldn't invoke adjustForVSB(true) twice.
+ */
+ private void adjustForVSB( boolean wantsVSB, Rectangle available,
+ Rectangle vsbR, Insets vpbInsets,
+ boolean leftToRight ) {
+ // int oldWidth = vsbR.width;
+ if ( wantsVSB ) {
+ // int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
+ // available.width));
+ //
+ // available.width -= vsbWidth;
+ // vsbR.width = vsbWidth;
+ vsbR.width = vsb.getPreferredSize().width;
+ //
+ // if( leftToRight ) {
+ vsbR.x = available.x + available.width + vpbInsets.right;
+ // } else {
+ // vsbR.x = available.x - vpbInsets.left;
+ // available.x += vsbWidth;
+ // }
+ // }
+ // else {
+ // available.width += oldWidth;
+ }
+ }
+
+ /**
+ * Adjusts the <code>Rectangle</code> <code>available</code> based on if
+ * the horizontal scrollbar is needed (<code>wantsHSB</code>).
+ * The location of the hsb is updated in <code>hsbR</code>, and
+ * the viewport border insets (<code>vpbInsets</code>) are used to offset
+ * the hsb. This is only called when <code>wantsHSB</code> has
+ * changed, eg you shouldn't invoked adjustForHSB(true) twice.
+ */
+ private void adjustForHSB( boolean wantsHSB, Rectangle available,
+ Rectangle hsbR, Insets vpbInsets ) {
+ // int oldHeight = hsbR.height;
+ if ( wantsHSB ) {
+ // int hsbHeight = Math.max(0, Math.min(available.height,
+ // hsb.getPreferredSize().height));
+ //
+ // available.height -= hsbHeight;
+ // hsbR.y = available.y + available.height + vpbInsets.bottom;
+ // hsbR.height = hsbHeight;
+ hsbR.height = hsb.getPreferredSize().height;
+ final Component spiralComponent = lowerLeft;
+ hsbR.y = available.y + available.height + vpbInsets.bottom + spiralComponent.getHeight() - hsbR.height;
+ // }
+ // else {
+ // available.height += oldHeight;
+ }
+ }
+
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/TimelineDrawUtil.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/TimelineDrawUtil.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/TimelineDrawUtil.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/oldUI/TimelineDrawUtil.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,250 @@
+package org.chboston.cnlp.timeline.oldUI;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+
+import java.awt.*;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.regex.Pattern;
+
+import static org.chboston.cnlp.timeline.timespan.CalendarUtil.TIME_MILLIS.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/22/12
+ */
+final public class TimelineDrawUtil {
+
+ static final Color DATE_SPAN_COLOR = Color.BLACK;
+ static final String DATE_SPAN_COLOR_NAME = "Black";
+ static final Color DATE_TEXT_COLOR = Color.BLUE;
+ static final String DATE_TEXT_COLOR_NAME = "Blue";
+ static final Color EVENT_TEXT_COLOR = Color.GREEN.darker().darker();
+ static final String EVENT_TEXT_COLOR_NAME = "Green";
+ static final Color EVENT_NEG_TEXT_COLOR = Color.RED;
+ static final String EVENT_NEG_TEXT_COLOR_NAME = "Red";
+ static private final Pattern SPACE_PATTERN = Pattern.compile( "\\s\\s+" );
+
+ static final class DateSelectionEvent extends EventObject {
+ final private String __dateSpanText;
+ final private Collection<Annotation> __dates;
+ final private Collection<Annotation> __events;
+
+ DateSelectionEvent( final Object source, final String dateSpanText,
+ final Collection<Annotation> dates,
+ final Collection<Annotation> events ) {
+ super( source );
+ __dateSpanText = dateSpanText;
+ __dates = dates;
+ __events = events;
+ }
+
+ public String getDateSpanText() {
+ return __dateSpanText;
+ }
+
+ public Collection<Annotation> getDates() {
+ return __dates;
+ }
+
+ public Collection<Annotation> getEvents() {
+ return __events;
+ }
+ }
+
+ static public interface DateSelectionListener extends EventListener {
+ public void dateSelected( final DateSelectionEvent selectionEvent );
+ }
+
+ private TimelineDrawUtil() {
+ }
+
+//
+// /**
+// * Partial implementation of Annotation that wraps a real Annotation.
+// * Generates a Hashcode based only upon text, class, and attributes.
+// * This prevents storage and plotting of annotations that have the same Class, text, and attributes.
+// */
+// static public class SpecialHashAnnotation implements Annotation {
+// final private Annotation __annotation;
+// final private String __simpleText;
+// private int __hashcode = -1;
+//
+// public SpecialHashAnnotation( final Annotation annotation ) {
+// __annotation = annotation;
+// __simpleText = SPACE_PATTERN.matcher( annotation.getSpannedText() ).replaceAll( " " );
+//
+// }
+//
+// public TextSpan getTextSpan() {
+// return TextSpan.NULL_TEXT_SPAN.INSTANCE;
+// }
+//
+// /**
+// * @return the text for the entire textspan of this entity
+// */
+// public String getSpannedText() {
+// return __simpleText;
+// }
+//
+// /**
+// * @return a representation of the text for the entire textspan of this entity. Most useful for relations
+// */
+// public String getSpannedTextRepresentation() {
+// return __annotation.getSpannedTextRepresentation();
+// }
+//
+// /**
+// * @return the classtype type of this entity, e.g. "sign or symptom"
+// */
+// public ClassType getClassType() {
+// return __annotation.getClassType();
+// }
+//
+// /**
+// * @return all the attributes registered for this annotation
+// */
+// public java.util.List<String> getAttributeNames() {
+// return __annotation.getAttributeNames();
+// }
+//
+// /**
+// * @param key the name of a trait that may belong to this annotation
+// * @return the attribute if this annotation has it, otherwise null
+// */
+// public Attribute getAttribute( final String key ) {
+// return __annotation.getAttribute( key );
+// }
+//
+// public String getAnnotatorName() {
+// return "SpecialHashAnnotation";
+// }
+//
+//
+// public boolean areValuesEqual( final Annotation annotation ) {
+// if ( !annotation.getSpannedTextRepresentation().equals( getSpannedTextRepresentation() )
+// || !annotation.getClassType().equals( getClassType() ) ) {
+// return false;
+// }
+// final Collection<String> attributeNames = getAttributeNames();
+// final Collection<String> annotationAttributeNames = annotation.getAttributeNames();
+// if ( annotationAttributeNames.size() != attributeNames.size() ) {
+// return false;
+// }
+// for ( String key : attributeNames ) {
+// if ( !getAttribute( key ).equals( annotation.getAttribute( key ) ) ) {
+// return false;
+// }
+// }
+// return true;
+// }
+//
+// /**
+// * {@inheritDoc}
+// */
+// @Override
+// public boolean equals( final Object object ) {
+// return object instanceof Annotation && areValuesEqual( (Annotation) object );
+// }
+//
+// /**
+// * {@inheritDoc}
+// */
+// @Override
+// public int hashCode() {
+// if ( __hashcode != -1 ) {
+// // hashcode already set
+// return __hashcode;
+// }
+// long bits = 17 + getSpannedTextRepresentation().hashCode();
+// bits = 2 * bits + getClassType().hashCode();
+// final Collection<String> attributeNames = getAttributeNames();
+// for ( String attributeName : attributeNames ) {
+// bits = 2 * bits + getAttribute( attributeName ).hashCode();
+// }
+// __hashcode = (((int) bits) ^ ((int) (bits >> 32)));
+// return __hashcode;
+// }
+// }
+
+
+ static public Calendar getBufferedBeginTime( final Calendar beginTime, final Calendar endTime ) {
+ final long timeSpanMillis = endTime.getTimeInMillis() - beginTime.getTimeInMillis();
+ final int calendarField = getOffsetCalendarField( timeSpanMillis );
+ final Calendar drawBeginTime = Calendar.getInstance();
+ drawBeginTime.set( beginTime.get( Calendar.YEAR ),
+ beginTime.get( Calendar.MONTH ),
+ beginTime.get( Calendar.DATE ),
+ 12,
+ 0 );
+ if ( drawBeginTime.getTimeInMillis() > beginTime.getTimeInMillis() ) {
+ drawBeginTime.add( Calendar.HOUR_OF_DAY, -12 );
+ }
+ final int amount = getOffsetCalendarAmount( timeSpanMillis );
+ drawBeginTime.add( calendarField, -1 * amount );
+ return drawBeginTime;
+ }
+
+ static public Calendar getBufferedEndTime( final Calendar beginTime, final Calendar endTime ) {
+ final long timeSpanMillis = endTime.getTimeInMillis() - beginTime.getTimeInMillis();
+ final int calendarField = getOffsetCalendarField( timeSpanMillis );
+ final Calendar drawEndTime = Calendar.getInstance();
+ drawEndTime.set( endTime.get( Calendar.YEAR ), endTime.get( Calendar.MONTH ), endTime.get( Calendar.DATE ),
+ 12, 0 );
+ if ( drawEndTime.getTimeInMillis() < endTime.getTimeInMillis() ) {
+ drawEndTime.add( Calendar.HOUR_OF_DAY, 12 );
+ }
+ final int amount = getOffsetCalendarAmount( timeSpanMillis );
+ drawEndTime.add( calendarField, amount );
+ return drawEndTime;
+ }
+
+ static private int getOffsetCalendarField( final long timeSpanMillis ) {
+ int calendarField = Calendar.MONTH;
+ if ( timeSpanMillis <= HOUR.__millis ) {
+ calendarField = Calendar.MINUTE;
+ } else if ( timeSpanMillis <= DAY.__millis ) {
+ calendarField = Calendar.MINUTE;
+ } else if ( timeSpanMillis <= WEEK.__millis ) {
+ calendarField = Calendar.HOUR_OF_DAY;
+ } else if ( timeSpanMillis <= MONTH.__millis ) {
+ calendarField = Calendar.DAY_OF_YEAR;
+// } else if ( timeSpanMillis <= SIX_MONTH_MILLIS ) {
+// calendarField = Calendar.DAY_OF_YEAR;
+ } else if ( timeSpanMillis <= YEAR.__millis ) {
+ calendarField = Calendar.WEEK_OF_YEAR;
+ } else if ( timeSpanMillis <= DECADE.__millis ) {
+ calendarField = Calendar.MONTH;
+ }
+ return calendarField;
+ }
+
+ static private int getOffsetCalendarAmount( final long timeSpanMillis ) {
+ if ( timeSpanMillis <= HOUR.__millis ) {
+ if ( timeSpanMillis >= HOUR.__millis / 2 ) {
+ return 10; // 10 minutes
+ }
+ return 5; // 5 minutes
+ } else if ( timeSpanMillis <= DAY.__millis ) {
+ final long factor = timeSpanMillis / HOUR.__millis;
+ final long minutes = 10 * factor; // +- 10 minutes per hour
+ return (int)Math.max( 30, (minutes - minutes % 30) ); // +- 10 minutes to n*30 minutes
+ } else if ( timeSpanMillis <= WEEK.__millis ) {
+ final long factor = 2 * timeSpanMillis / DAY.__millis;
+ return (int)Math.max( 2, factor ); // +- 2 hours per day
+ } else if ( timeSpanMillis <= MONTH.__millis ) {
+ final long factor = 2 * timeSpanMillis / WEEK.__millis;
+ return (int)Math.max( 2, factor ); // +- 2 days per week
+ } else if ( timeSpanMillis <= YEAR.__millis ) {
+ final long factor = timeSpanMillis / MONTH.__millis;
+ return (int)Math.max( 1, factor ); // +- 1 week per month
+ } else if ( timeSpanMillis <= DECADE.__millis ) {
+ return 6; // +- 6 months
+ }
+ return 5;
+ }
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/CompoundTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/CompoundTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/CompoundTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/CompoundTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,156 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import net.jcip.annotations.Immutable;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/17/14
+ */
+@Immutable
+final public class CompoundTimeline extends AbstractTimeSpan implements Timeline {
+
+ // TODO use MutableTimeline and make this class mutable
+
+ final private Timeline _timelineDelegate;
+ final private Collection<Timeline> _timelines;
+
+ public CompoundTimeline( final String title, final long referenceMillis,
+ final Collection<Timeline> timelines ) {
+ _timelines = Collections.unmodifiableCollection( timelines );
+ // List of all Time Spans.
+ final Collection<PointedTimeSpan> timeSpans = new HashSet<>();
+ final Collection<Entity> times = new HashSet<>();
+ for ( Timeline timeline : timelines ) {
+ timeSpans.addAll( timeline.getTimeSpans() );
+ times.addAll( timeline.getTimes() );
+ }
+ // Map of all Entities in TimeSpans
+ final Map<PointedTimeSpan, Collection<Entity>> timeSpanEntityMap
+ = new HashMap<>( timeSpans.size() );
+ final Map<Entity, Collection<Relation>> entityTlinkMap = new HashMap<>();
+ for ( PointedTimeSpan timeSpan : timeSpans ) {
+ final Collection<Entity> entities = new HashSet<>();
+ for ( Timeline timeline : timelines ) {
+ final Collection<Entity> timelineEntities = timeline.getEntities( timeSpan );
+ if ( timelineEntities != null && !timelineEntities.isEmpty() ) {
+ entities.addAll( timelineEntities );
+ for ( Entity entity : timelineEntities ) {
+ final Collection<Relation> relations = timeline.getEntityEntityRelations( entity );
+ if ( relations != null && !relations.isEmpty() ) {
+ entityTlinkMap.put( entity, relations );
+ }
+ }
+ }
+ }
+ timeSpanEntityMap.put( timeSpan, entities );
+ }
+ _timelineDelegate = new DefaultTimeline( title, referenceMillis, timeSpanEntityMap, entityTlinkMap, times );
+ }
+
+ /**
+ * @return the individual timelines that make up this compound timeline
+ */
+ public Collection<Timeline> getTimelines() {
+ return _timelines;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _timelineDelegate.getTitle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _timelineDelegate.getReferenceMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _timelineDelegate.getTimeSpans();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ return _timelineDelegate.getEntityEntityRelations( entity );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ return _timelineDelegate.getEntities( timeSpan );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ return _timelineDelegate.getEntities();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _timelineDelegate.getTimes();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _timelineDelegate.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _timelineDelegate.getStopMillis();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _timelineDelegate.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _timelineDelegate.iterator();
+ }
+
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/DefaultTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/DefaultTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/DefaultTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/DefaultTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,197 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import net.jcip.annotations.Immutable;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.nlp.util.CollectionMap;
+import org.chboston.cnlp.timeline.timespan.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.DefaultTimeSpan;
+import org.chboston.cnlp.timeline.timespan.TimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.TimeSpanPlus;
+import org.chboston.cnlp.timeline.timespan.plus.TimeSpanPlusComparator;
+
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/2/13
+ */
+@Immutable
+final public class DefaultTimeline extends AbstractTimeSpan implements Timeline {
+
+ // TODO make this a wrapper around a MutableTimeline created with Collections.unmodifiableCollection( parm )
+ // throw UnsupportedOperationException on add, set methods
+
+ final private String _title;
+ // reference time for the timeline. Used for searching, etc. Basically the "docTime" or Current Date.
+ final private long _referenceMillis;
+
+ // List of all Time Spans.
+ final private List<PointedTimeSpan> _timeSpanList;
+ // Every timeline has/is a time span with start and end times
+ final private TimeSpan _timeSpanDelegate;
+
+ final private Map<PointedTimeSpan, Collection<Entity>> _timeSpanEntityMap;
+ final private Map<Entity, Collection<Relation>> _entityTlinkMap;
+
+ final private Collection<Entity> _times;
+
+
+ DefaultTimeline( final String title, final long referenceMillis,
+ final Map<PointedTimeSpan, Collection<Entity>> timeSpanEntityMap,
+ final Map<Entity, Collection<Relation>> entityTlinkMap,
+ final Collection<Entity> times ) {
+ _title = title;
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis( referenceMillis );
+ calendar.set( Calendar.HOUR_OF_DAY, 0 );
+ calendar.set( Calendar.MINUTE, 0 );
+ _referenceMillis = calendar.getTimeInMillis();
+ _timeSpanEntityMap = Collections.unmodifiableMap( timeSpanEntityMap );
+ _entityTlinkMap = Collections.unmodifiableMap( entityTlinkMap );
+ _times = Collections.unmodifiableCollection( times );
+ final List<PointedTimeSpan> timeSpanList = new ArrayList<>( timeSpanEntityMap.keySet() );
+ timeSpanList.remove( TimeSpanPlus.UNKNOWN_TIMESPAN_PLUS );
+ Collections.sort( timeSpanList, TimeSpanPlusComparator.getInstance() );
+ _timeSpanList = Collections.unmodifiableList( timeSpanList );
+ long start = Long.MAX_VALUE;
+ long end = Long.MIN_VALUE;
+ for ( TimeSpan timeSpan : timeSpanList ) {
+ start = Math.min( start, timeSpan.getStartMillis() );
+ end = Math.max( end, timeSpan.getStopMillis() );
+ }
+ _timeSpanDelegate = new DefaultTimeSpan( start, end );
+ }
+
+ DefaultTimeline( final String title, final long referenceMillis,
+ final CollectionMap<PointedTimeSpan, Entity> timeSpanEntityMap,
+ final CollectionMap<Entity, Relation> entityTlinkMap,
+ final Collection<Entity> times ) {
+ _title = title;
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis( referenceMillis );
+ calendar.set( Calendar.HOUR_OF_DAY, 0 );
+ calendar.set( Calendar.MINUTE, 0 );
+ _referenceMillis = calendar.getTimeInMillis();
+ _timeSpanEntityMap = Collections.unmodifiableMap( (Map<PointedTimeSpan, Collection<Entity>>)timeSpanEntityMap );
+ _entityTlinkMap = Collections.unmodifiableMap( (Map<Entity, Collection<Relation>>)entityTlinkMap );
+ _times = Collections.unmodifiableCollection( times );
+ final List<PointedTimeSpan> timeSpanList = new ArrayList<>( _timeSpanEntityMap.keySet() );
+ timeSpanList.remove( TimeSpanPlus.UNKNOWN_TIMESPAN_PLUS );
+ Collections.sort( timeSpanList, TimeSpanPlusComparator.getInstance() );
+ _timeSpanList = Collections.unmodifiableList( timeSpanList );
+ long start = Long.MAX_VALUE;
+ long end = Long.MIN_VALUE;
+ for ( TimeSpan timeSpan : timeSpanList ) {
+ start = Math.min( start, timeSpan.getStartMillis() );
+ end = Math.max( end, timeSpan.getStopMillis() );
+ }
+ _timeSpanDelegate = new DefaultTimeSpan( start, end );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _referenceMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _timeSpanList;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ final Collection<Relation> tlinks = _entityTlinkMap.get( entity );
+ if ( tlinks != null ) {
+ return tlinks;
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ return _timeSpanEntityMap.get( timeSpan );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ final Collection<Entity> allEntities = new HashSet<>( _entityTlinkMap.keySet() );
+ for ( PointedTimeSpan timeSpan : _timeSpanList ) {
+ allEntities.addAll( getEntities( timeSpan ) );
+ }
+ final Collection<Entity> unknownTimeEntities = getEntities( TimeSpanPlus.UNKNOWN_TIMESPAN_PLUS );
+ if ( unknownTimeEntities != null ) {
+ allEntities.addAll( unknownTimeEntities );
+ }
+ return allEntities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _times;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _timeSpanDelegate.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _timeSpanDelegate.getStopMillis();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _timeSpanDelegate.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _timeSpanList.iterator();
+ }
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/EventTextTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/EventTextTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/EventTextTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/EventTextTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,176 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/21/14
+ */
+public class EventTextTimeline extends AbstractTimeSpan implements Timeline {
+
+ final private String _title;
+ final private Timeline _fullTimeline;
+ final private Collection<String> _eventTexts;
+ final private List<PointedTimeSpan> _eventTextTimeSpans = new ArrayList<>();
+
+
+ public EventTextTimeline( final String title,
+ final Timeline fullTimeline,
+ final Collection<String> eventTexts ) {
+ _title = title;
+ _fullTimeline = fullTimeline;
+ _eventTexts = new ArrayList<>( eventTexts.size() );
+ for ( String text : eventTexts ) {
+ _eventTexts.add( text.toLowerCase() );
+ }
+ segregateByEventText( fullTimeline, _eventTexts );
+ }
+
+ public Collection<String> getEventTexts() {
+ return _eventTexts;
+ }
+
+ private void segregateByEventText( final Timeline fullTimeline, final Collection<String> eventTexts ) {
+ // The number of timespans in a timeline can be large, so sorting by event text should be done
+ // at instantiation rather than dynamically on-call
+ for ( PointedTimeSpan timeSpan : fullTimeline ) {
+ boolean added = false;
+ final Collection<Entity> entities = getEntities( timeSpan );
+ for ( Entity entity : entities ) {
+ final String entityText = entity.getSpannedText().toLowerCase();
+ for ( String text : eventTexts ) {
+ if ( entityText.contains( text ) ) {
+ _eventTextTimeSpans.add( timeSpan );
+ added = true;
+ break;
+ }
+ }
+ if ( added ) {
+ break;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _fullTimeline.getReferenceMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _eventTextTimeSpans;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ return _fullTimeline.getEntityEntityRelations( entity );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ // There should be few enough entities in a single timespan to do this dynamically
+ final Collection<Entity> allEntities = _fullTimeline.getEntities( timeSpan );
+ final Collection<Entity> textEntities = new HashSet<>();
+ for ( Entity entity : allEntities ) {
+ final String entityText = entity.getSpannedText().toLowerCase();
+ for ( String text : _eventTexts ) {
+ if ( entityText.contains( text ) ) {
+ textEntities.add( entity );
+ break;
+ }
+ }
+ }
+ return textEntities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ final Collection<Entity> allEntities = _fullTimeline.getEntities();
+ final Collection<Entity> textEntities = new HashSet<>();
+ for ( Entity entity : allEntities ) {
+ final String entityText = entity.getSpannedText().toLowerCase();
+ for ( String text : _eventTexts ) {
+ if ( entityText.contains( text ) ) {
+ textEntities.add( entity );
+ break;
+ }
+ }
+ }
+ return textEntities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _fullTimeline.getTimes();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _fullTimeline.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _fullTimeline.getStopMillis();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _fullTimeline.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _eventTextTimeSpans.iterator();
+ }
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/MutableTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/MutableTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/MutableTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/MutableTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,269 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.DefaultTimeSpan;
+import org.chboston.cnlp.timeline.timespan.TimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.TimeSpanPlus;
+import org.chboston.cnlp.timeline.timespan.plus.TimeSpanPlusComparator;
+
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/21/14
+ */
+final public class MutableTimeline extends AbstractTimeSpan implements Timeline {
+
+ // TODO add mutable state methods (add, set) to interface Timeline, make MutableTimeline DefaultTimeline,
+ // Make DefaultTimeline UnmodifiableTimeline (or remove altogether)
+
+ final private String _title;
+ // reference time for the timeline. Used for searching, etc. Basically the "docTime" or Current Date.
+ private long _referenceMillis;
+
+ // List of all Time Spans.
+ final private List<PointedTimeSpan> _timeSpanList;
+ // Every timeline has/is a time span with start and end times
+ private TimeSpan _timeSpanDelegate;
+
+ final private Map<PointedTimeSpan, Collection<Entity>> _timeSpanEntityMap;
+ final private Map<Entity, Collection<Relation>> _entityTlinkMap;
+ final private Collection<Entity> _times;
+
+ MutableTimeline( final String title ) {
+ this( title, System.currentTimeMillis(),
+ new HashMap<PointedTimeSpan, Collection<Entity>>(),
+ new HashMap<Entity, Collection<Relation>>(), new HashSet<Entity>() );
+ }
+
+ MutableTimeline( final String title, final long referenceMillis,
+ final Map<PointedTimeSpan, Collection<Entity>> timeSpanEntityMap,
+ final Map<Entity, Collection<Relation>> entityTlinkMap, final Collection<Entity> times ) {
+ _title = title;
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis( referenceMillis );
+ calendar.set( Calendar.HOUR_OF_DAY, 0 );
+ calendar.set( Calendar.MINUTE, 0 );
+ _referenceMillis = calendar.getTimeInMillis();
+ _timeSpanEntityMap = timeSpanEntityMap;
+ _entityTlinkMap = entityTlinkMap;
+ _times = times;
+ final List<PointedTimeSpan> timeSpanList = new ArrayList<>( timeSpanEntityMap.keySet() );
+ Collections.sort( timeSpanList, TimeSpanPlusComparator.getInstance() );
+ _timeSpanList = timeSpanList;
+
+ long start = Long.MAX_VALUE;
+ long end = Long.MIN_VALUE;
+ for ( TimeSpan timeSpan : timeSpanList ) {
+ start = Math.min( start, timeSpan.getStartMillis() );
+ end = Math.max( end, timeSpan.getStopMillis() );
+ }
+ _timeSpanDelegate = new DefaultTimeSpan( start, end );
+ }
+
+ MutableTimeline( final String title, final long referenceMillis,
+ final Map<PointedTimeSpan, Collection<Entity>> timeSpanEntityMap,
+ final Map<Entity, Collection<Relation>> entityTlinkMap,
+ final long startMillis, final long stopMillis, final Collection<Entity> times ) {
+ _title = title;
+ _referenceMillis = referenceMillis;
+ _timeSpanEntityMap = timeSpanEntityMap;
+ _entityTlinkMap = entityTlinkMap;
+ _times = times;
+ final List<PointedTimeSpan> timeSpanList = new ArrayList<>( timeSpanEntityMap.keySet() );
+ Collections.sort( timeSpanList, TimeSpanPlusComparator.getInstance() );
+ _timeSpanList = timeSpanList;
+ _timeSpanDelegate = new DefaultTimeSpan( startMillis, stopMillis );
+ }
+
+ public void setReferenceMillis( final long referenceMillis ) {
+ _referenceMillis = referenceMillis;
+ fireStateChanged();
+ }
+
+ public void setTimeSpan( final long startMillis, final long stopMillis ) {
+ _timeSpanDelegate = new DefaultTimeSpan( startMillis, stopMillis );
+ fireStateChanged();
+ }
+
+ public void addTimeSpans( final Collection<TimeSpanPlus> timeSpans ) {
+ _timeSpanList.addAll( timeSpans );
+ Collections.sort( _timeSpanList, TimeSpanPlusComparator.getInstance() );
+ fireStateChanged();
+ }
+
+ public void addEntities( final Map<TimeSpanPlus, Collection<Entity>> timeSpanEntityMap ) {
+ for ( Map.Entry<TimeSpanPlus, Collection<Entity>> entry : timeSpanEntityMap.entrySet() ) {
+ final Collection<Entity> entities = _timeSpanEntityMap.get( entry.getKey() );
+ if ( entities != null ) {
+ entities.addAll( entry.getValue() );
+ } else {
+ _timeSpanEntityMap.put( entry.getKey(), entry.getValue() );
+ }
+ }
+ fireStateChanged();
+ }
+
+ public void addEntityEntityRelations( final Map<Entity, Collection<Relation>> entityTlinkMap ) {
+ for ( Map.Entry<Entity, Collection<Relation>> entry : entityTlinkMap.entrySet() ) {
+ final Collection<Relation> relations = _entityTlinkMap.get( entry.getKey() );
+ if ( relations != null ) {
+ relations.addAll( entry.getValue() );
+ } else {
+ _entityTlinkMap.put( entry.getKey(), entry.getValue() );
+ }
+ }
+ fireStateChanged();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _referenceMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _timeSpanList;
+ }
+
+ // /**
+ // * Collapse and connect time spans in such a way that only large discontiguous non-overlapping spans are returned
+ // * @return spans made by overlapping all smaller time spans
+ // */
+ // public Collection<TimeSpan> getTimeSpanCoverage() {
+ // final Collection<TimeSpan> addSpans = new HashSet<TimeSpan>();
+ // final Collection<TimeSpan> removeSpans = new HashSet<TimeSpan>();
+ // final int size = _timeSpanList.size();
+ // for ( int i=0; i<size; i++ ) {
+ // TimeSpan bigTimeSpan = new DefaultTimeSpan( _timeSpanList.get(i).getStartMillis(),
+ // _timeSpanList.get(i).getStopMillis() );
+ // for ( int j=size-1; j>=0; j-- ) {
+ // final TimeSpan checkTimeSpan = _timeSpanList.get(j);
+ // if ( bigTimeSpan.getStartMillis() == checkTimeSpan.getStartMillis()
+ // && bigTimeSpan.getStopMillis() == checkTimeSpan.getStopMillis() ) {
+ // continue;
+ // }
+ // if ( bigTimeSpan.contains( checkTimeSpan ) ) {
+ // continue;
+ // }
+ // if ( checkTimeSpan.contains( bigTimeSpan ) ) {
+ // bigTimeSpan = new DefaultTimeSpan( checkTimeSpan.getStartMillis(), checkTimeSpan.getStopMillis() );
+ // continue;
+ // }
+ // if ( bigTimeSpan.overlaps( checkTimeSpan ) ) {
+ // bigTimeSpan = new DefaultTimeSpan( Math.min( bigTimeSpan.getStartMillis(), checkTimeSpan.getStartMillis()),
+ // Math.max( bigTimeSpan.getStopMillis(), checkTimeSpan.getStopMillis()) );
+ // }
+ // }
+ // for ( TimeSpan addSpan : addSpans ) {
+ // if ( addSpan.contains( bigTimeSpan ) ) {
+ // bigTimeSpan = addSpan;
+ // continue;
+ // }
+ // if ( bigTimeSpan.contains( addSpan ) ) {
+ // removeSpans.add( addSpan );
+ // }
+ // if ( addSpan.overlaps( bigTimeSpan ) ) {
+ // bigTimeSpan = new DefaultTimeSpan( Math.min( bigTimeSpan.getStartMillis(), addSpan.getStartMillis()),
+ // Math.max( bigTimeSpan.getStopMillis(), addSpan.getStopMillis()) );
+ // removeSpans.add( addSpan );
+ // }
+ // }
+ // addSpans.removeAll( removeSpans );
+ // removeSpans.clear();
+ // addSpans.add( bigTimeSpan );
+ // }
+ // return addSpans;
+ // }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ final Collection<Relation> tlinks = _entityTlinkMap.get( entity );
+ if ( tlinks != null ) {
+ return tlinks;
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ return _timeSpanEntityMap.get( timeSpan );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ return _entityTlinkMap.keySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _times;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _timeSpanDelegate.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _timeSpanDelegate.getStopMillis();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _timeSpanDelegate.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _timeSpanList.iterator();
+ }
+
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SectionedTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SectionedTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SectionedTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SectionedTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,141 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.TimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/21/14
+ */
+public class SectionedTimeline extends AbstractTimeSpan implements Timeline {
+
+ final private String _title;
+ final private Timeline _fullTimeline;
+ final private Collection<TimeSpan> _sections;
+ final private List<PointedTimeSpan> _sectionTimeSpans = new ArrayList<>();
+
+
+ public SectionedTimeline( final String title,
+ final Timeline fullTimeline,
+ final Collection<TimeSpan> sections ) {
+ _title = title;
+ _fullTimeline = fullTimeline;
+ _sections = sections;
+ segregateBySection( fullTimeline, sections );
+ }
+
+ private void segregateBySection( final Timeline fullTimeline, final Collection<TimeSpan> sections ) {
+ // The number of timespans in a timeline can be large, so sorting by event text should be done
+ // at instantiation rather than dynamically on-call
+ for ( PointedTimeSpan timeSpan : fullTimeline ) {
+ for ( TimeSpan section : sections ) {
+ if ( section.contains( timeSpan ) ) {
+ _sectionTimeSpans.add( timeSpan );
+ break;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _fullTimeline.getReferenceMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _sectionTimeSpans;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ return _fullTimeline.getEntityEntityRelations( entity );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ return _fullTimeline.getEntities( timeSpan );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ return _fullTimeline.getEntities();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _fullTimeline.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _fullTimeline.getStopMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _fullTimeline.getTimes();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _fullTimeline.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _sectionTimeSpans.iterator();
+ }
+
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SemanticTypeTimeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SemanticTypeTimeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SemanticTypeTimeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/SemanticTypeTimeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,157 @@
+package org.chboston.cnlp.timeline.timeline;
+
+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.AbstractTimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.*;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/21/14
+ */
+public class SemanticTypeTimeline extends AbstractTimeSpan implements Timeline {
+
+ final private String _title;
+ final private Timeline _fullTimeline;
+ final private SemanticClassType _semanticClassType;
+ final private List<PointedTimeSpan> _semanticTimeSpans = new ArrayList<>();
+
+
+ public SemanticTypeTimeline( final String title,
+ final Timeline fullTimeline,
+ final SemanticClassType semanticClassType ) {
+ _title = title;
+ _fullTimeline = fullTimeline;
+ _semanticClassType = semanticClassType;
+ segregateBySemantics( fullTimeline, semanticClassType );
+ }
+
+ public SemanticClassType getSemanticClassType() {
+ return _semanticClassType;
+ }
+
+ private void segregateBySemantics( final Timeline fullTimeline, final SemanticClassType semanticClassType ) {
+ // The number of timespans in a timeline can be large, so sorting by semantic type should be done
+ // at instantiation rather than dynamically on-call
+ for ( PointedTimeSpan timeSpan : fullTimeline ) {
+ final Collection<Entity> entities = fullTimeline.getEntities( timeSpan );
+ for ( Entity entity : entities ) {
+ if ( entity.isClassType( semanticClassType ) ) {
+ _semanticTimeSpans.add( timeSpan );
+ break;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTitle() {
+ return _title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getReferenceMillis() {
+ return _fullTimeline.getReferenceMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PointedTimeSpan> getTimeSpans() {
+ return _semanticTimeSpans;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Relation> getEntityEntityRelations( final Entity entity ) {
+ return _fullTimeline.getEntityEntityRelations( entity );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities( final PointedTimeSpan timeSpan ) {
+ // There should be few enough entities in a single timespan to do this dynamically
+ final Collection<Entity> allEntities = _fullTimeline.getEntities( timeSpan );
+ final Collection<Entity> semanticEntities = new HashSet<>();
+ for ( Entity entity : allEntities ) {
+ if ( entity.isClassType( _semanticClassType ) ) {
+ semanticEntities.add( entity );
+ }
+ }
+ return semanticEntities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getEntities() {
+ final Collection<Entity> allEntities = _fullTimeline.getEntities();
+ final Collection<Entity> semanticEntities = new HashSet<>();
+ for ( Entity entity : allEntities ) {
+ if ( entity.isClassType( _semanticClassType ) ) {
+ semanticEntities.add( entity );
+ }
+ }
+ return semanticEntities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Entity> getTimes() {
+ return _fullTimeline.getTimes();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStartMillis() {
+ return _fullTimeline.getStartMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getStopMillis() {
+ return _fullTimeline.getStopMillis();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFuzzyDate() {
+ return _fullTimeline.isFuzzyDate();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<PointedTimeSpan> iterator() {
+ return _semanticTimeSpans.iterator();
+ }
+
+}
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/Timeline.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/Timeline.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/Timeline.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/timeline/timeline/Timeline.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,56 @@
+package org.chboston.cnlp.timeline.timeline;
+
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.timeline.timespan.TimeSpan;
+import org.chboston.cnlp.timeline.timespan.plus.PointedTimeSpan;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 3/17/14
+ */
+public interface Timeline extends TimeSpan, Iterable<PointedTimeSpan> {
+
+ /**
+ * @return title
+ */
+ String getTitle();
+
+ /**
+ * @return reference time for the timeline. Used for searching, etc. Basically the "docTime" or Current Date.
+ */
+ long getReferenceMillis();
+
+ /**
+ * @return List of all Time Spans.
+ */
+ List<PointedTimeSpan> getTimeSpans();
+
+ /**
+ * @param entity entity that may or may not be in temporal relations
+ * @return all temporal relations for the given entity
+ */
+ Collection<Relation> getEntityEntityRelations( Entity entity );
+
+ /**
+ * @param timeSpan some time span
+ * @return all entities associated with time span
+ */
+ Collection<Entity> getEntities( PointedTimeSpan timeSpan );
+
+ /**
+ * @return all entities associated with timeline
+ */
+ Collection<Entity> getEntities();
+
+ /**
+ * @return all timex associated with timeline
+ */
+ Collection<Entity> getTimes();
+
+
+}