@Override
 public void contentsChanged(ListDataEvent e) {
   // case where the active layer was removed
   if (!layers.contains(activeLayer)) {
     setActiveLayer(null);
   }
   if ((activeLayer == null) && !layers.isEmpty()) {
     setActiveLayer(layers.getLayers()[0]);
   }
   updateGraphicsPanelDrawers();
   getScore().autorescaleScoreAxis();
 }
 /**
  * Sets the active layer of the track if the specified layer is one of the layers of the track.
  * Sets the active layer to null if the specified parameter is null. Does nothing if the specified
  * layer is not null and is not one of the layers of the track
  *
  * @param activeLayer the active layer to set
  */
 public void setActiveLayer(Layer<?> activeLayer) {
   Layer<?> oldLayer = getActiveLayer();
   if (activeLayer == null) {
     this.activeLayer = null;
   } else if (layers.contains(activeLayer)) {
     this.activeLayer = activeLayer;
   }
   // update the mouse listeners of the graphics panel
   if (oldLayer != activeLayer) {
     if (oldLayer != null) {
       if (oldLayer instanceof MouseMotionListener) {
         graphicsPanel.removeMouseMotionListener((MouseMotionListener) oldLayer);
       }
       if (oldLayer instanceof MouseListener) {
         graphicsPanel.removeMouseListener((MouseListener) oldLayer);
       }
       if (oldLayer instanceof MouseWheelListener) {
         graphicsPanel.removeMouseWheelListener((MouseWheelListener) oldLayer);
       }
     }
     if (activeLayer != null) {
       if (activeLayer instanceof MouseMotionListener) {
         graphicsPanel.addMouseMotionListener((MouseMotionListener) activeLayer);
       }
       if (activeLayer instanceof MouseListener) {
         graphicsPanel.addMouseListener((MouseListener) activeLayer);
       }
       if (activeLayer instanceof MouseWheelListener) {
         graphicsPanel.addMouseWheelListener((MouseWheelListener) activeLayer);
       }
     }
   }
 }
 /**
  * Method used for unserialization
  *
  * @param in
  * @throws IOException
  * @throws ClassNotFoundException
  */
 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
   int savedVersion = in.readInt();
   trackNumber = in.readInt();
   // recreate panels
   trackPanel = new JPanel();
   handlePanel = new HandlePanel(trackNumber);
   graphicsPanel = new GraphicsPanel();
   // set the background and foreground layers
   backgroundLayer = (BackgroundLayer) in.readObject();
   backgroundLayer.setTrack(this);
   foregroundLayer = (ForegroundLayer) in.readObject();
   foregroundLayer.setTrack(this);
   // initialize the track
   // add the tracks
   int layerCount = in.readInt();
   if (layerCount > 0) {
     layers = (TrackModel) in.readObject();
     // since the track field of layers is transient we have to set it
     for (Layer<?> currentLayer : layers) {
       currentLayer.setTrack(this);
     }
     setActiveLayer((Layer<?>) in.readObject());
   } else {
     layers = new TrackModel();
     layers.addListDataListener(this);
   }
   score = (TrackScore) in.readObject();
   // initialize the track
   initTrack();
   // restore the height of the track
   setPreferredHeight(in.readInt());
   if (savedVersion >= 1) {
     trackName = (String) in.readObject();
   }
 }
 @Override
 public void intervalRemoved(ListDataEvent e) {
   // case where the active layer was removed
   if (!layers.contains(activeLayer)) {
     setActiveLayer(null);
   }
   updateGraphicsPanelDrawers();
   getScore().autorescaleScoreAxis();
 }
 /**
  * Updates the list of drawers registered to the graphics panel. There are one drawer per layer
  * including the background and foreground layers that need to be registered.
  */
 private void updateGraphicsPanelDrawers() {
   if (layers
       == null) { // case where there is no other layer than the foreground and the background
     Drawer[] drawers = {backgroundLayer, foregroundLayer};
     graphicsPanel.setDrawers(drawers);
   } else { // case where there are other layers
     Drawer[] drawers = new Drawer[layers.size() + 2];
     drawers[0] = backgroundLayer;
     int i = 1;
     // we want to draw the layers in reverse order because the first layers
     // of the list should be on top
     for (int j = layers.size() - 1; j >= 0; j--) {
       Drawer currentDrawer = layers.getLayers()[j];
       drawers[i] = currentDrawer;
       i++;
     }
     drawers[i] = foregroundLayer;
     graphicsPanel.setDrawers(drawers);
   }
 }
 /**
  * Method used for serialization
  *
  * @param out
  * @throws IOException
  */
 private void writeObject(ObjectOutputStream out) throws IOException {
   out.writeInt(SAVED_FORMAT_VERSION_NUMBER);
   out.writeInt(trackNumber);
   out.writeObject(backgroundLayer);
   out.writeObject(foregroundLayer);
   // write the number of layers
   if ((layers == null) || layers.isEmpty()) {
     out.writeInt(0);
   } else {
     out.writeInt(layers.size());
     out.writeObject(layers);
     // make sure the active layer is not null
     if (activeLayer == null) {
       setActiveLayer(layers.getLayers()[0]);
     }
     out.writeObject(activeLayer);
   }
   out.writeObject(score);
   // save the height of the track
   out.writeInt(trackPanel.getHeight());
   if (SAVED_FORMAT_VERSION_NUMBER >= 1) {
     out.writeObject(getName());
   }
 }
  /**
   * Creates an instance of {@link Track}
   *
   * @param trackNumber number of the track
   */
  public Track(int trackNumber) {
    super();

    // create the panels
    trackPanel = new JPanel();
    handlePanel = new HandlePanel(trackNumber);
    graphicsPanel = new GraphicsPanel();

    // initializes the foreground and background drawer
    backgroundLayer = new BackgroundLayer(this);
    foregroundLayer = new ForegroundLayer(this);

    // set the track number
    this.trackNumber = trackNumber;

    // set the track score
    score = new TrackScore(this);

    // initializes the layer list
    layers = new TrackModel();
    layers.addListDataListener(this);

    initTrack();
  }