gt:                     for (int i = 0; i < tokens.getItemCount(); i++) {
context: /*
   * Copyright (C) 2018 ISTC - CNR
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package it.cnr.istc.lecture.desktopapp;
  
  import it.cnr.istc.lecture.api.Lesson.LessonState;
  import it.cnr.istc.lecture.api.model.EventTemplate;
  import it.cnr.istc.lecture.api.model.QuestionEventTemplate;
  import it.cnr.istc.lecture.api.model.TextEventTemplate;
  import it.cnr.istc.lecture.api.model.URLEventTemplate;
  import it.cnr.istc.lecture.desktopapp.TeachingLessonContext.TokenRow;
  import java.net.URL;
  import java.text.FieldPosition;
  import java.text.NumberFormat;
  import java.text.ParsePosition;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.ResourceBundle;
  import javafx.animation.Interpolator;
  import javafx.animation.KeyFrame;
  import javafx.animation.KeyValue;
  import javafx.animation.Timeline;
  import javafx.beans.binding.Bindings;
  import javafx.beans.property.LongProperty;
  import javafx.beans.property.ObjectProperty;
  import javafx.beans.property.SimpleLongProperty;
  import javafx.beans.property.SimpleObjectProperty;
  import javafx.beans.value.ChangeListener;
  import javafx.beans.value.ObservableValue;
  import javafx.collections.ListChangeListener;
  import javafx.collections.transformation.SortedList;
  import javafx.event.ActionEvent;
  import javafx.fxml.FXML;
  import javafx.fxml.Initializable;
  import javafx.scene.control.Button;
  import javafx.scene.control.ContextMenu;
  import javafx.scene.control.MenuItem;
  import javafx.scene.control.SeparatorMenuItem;
  import javafx.scene.control.TableCell;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableRow;
  import javafx.scene.control.TableView;
  import javafx.scene.control.TextField;
  import javafx.scene.control.cell.PropertyValueFactory;
  import javafx.scene.control.cell.TextFieldTableCell;
  import javafx.scene.layout.StackPane;
  import javafx.scene.paint.Color;
  import javafx.util.Duration;
  import javafx.util.StringConverter;
  import org.controlsfx.glyphfont.FontAwesome;
  import org.controlsfx.glyphfont.Glyph;
  import org.jfree.chart.JFreeChart;
  import org.jfree.chart.axis.NumberAxis;
  import org.jfree.chart.fx.ChartViewer;
  import org.jfree.chart.plot.ValueMarker;
  import org.jfree.chart.plot.XYPlot;
  import org.jfree.chart.renderer.xy.XYShapeRenderer;
  import org.jfree.chart.ui.RectangleAnchor;
  import org.jfree.chart.ui.TextAnchor;
  import org.jfree.chart.util.DefaultShadowGenerator;
  import org.jfree.data.xy.XYDataItem;
  import org.jfree.data.xy.XYSeries;
  import org.jfree.data.xy.XYSeriesCollection;
  
  /**
   *
   * @author Riccardo De Benedictis
   */
  public class LessonController implements Initializable {
  
      @FXML
      private TextField lesson_name;
      @FXML
      private Button play_button;
      @FXML
      private Button pause_button;
      @FXML
      private Button stop_button;
      @FXML
      private TextField time;
      @FXML
      private StackPane lesson_chart_pane;
      @FXML
      private TableView<TokenRow> tokens_table_view;
      @FXML
      private TableColumn<TokenRow, Long> time_column;
      @FXML
      private TableColumn<TokenRow, Long> min_column;
      @FXML
      private TableColumn<TokenRow, Long> max_column;
      @FXML
      private TableColumn<TokenRow, String> id_column;
      @FXML
      private TableColumn<TokenRow, String> role_column;
      @FXML
      private TableColumn<TokenRow, String> subject_column;
      private final ObjectProperty<TeachingLessonContext> l_ctx = new SimpleObjectProperty<>();
      private final TokenXYSeries tokens = new TokenXYSeries("Tokens");
      private final ValueMarker t_now = new ValueMarker(0);
      private final LongProperty t_now_property = new SimpleLongProperty(0);
      private final ChangeListener<Number> TIME_LISTENER = (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
          time.setText(TIME_STRING_CONVERTER.toString(newValue.longValue()));
          final Timeline tl = new Timeline();
          final KeyValue kv = new KeyValue(t_now_property, newValue.longValue(), Interpolator.EASE_BOTH);
          final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
          tl.getKeyFrames().add(kf);
          tl.play();
      };
      private final ChangeListener<LessonState> STATE_LISTENER = (ObservableValue<? extends LessonState> observable, LessonState oldValue, LessonState newValue) -> {
          if (newValue != null) {
              switch (newValue) {
                  case Running:
                      play_button.setDisable(true);
                      pause_button.setDisable(false);
                      stop_button.setDisable(false);
                      break;
                  case Paused:
                      play_button.setDisable(false);
                      pause_button.setDisable(true);
                      stop_button.setDisable(false);
                      break;
                  case Stopped:
                      play_button.setDisable(false);
                      pause_button.setDisable(true);
                      stop_button.setDisable(true);
                      break;
                  default:
                      throw new AssertionError(newValue.name());
              }
          }
      };
      private static final StringConverter TIME_STRING_CONVERTER = new TimeStringConverter();
      private final ChangeListener<Number> TOKENS_TIME_CHANGE_LISTENER = (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
          List<XYDataItem> items = new ArrayList<>(tokens.getItemCount());
          for (int i = 0; i < tokens.getItemCount(); i++) {
              if (((TokenXYDataItem) tokens.getDataItem(i)).t.timeProperty() == observable) {
                  long x = ((TokenXYDataItem) tokens.getDataItem(i)).t.getTime();
                  long y = 1;
                  for (int j = 0; j < tokens.getItemCount(); j++) {
                      if (tokens.getDataItem(j).getXValue() == x) {
                          y++;
                      }
                  }
                  items.add(new TokenXYDataItem(x, y, ((TokenXYDataItem) tokens.getDataItem(i)).t));
              } else {
                  items.add(tokens.getDataItem(i));
              }
          }
          tokens.clear();
          for (XYDataItem item : items) {
              tokens.add(item);
          }
      };
      private final ListChangeListener<TokenRow> TOKENS_CHANGE_LISTENER = (ListChangeListener.Change<? extends TokenRow> c) -> {
          while (c.next()) {
              c.getAddedSubList().forEach(tk_row -> {
                  long x = tk_row.getTime();
                  long y = 1;
                  for (int i = 0; i < tokens.getItemCount(); i++) {
                      if (tokens.getDataItem(i).getXValue() == x) {
                          y++;
                      }
                  }
                  tokens.add(new TokenXYDataItem(x, y, tk_row));
                  tk_row.timeProperty().addListener(TOKENS_TIME_CHANGE_LISTENER);
              });
              c.getRemoved().forEach(tk_row -> {
                  tk_row.timeProperty().removeListener(TOKENS_TIME_CHANGE_LISTENER);
                  for (int i = 0; i < tokens.getItemCount(); i++) {
                      if (((TokenXYDataItem) tokens.getDataItem(i)).t == tk_row) {
                          tokens.remove(i);
                          break;
                      }
                  }
              });
          }
      };
  
      @Override
      public void initialize(URL location, ResourceBundle resources) {
          l_ctx.addListener((ObservableValue<? extends TeachingLessonContext> observable, TeachingLessonContext oldValue, TeachingLessonContext newValue) -> {
              if (oldValue != null) {
                  oldValue.timeProperty().removeListener(TIME_LISTENER);
                  oldValue.stateProperty().removeListener(STATE_LISTENER);
                  oldValue.tokensProperty().removeListener(TOKENS_CHANGE_LISTENER);
              }
              tokens.clear();
              if (newValue != null) {
                  lesson_name.setText(newValue.getLesson().name);
                  STATE_LISTENER.changed(newValue.stateProperty(), oldValue != null ? oldValue.stateProperty().getValue() : null, newValue.stateProperty().getValue());
                  newValue.stateProperty().addListener(STATE_LISTENER);
                  TIME_LISTENER.changed(newValue.timeProperty(), oldValue != null ? oldValue.timeProperty().getValue() : null, newValue.timeProperty().getValue());
                  newValue.timeProperty().addListener(TIME_LISTENER);
                  newValue.tokensProperty().forEach(tk_row -> {
                      long x = tk_row.getTime();
                      long y = 1;
  