/**
   * Called when the table selection changes
   *
   * @param evt the event
   */
  @Override
  public void valueChanged(ListSelectionEvent evt) {
    // Check if we are in a quiescent state
    if (quiescent) {
      return;
    }

    if (!evt.getValueIsAdjusting()) {
      selectedWp = routeDetailTable.getSelectedRow();
      updateButtonEnabledState();
    }
  }
  /** Initializes the user interface */
  private void initGui() {
    Insets insets1 = new Insets(5, 5, 0, 5);
    Insets insets2 = new Insets(5, 25, 0, 5);
    Insets insets3 = new Insets(5, 5, 0, 0);
    Insets insets4 = new Insets(5, 0, 0, 5);
    Insets insets5 = new Insets(5, 5, 5, 5);
    Insets insets6 = new Insets(5, 25, 5, 5);
    Insets insets10 = new Insets(10, 10, 10, 10);

    JPanel content = new JPanel(new GridBagLayout());
    getContentPane().add(content);

    // ********************************
    // ** Route properties panel
    // ********************************

    JPanel routeProps = new JPanel(new GridBagLayout());
    routeProps.setBorder(new TitledBorder(new LineBorder(Color.black), "Route Properties"));
    content.add(
        routeProps, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets10, 0, 0));

    // Auto-completion
    List<String> strings = new ArrayList<>();
    strings.add("Copenhagen");
    strings.add("Oslo");
    AutoCompleteDecorator.decorate(originTxT, strings, false);
    AutoCompleteDecorator.decorate(destinationTxT, strings, false);

    // Column 1 widgets
    int gridY = 0;
    nameTxT.setEditable(!readOnlyRoute);
    nameTxT.getDocument().addDocumentListener(new TextFieldChangeListener(nameTxT));
    routeProps.add(
        new JLabel("Name:"),
        new GridBagConstraints(0, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));
    routeProps.add(
        fixSize(nameTxT, 120),
        new GridBagConstraints(1, gridY++, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));

    originTxT.setEditable(!readOnlyRoute);
    originTxT.getDocument().addDocumentListener(new TextFieldChangeListener(originTxT));
    routeProps.add(
        new JLabel("Origin:"),
        new GridBagConstraints(0, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));
    routeProps.add(
        fixSize(originTxT, 120),
        new GridBagConstraints(1, gridY++, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));

    destinationTxT.setEnabled(!readOnlyRoute);
    destinationTxT.getDocument().addDocumentListener(new TextFieldChangeListener(destinationTxT));
    routeProps.add(
        new JLabel("Destination:"),
        new GridBagConstraints(0, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));
    routeProps.add(
        fixSize(destinationTxT, 120),
        new GridBagConstraints(1, gridY++, 1, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));

    distanceTxT.setEditable(false);
    routeProps.add(
        new JLabel("Total Distance:"),
        new GridBagConstraints(0, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    routeProps.add(
        fixSize(distanceTxT, 120),
        new GridBagConstraints(1, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));

    // Column 2 widgets
    gridY = 0;
    int h = (int) departurePicker.getPreferredSize().getHeight();
    initDatePicker(departurePicker, departureSpinner);
    routeProps.add(
        new JLabel("Estimated Time of Departure:"),
        new GridBagConstraints(2, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets2, 0, 0));
    routeProps.add(
        fixSize(departurePicker, 120),
        new GridBagConstraints(3, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets3, 0, 0));
    routeProps.add(
        fixSize(departureSpinner, 60, h),
        new GridBagConstraints(4, gridY++, 1, 1, 0.0, 0.0, WEST, NONE, insets4, 0, 0));

    initDatePicker(arrivalPicker, arrivalSpinner);
    routeProps.add(
        new JLabel("Estimated Time of Arrival:"),
        new GridBagConstraints(2, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets2, 0, 0));
    routeProps.add(
        fixSize(arrivalPicker, 120),
        new GridBagConstraints(3, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets3, 0, 0));
    routeProps.add(
        fixSize(arrivalSpinner, 60, h),
        new GridBagConstraints(4, gridY++, 1, 1, 0.0, 0.0, WEST, NONE, insets4, 0, 0));

    inrouteTxT.setEditable(false);
    routeProps.add(
        new JLabel("Estimated Time in-route:"),
        new GridBagConstraints(2, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets2, 0, 0));
    routeProps.add(
        fixSize(inrouteTxT, 180),
        new GridBagConstraints(3, gridY++, 2, 1, 0.0, 0.0, WEST, NONE, insets1, 0, 0));

    etaCalculationTime.setEnabled(!readOnlyRoute);
    etaCalculationTime.addActionListener(this);
    routeProps.add(
        new JLabel("Calculate TTG/ETA using:"),
        new GridBagConstraints(2, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets6, 0, 0));
    routeProps.add(
        fixSize(etaCalculationTime, 180),
        new GridBagConstraints(3, gridY++, 2, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));

    allSpeeds.setEnabled(!readOnlyRoute);
    allSpeedsBtn.setEnabled(!readOnlyRoute);
    routeProps.add(
        new JLabel("Speed all legs: "),
        new GridBagConstraints(2, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets2, 0, 0));
    routeProps.add(
        fixSize(allSpeeds, 60),
        new GridBagConstraints(3, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets3, 0, 0));
    routeProps.add(
        fixSize(allSpeedsBtn, 60, h),
        new GridBagConstraints(4, gridY, 1, 1, 0.0, 0.0, WEST, NONE, insets4, 0, 0));

    routeProps.add(
        new JLabel(""),
        new GridBagConstraints(5, 0, 1, 1, 1.0, 0.0, WEST, HORIZONTAL, insets2, 0, 0));

    // ********************************
    // ** Route detail panel
    // ********************************

    routeTableModel = createRouteTableModel();
    routeDetailTable = new DeltaTable(routeTableModel, DELTA_START_COL_INDEX);
    routeDetailTable.setTableFont(routeDetailTable.getTableFont().deriveFont(10.0f));
    routeDetailTable.setNonEditableBgColor(
        UIManager.getColor("Table.background").darker().darker());
    routeDetailTable.addListSelectionListener(this);

    // Set the minimum column widths
    for (int x = 0; x < COL_MIN_WIDTHS.length; x++) {
      routeDetailTable.getColumn(x).setMinWidth(COL_MIN_WIDTHS[x]);
    }

    // Configure lock column
    routeDetailTable.fixColumnWidth(0, COL_MIN_WIDTHS[0]);
    routeDetailTable.getColumn(0).setCellRenderer(new LockTableCell.CustomBooleanCellRenderer());
    routeDetailTable.getColumn(0).setCellEditor(new LockTableCell.CustomBooleanCellEditor());

    // Configure ETA column
    routeDetailTable.getColumn(7).setCellEditor(new EtaEditor());

    // Configure heading column
    JComboBox<Heading> headingCombo = new JComboBox<>(Heading.values());
    headingCombo.setFont(headingCombo.getFont().deriveFont(10.0f));
    routeDetailTable.getColumn(10).setCellEditor(new DefaultCellEditor(headingCombo));

    JPanel routeTablePanel = new JPanel(new BorderLayout());
    routeTablePanel.add(routeDetailTable, BorderLayout.CENTER);
    routeTablePanel.setBorder(new TitledBorder(new LineBorder(Color.black), "Route Details"));
    content.add(
        routeTablePanel,
        new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, NORTHWEST, BOTH, insets10, 0, 0));

    // ********************************
    // ** Button panel
    // ********************************

    JPanel btnPanel = new JPanel(new GridBagLayout());
    content.add(
        btnPanel,
        new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, insets10, 0, 0));

    btnZoomToRoute.addActionListener(this);
    btnZoomToWp.addActionListener(this);
    btnDelete.addActionListener(this);
    btnActivate.addActionListener(this);
    btnClose.addActionListener(this);
    cbVisible.addActionListener(this);
    allSpeedsBtn.addActionListener(this);
    getRootPane().setDefaultButton(btnClose);
    btnPanel.add(
        btnZoomToRoute, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    btnPanel.add(
        btnZoomToWp, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    btnPanel.add(
        btnDelete, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    btnPanel.add(
        btnActivate, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    btnPanel.add(
        cbVisible, new GridBagConstraints(4, 0, 1, 1, 0.0, 0.0, WEST, NONE, insets5, 0, 0));
    btnPanel.add(btnClose, new GridBagConstraints(5, 0, 1, 1, 1.0, 0.0, EAST, NONE, insets5, 0, 0));
  }