All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentcs.kernelcontrolcenter.vehicles.VehicleTableModel Maven / Gradle / Ivy

/**
 * Copyright (c) The openTCS Authors.
 *
 * This program is free software and subject to the MIT license. (For details,
 * see the licensing information (LICENSE.txt) you should have received with
 * this copy of the software.)
 */
package org.opentcs.kernelcontrolcenter.vehicles;

import static java.util.Objects.requireNonNull;
import static org.opentcs.kernelcontrolcenter.I18nKernelControlCenter.BUNDLE_PATH;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import org.opentcs.components.kernel.services.VehicleService;
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
import org.opentcs.drivers.vehicle.management.VehicleAttachmentInformation;
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
import org.opentcs.util.CallWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A model for displaying a list/table of vehicles in the kernel GUI.
 */
public class VehicleTableModel
    extends
      AbstractTableModel
    implements
      PropertyChangeListener {

  /**
   * This class's logger.
   */
  private static final Logger LOG = LoggerFactory.getLogger(VehicleTableModel.class);
  /**
   * This class's resource bundle.
   */
  private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(BUNDLE_PATH);
  /**
   * The column names.
   */
  private static final String[] COLUMN_NAMES
      = new String[]{
          BUNDLE.getString("vehicleTableModel.column_vehicle.headerText"),
          BUNDLE.getString("vehicleTableModel.column_state.headerText"),
          BUNDLE.getString("vehicleTableModel.column_adapter.headerText"),
          BUNDLE.getString("vehicleTableModel.column_enabled.headerText"),
          BUNDLE.getString("vehicleTableModel.column_position.headerText")
      };
  /**
   * The column classes.
   */
  private static final Class[] COLUMN_CLASSES
      = new Class[]{
          String.class,
          String.class,
          VehicleCommAdapterDescription.class,
          Boolean.class,
          String.class
      };
  /**
   * The index of the column showing the vehicle name.
   */
  private static final int VEHICLE_COLUMN = 0;
  /**
   * The index of the column showing the vehicle state.
   */
  private static final int STATE_COLUMNN = 1;
  /**
   * The index of the column showing the associated adapter.
   */
  private static final int ADAPTER_COLUMN = 2;
  /**
   * The index of the column showing the adapter's enabled state.
   */
  private static final int ENABLED_COLUMN = 3;
  /**
   * The index of the column showing the vehicle's current position.
   */
  private static final int POSITION_COLUMN = 4;
  /**
   * The identifier for the adapter column.
   */
  private static final String ADAPTER_COLUMN_IDENTIFIER = COLUMN_NAMES[ADAPTER_COLUMN];
  /**
   * The identifier for the position column.
   */
  private static final String POSITION_COLUMN_IDENTIFIER = COLUMN_NAMES[POSITION_COLUMN];
  /**
   * The vehicles we're controlling.
   */
  private final List entries = new ArrayList<>();
  /**
   * The vehicle service used for interactions.
   */
  private final VehicleService vehicleService;
  /**
   * The call wrapper to use for service calls.
   */
  private final CallWrapper callWrapper;

  /**
   * Creates a new instance.
   *
   * @param vehicleService The vehicle service used for interactions.
   * @param callWrapper The call wrapper to use for service calls.
   */
  public VehicleTableModel(
      VehicleService vehicleService,
      CallWrapper callWrapper
  ) {
    this.vehicleService = requireNonNull(vehicleService, "vehicleService");
    this.callWrapper = requireNonNull(callWrapper, "callWrapper");
  }

  /**
   * Returns the identifier for the adapter column.
   *
   * @return The identifier for the adapter column.
   */
  public static String adapterColumnIdentifier() {
    return ADAPTER_COLUMN_IDENTIFIER;
  }

  /**
   * Returns the identifier for the position column.
   *
   * @return The identifier for the position column.
   */
  public static String positionColumnIdentifier() {
    return POSITION_COLUMN_IDENTIFIER;
  }

  /**
   * Adds a new entry to this model.
   *
   * @param newEntry The new entry.
   */
  public void addData(LocalVehicleEntry newEntry) {
    entries.add(newEntry);
    fireTableRowsInserted(entries.size(), entries.size());
  }

  /**
   * Returns the vehicle entry at the given row.
   *
   * @param row The row.
   * @return The entry at the given row.
   */
  public LocalVehicleEntry getDataAt(int row) {
    if (row >= 0) {
      return entries.get(row);
    }
    else {
      return null;
    }
  }

  @Override
  public int getRowCount() {
    return entries.size();
  }

  @Override
  public int getColumnCount() {
    return COLUMN_NAMES.length;
  }

  @Override
  public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    LocalVehicleEntry entry = entries.get(rowIndex);
    switch (columnIndex) {
      case ADAPTER_COLUMN:
        break;
      case ENABLED_COLUMN:
        setEnabledState((boolean) aValue, entry);
        break;
      case POSITION_COLUMN:
        break;
      default:
        LOG.warn("Unhandled column index: {}", columnIndex);
    }
  }

  @Override
  public Object getValueAt(int rowIndex, int columnIndex) {
    if (rowIndex >= entries.size()) {
      return null;
    }

    LocalVehicleEntry entry = entries.get(rowIndex);

    switch (columnIndex) {
      case VEHICLE_COLUMN:
        return entry.getVehicleName();
      case STATE_COLUMNN:
        return getVehicleState(entry);
      case ADAPTER_COLUMN:
        return entry.getAttachmentInformation().getAttachedCommAdapter();
      case ENABLED_COLUMN:
        return entry.getProcessModel().isCommAdapterEnabled();
      case POSITION_COLUMN:
        return entry.getProcessModel().getPosition();
      default:
        LOG.warn("Unhandled column index: {}", columnIndex);
        return "Invalid column index " + columnIndex;
    }
  }

  @Override
  public String getColumnName(int columnIndex) {
    try {
      return COLUMN_NAMES[columnIndex];
    }
    catch (ArrayIndexOutOfBoundsException exc) {
      LOG.warn("Invalid columnIndex", exc);
      return "Invalid column index " + columnIndex;
    }
  }

  @Override
  public Class getColumnClass(int columnIndex) {
    return COLUMN_CLASSES[columnIndex];
  }

  @Override
  public boolean isCellEditable(int rowIndex, int columnIndex) {
    switch (columnIndex) {
      case ADAPTER_COLUMN:
        return true;
      case ENABLED_COLUMN:
        return true;
      case POSITION_COLUMN:
        LocalVehicleEntry entry = entries.get(rowIndex);
        return entry.getAttachedCommAdapterDescription().isSimVehicleCommAdapter()
            && entry.getProcessModel().isCommAdapterEnabled();
      default:
        return false;
    }
  }

  /**
   * Returns a list containing the vehicle models associated with this model.
   *
   * @return A list containing the vehicle models associated with this model.
   */
  public List getVehicleEntries() {
    return entries;
  }

  @Override
  public void propertyChange(PropertyChangeEvent evt) {
    if (!(evt.getSource() instanceof LocalVehicleEntry)) {
      return;
    }

    if (!isRelevantUpdate(evt)) {
      return;
    }

    LocalVehicleEntry entry = (LocalVehicleEntry) evt.getSource();
    for (int index = 0; index < entries.size(); index++) {
      if (entry == entries.get(index)) {
        int myIndex = index;
        SwingUtilities.invokeLater(() -> fireTableRowsUpdated(myIndex, myIndex));
      }
    }
  }

  private void setEnabledState(boolean enabled, LocalVehicleEntry entry) {
    try {
      if (enabled) {
        callWrapper.call(
            () -> vehicleService.enableCommAdapter(
                entry.getAttachmentInformation().getVehicleReference()
            )
        );
      }
      else {
        callWrapper.call(
            () -> vehicleService.disableCommAdapter(
                entry.getAttachmentInformation().getVehicleReference()
            )
        );
      }
    }
    catch (Exception ex) {
      LOG.warn("Error enabling/disabling comm adapter for {}", entry.getVehicleName(), ex);
    }
  }

  private String getVehicleState(LocalVehicleEntry entry) {
    return entry.getProcessModel().getState().name();
  }

  private boolean isRelevantUpdate(PropertyChangeEvent evt) {
    if (Objects.equals(
        evt.getPropertyName(),
        LocalVehicleEntry.Attribute.ATTACHMENT_INFORMATION.name()
    )) {
      VehicleAttachmentInformation oldInfo = (VehicleAttachmentInformation) evt.getOldValue();
      VehicleAttachmentInformation newInfo = (VehicleAttachmentInformation) evt.getNewValue();
      return !oldInfo.getAttachedCommAdapter().equals(newInfo.getAttachedCommAdapter());
    }
    if (Objects.equals(
        evt.getPropertyName(),
        LocalVehicleEntry.Attribute.PROCESS_MODEL.name()
    )) {
      VehicleProcessModelTO oldTo = (VehicleProcessModelTO) evt.getOldValue();
      VehicleProcessModelTO newTo = (VehicleProcessModelTO) evt.getNewValue();
      return oldTo.isCommAdapterEnabled() != newTo.isCommAdapterEnabled()
          || oldTo.getState() != newTo.getState()
          || !Objects.equals(oldTo.getPosition(), newTo.getPosition());
    }
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy