Package jmt.gui.exact.panels

Source Code of jmt.gui.exact.panels.StationsPanel$StationTableModel

/**   
  * Copyright (C) 2006, Laboratorio di Valutazione delle Prestazioni - Politecnico di Milano

  * 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 2 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, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */

package jmt.gui.exact.panels;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import jmt.analytical.SolverAlgorithm;
import jmt.framework.data.ArrayUtils;
import jmt.framework.gui.help.HoverHelp;
import jmt.framework.gui.table.editors.ButtonCellEditor;
import jmt.framework.gui.wizard.WizardPanel;
import jmt.gui.common.resources.JMTImageLoader;
import jmt.gui.exact.ExactConstants;
import jmt.gui.exact.ExactModel;
import jmt.gui.exact.ExactWizard;
import jmt.gui.exact.table.ComboBoxCell;
import jmt.gui.exact.table.ExactTable;
import jmt.gui.exact.table.ExactTableModel;
import jmt.gui.exact.table.ListOp;

/**

* @author alyf (Andrea Conti)
* Date: 11-set-2003
* Time: 23.48.19

*/

/**
* 2nd panel: stations number, names, types
*/
public final class StationsPanel extends WizardPanel implements ExactConstants, ForceUpdatablePanel {

  /**
   *
   */
  private static final long serialVersionUID = 1L;
  private ExactWizard ew;
  private HoverHelp help;
  private static final String helpText = "<html>In this panel you can define the number of stations in the system and their properties.<br><br>"
      + " To edit values, single-click on the desired cell"
      + " and start typing.<br> To select stations click or drag on the row headers.<br> <b>For a list of the available operations right-click"
      + " on the table</b>.<br>" + " Pressing DELETE removes all selected stations from the system.</html>";

  private int stations;
  private int pop;

  private String[] stationNames;
  private int[] stationTypes;
  private int nameCounter = 1;

  private List<ListOp> stationOps;
  private boolean hasDeletes;
  private boolean deleting = false;

  private JSpinner stationSpinner = new JSpinner(new SpinnerNumberModel(1, 1, MAX_STATIONS, 1));

  private StationTable stationTable;

  private ChangeListener spinnerListener = new ChangeListener() {
    public void stateChanged(ChangeEvent ce) {
      if (!deleting) {
        updateSizes();
      }
    }
  };

  private AbstractAction deleteStation = new AbstractAction("Delete selected stations") {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, false));
      putValue(Action.SHORT_DESCRIPTION, "Deletes selected stations from the system");
    }

    public void actionPerformed(ActionEvent e) {
      deleteSelectedStations();
    }
  };

  private AbstractAction deleteOneStation = new AbstractAction("") {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.SHORT_DESCRIPTION, "Deletes this station");
      putValue(Action.SMALL_ICON, JMTImageLoader.loadImage("Close"));
    }

    public void actionPerformed(ActionEvent e) {
    }
  };

  private AbstractAction addStation = new AbstractAction("New Station") {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.SHORT_DESCRIPTION, "Adds a new Station to Model");
    }

    public void actionPerformed(ActionEvent e) {
      addStation();
    }
  };

  public StationsPanel(ExactWizard ew) {
    this.ew = ew;
    help = ew.getHelp();

    stationOps = new ArrayList<ListOp>();
    sync();
    makeNames();
    initComponents();
  }

  private void sync() {

    hasDeletes = false;
    stationOps.clear();

    /* sync status with data object */
    /* arrays are copied to ensure data object consistency is preserved */
    ExactModel data = ew.getData();
    synchronized (data) {
      stations = data.getStations();
      pop = data.getMaxpop();
      stationNames = ArrayUtils.copy(data.getStationNames());
      stationTypes = ArrayUtils.copy(data.getStationTypes());
    }

    stationSpinner.setValue(new Integer(stations));
  }
 
  /**
   * if true, load dependent stations are allowed
   * (at the moment, only single class closed models allow LD stations)
   * @return true if the model allows load dependent. False otherwise.
   */
  private boolean isLdEnabled() {
    ExactModel data = ew.getData();
    return data.isClosed() && !data.isMultiClass() && data.getAlgorithmType().supportLoadDependent() && !data.isWhatifAlgorithms();
  }

  @Override
  public void gotFocus() {
    sync();
    stationTable.update();
  }

  @Override
  public void lostFocus() {
    commit();
    //release();
  }

  /**
   * make up names for null entries
   */
  private void makeNames() {
    for (int i = 0; i < stationNames.length; i++) {
      if (stationNames[i] == null) {
        stationNames[i] = "Station" + (++nameCounter);
      }
    }
  }

  /**
   * resize internal data structures according to new values. intended to be called from a listener.
   */
  private void updateSizes() {
    setNumberOfStations(((Integer) stationSpinner.getValue()).intValue());
  }

  private void addStation() {
    setNumberOfStations(stations + 1);
  }

  private void setNumberOfStations(int number) {
    stationTable.stopEditing();
    stations = number;

    stationNames = ArrayUtils.resize(stationNames, stations, null);
    makeNames();

    stationTypes = ArrayUtils.resize(stationTypes, stations, STATION_LI);

    stationTable.update();
    if (!deleting) {
      stationOps.add(ListOp.createResizeOp(stations));
    }

    stationSpinner.setValue(new Integer(stations));
    stationTable.updateDeleteCommand();
  }

  /**
   * Set up the panel contents and layout
   */
  private void initComponents() {
    stationSpinner.addChangeListener(spinnerListener);

    stationTable = new StationTable();

    /* and now some Box black magic */

    Box stationSpinnerBox = Box.createHorizontalBox();
    //OLD
    //DEK (Federico Granata) 26-09-2003
    //JLabel spinnerLabel = new JLabel("<html><font size=\"4\">Set the number of stations (1-" + MAX_STATIONS + "):</font></html>");
    //NEW
    //@author Stefano
    JLabel spinnerLabel = new JLabel(DESCRIPTION_STATIONS);

    //spinnerLabel.setMaximumSize(new Dimension(300, 18));
    stationSpinnerBox.add(spinnerLabel);
    stationSpinnerBox.add(Box.createHorizontalStrut(10));
    Box numberBox = Box.createVerticalBox();

    JPanel spinnerPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    JLabel numberLabel = new JLabel("Number:");
    stationSpinner.setMaximumSize(new Dimension(600, 18));
    spinnerPanel.add(numberLabel);
    spinnerPanel.add(stationSpinner);
    numberBox.add(spinnerPanel);

    numberBox.add(new JButton(addStation));

    numberBox.setMaximumSize(new Dimension(150, 50));

    stationSpinnerBox.add(numberBox);
    //END

    Box stationBox = Box.createVerticalBox();
    stationBox.add(Box.createVerticalStrut(20));
    stationBox.add(stationSpinnerBox);
    stationBox.add(Box.createVerticalStrut(10));
    JScrollPane stationTablePane = new JScrollPane(stationTable);
    stationTablePane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    stationTablePane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    stationBox.add(stationTablePane);
    stationBox.add(Box.createRigidArea(new Dimension(10, 20)));

    Box totalBox = Box.createHorizontalBox();
    totalBox.add(Box.createHorizontalStrut(20));
    totalBox.add(stationBox);
    totalBox.add(Box.createHorizontalStrut(20));

    setLayout(new BorderLayout());
    add(totalBox, BorderLayout.CENTER);

  }

  @Override
  public String getName() {
    return "Stations";
  }

  private void commit() {
    if (stationSpinner.getEditor().getComponent(0).hasFocus()) {
      try {
        stationSpinner.commitEdit();
        updateSizes();
      } catch (java.text.ParseException e) {
      }
    }

    stationTable.stopEditing();

    ExactModel data = ew.getData();
    synchronized (data) {

      if (hasDeletes) {
        playbackStationOps(data); //play back ops on the data object
      } else {
        data.resize(stations, data.getClasses());
      }
      data.setStationNames(stationNames);
      data.setStationTypes(stationTypes);

      //NEW
      //@author Stefano Omini
      sync();
      //end NEW
    }

  }

  @Override
  public boolean canFinish() {
    return checkLD() && !areThereDuplicates();
  }

  private void deleteSelectedStations() {
    int[] selectedRows = stationTable.getSelectedRows();
    int nrows = selectedRows.length;
    if (nrows == 0) {
      return;
    }
    int left = stationTable.getRowCount() - nrows;
    if (left < 1) {
      stationTable.removeRowSelectionInterval(selectedRows[nrows - 1], selectedRows[nrows - 1]);
      deleteSelectedStations();
      return;
    }
    deleteStations(selectedRows);
  }

  private void deleteStations(int[] idx) {
    deleting = true;
    Arrays.sort(idx);
    for (int i = idx.length - 1; i >= 0; i--) {
      deleteStation(idx[i]);
    }
    updateSizes();
    deleting = false;
  }

  private void deleteStation(int i) {
    stations--;
    stationSpinner.setValue(new Integer(stations));

    stationNames = ArrayUtils.delete(stationNames, i);
    stationTypes = ArrayUtils.delete(stationTypes, i);

    stationOps.add(ListOp.createDeleteOp(i));
    hasDeletes = true;

  }

  private void playbackStationOps(ExactModel data) {
    for (int i = 0; i < stationOps.size(); i++) {
      ListOp lo = stationOps.get(i);
      if (lo.isDeleteOp()) {
        data.deleteStation(lo.getData());
      }
      if (lo.isResizeOp()) {
        data.resize(lo.getData(), data.getClasses());
      }

    }
  }

  @Override
  public boolean canGoBack() {
    checkLD();
    if (areThereDuplicates()) {
      return false;
    }
    return true;
  }

  @Override
  public boolean canGoForward() {
    checkLD();
    if (areThereDuplicates()) {
      return false;
    }
    return true;
  }

  /**
   * @return true if the system contains LD stations
   */
  private boolean isLD() {
    for (int i = 0; i < stations; i++) {
      if (stationTypes[i] == STATION_LD) {
        return true;
      }
    }
    return false;
  }

  //checks population of classes for ld stations
  private boolean checkLD() {
    stationTable.stopEditing();
    if (pop < 1 && isLD()) {
      JOptionPane
          .showMessageDialog(
              this,
              "<html><center>A system with zero customers cannot have load dependent stations.<br>Increase the number of customers or remove all load dependent stations.</center></html>",
              "Warning", JOptionPane.WARNING_MESSAGE);
      return false;
    }
    return true;
  }

  //checks for presence of classes with same name
  private boolean areThereDuplicates() {

    boolean thereAreDupl = false;
    for (int i = 0; i < stationNames.length; i++) {
      for (int j = i + 1; j < stationNames.length; j++) {
        thereAreDupl = thereAreDupl || stationNames[i].equalsIgnoreCase(stationNames[j]);
      }
    }
    if (thereAreDupl) {
      JOptionPane.showMessageDialog(this,
          "<html><center>Two or more stations in this system are identified by the same name.<br>Please modify names.</center></html>",
          "Warning", JOptionPane.WARNING_MESSAGE);
      return true;
    } else {
      return false;
    }
  }

  @Override
  public void help() {
    JOptionPane.showMessageDialog(this, helpText, "Help", JOptionPane.INFORMATION_MESSAGE);

  }

  //NEW Federico Dall'Orso
  //Methods added to implement forcing of data refresh
  public void retrieveData() {
    sync();
  }

  public void commitData() {
    commit();
  }

  //END

  /* ------------------------------------------------------------------
     The StationTable is a fairly complex object that would be probably better of as an outer class.
     However, it is very specialized and it needs access to the data structures of the StationsPanel,
     so having it as an inner class is *much* more practical
     ------------------------------------------------------------------
     */

  /**
   * the nifty station table
   */
  private class StationTable extends ExactTable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private TableCellEditor LD_disabled_StationTypeEditor, LD_enabled_StationTypeEditor;
    //BEGIN Federico Dall'Orso 8/3/2005
    //NEW
    private ComboBoxCell LD_disabled_StationTypeCell, LD_enabled_StationTypeCell;
    //14/3/2005
    private JButton deleteButton;
    private ButtonCellEditor deleteButtonCellRenderer;

    //END Federico Dall'Orso

    StationTable() {
      super(new StationTableModel());

      //BEGIN Federico Dall'Orso 8/3/2005
      //station type cell renderers
      //NEW
      LD_disabled_StationTypeCell = new ComboBoxCell(STATION_TYPENAMES);
      LD_enabled_StationTypeCell = new ComboBoxCell(STATION_TYPENAMES_LD_ENABLED);
      //14/3/2005
      deleteButton = new JButton(deleteOneStation);
      deleteButtonCellRenderer = new ButtonCellEditor(deleteButton);
      enableDeletes();
      rowHeader.setRowHeight(18);
      setRowHeight(18);
      //END Federico Dall'Orso

      /* a station type cell editor for open/mixed systems */
      JComboBox stationTypeBox = new JComboBox(STATION_TYPENAMES);
      stationTypeBox.setEditable(false);
      LD_disabled_StationTypeEditor = new DefaultCellEditor(stationTypeBox);

      /* a station type cell editor for closed systems */
      JComboBox LD_enabled_StationTypeBox = new JComboBox(STATION_TYPENAMES_LD_ENABLED);
      LD_enabled_StationTypeBox.setEditable(false);
      LD_enabled_StationTypeEditor = new DefaultCellEditor(LD_enabled_StationTypeBox);

      setColumnSelectionAllowed(false);
      setRowSelectionAllowed(true);

      setDisplaysScrollLabels(true);

      installKeyboardAction(getInputMap(), getActionMap(), deleteStation);
      mouseHandler = new ExactTable.MouseHandler(makeMouseMenu());
      mouseHandler.install();

      help.addHelp(this,
          "Click or drag to select stations; to edit data single-click and start typing. Right-click for a list of available operations");
      help.addHelp(moreRowsLabel, "There are more stations: scroll down to see them");
      help.addHelp(selectAllButton, "Click to select all stations");
      tableHeader.setToolTipText(null);
      rowHeader.setToolTipText(null);
      help.addHelp(rowHeader, "Click, SHIFT-click or drag to select stations");
    }

    //BEGIN Federico Dall'Orso 14/3/2005
    /*enables deleting operations with last column's button*/
    private void enableDeletes() {
      deleteOneStation.setEnabled(stations > 1);
      /*It seems the only way to implement row deletion...*/
      this.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
          if ((columnAtPoint(e.getPoint()) == getColumnCount() - 1) && getRowCount() > 1) {
            setRowSelectionInterval(rowAtPoint(e.getPoint()), rowAtPoint(e.getPoint()));
            deleteSelectedStations();
          }
        }
      });
      getColumnModel().getColumn(getColumnCount() - 1).setMinWidth(20);
      getColumnModel().getColumn(getColumnCount() - 1).setMaxWidth(20);
    }

    //END Federico Dall'Orso 14/3/2005

    @Override
    protected void installKeyboard() {
    }

    @Override
    protected void installMouse() {
    }

    @Override
    protected JPopupMenu makeMouseMenu() {
      JPopupMenu menu = new JPopupMenu();
      menu.add(deleteStation);
      return menu;
    }

    /**
     * Overridden to ensure proper handling of station type column
     */
    @Override
    public TableCellEditor getCellEditor(int row, int column) {
      if (column == 1) { //station type
        /* select the right editor */

        if (isLdEnabled()) {
          return LD_enabled_StationTypeEditor;
        } else {
          return LD_disabled_StationTypeEditor;
        }
      } else {
        return super.getCellEditor(row, column);
      }
    }

    //BEGIN Federico Dall'Orso 8/3/2005
    //NEW
    /**Returns combobox-styled cellrenderer if a multiple choice cell is to be rendered.
     * @return cell renderer*/
    @Override
    public TableCellRenderer getCellRenderer(int row, int column) {
      //if this is type column, I must render it as a combo box instead of a jtextfield
      if (column == 1) {
        if (isLdEnabled()) {
          return LD_enabled_StationTypeCell;
        } else {
          return LD_disabled_StationTypeCell;
        }
      } else if (column == getColumnCount() - 1) {
        return deleteButtonCellRenderer;
      } else {
        return new DefaultTableCellRenderer();
      }
    }

    //END Federico Dall'Orso 8/3/2005

    //BEGIN Federico Dall'Orso 14/3/2005
    //NEW
    //Updates appearence of last column's buttons
    void updateDeleteCommand() {
      deleteOneStation.setEnabled(stations > 1);
      getColumnModel().getColumn(getColumnCount() - 1).setMinWidth(20);
      getColumnModel().getColumn(getColumnCount() - 1).setMaxWidth(20);
    }

    //END Federico Dall'Orso 14/3/2005

    @Override
    protected void updateActions() {
      deleteStation.setEnabled(stations > 1 && getSelectedRowCount() > 0);
      deleteOneStation.setEnabled(stations > 1);
    }

  }

  /**
   * the model backing the station table
   */
  private class StationTableModel extends ExactTableModel {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private Object[] prototypes = { "10000", new String(new char[15]), new String(new char[15]), "" };

    @Override
    public Object getPrototype(int columnIndex) {
      return prototypes[columnIndex + 1];
    }

    public int getRowCount() {
      return stations;
    }

    public int getColumnCount() {
      return 3;
    }

    @Override
    public String getColumnName(int index) {
      switch (index) {
        case 0:
          return "Name";
        case 1:
          return "Type";
        default:
          return null;
      }
    }

    @Override
    protected Object getRowName(int rowIndex) {
      return new Integer(rowIndex + 1);
    }

    @Override
    protected Object getValueAtImpl(int rowIndex, int columnIndex) {
      switch (columnIndex) {
        case 0://name
          return stationNames[rowIndex];
        case 1://type
          return STATION_TYPENAMES_LD_ENABLED[stationTypes[rowIndex]];
        default:
          return null;
      }
    }

    @Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
      switch (columnIndex) {
        case 0: //name
          stationNames[rowIndex] = (String) value;
          break;
        case 1: //type
          for (int i = 0; i < STATION_TYPENAMES_LD_ENABLED.length; i++) {
            if (value == STATION_TYPENAMES_LD_ENABLED[i]) { //literal strings are canonical objects, hence == is ok
              stationTypes[rowIndex] = i;
              break;
            }
          }
          boolean isLd = isLD();
          ew.updateAlgoPanel(null, null, null, isLd);
          if (isLd) {
            ew.getData().setAlgorithmType(SolverAlgorithm.EXACT);
          }
          break;
        default:
      }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      switch (columnIndex) {
        case 0:
        case 1:
          return true;
        default:
          return false;
      }
    }
  }

}
TOP

Related Classes of jmt.gui.exact.panels.StationsPanel$StationTableModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.