Package jmt.gui.jsim.panels

Source Code of jmt.gui.jsim.panels.ClassesPanel

/**   
  * 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.jsim.panels;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.text.ParseException;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import jmt.framework.gui.table.editors.ButtonCellEditor;
import jmt.framework.gui.wizard.WizardPanel;
import jmt.gui.common.CommonConstants;
import jmt.gui.common.Defaults;
import jmt.gui.common.definitions.ClassDefinition;
import jmt.gui.common.definitions.SimulationDefinition;
import jmt.gui.common.distributions.Distribution;
import jmt.gui.common.editors.DistributionsEditor;
import jmt.gui.common.editors.ImagedComboBoxCellEditorFactory;
import jmt.gui.common.resources.JMTImageLoader;

/**
* Created by IntelliJ IDEA.
* User: OrsotronIII
* Date: 13-mag-2005
* Time: 14.43.32
* This panel provides functionality of editing and visualizing data about model's
* classes.
* Modified by Bertoli Marco 9-jan-2006  --> ComboBoxCellEditor
*/
public class ClassesPanel extends WizardPanel implements CommonConstants {

  //Interface containing values of main parameters to be set by user
  /*TODO: to enable this functionality, just put a constructor accepting a customized
  *JSIMDefault class as parameter, and then put a form to allow user to generate instances
  *of this class.*/
  //protected Defaults defaults = new Defaults(){};
  /**
   *
   */
  private static final long serialVersionUID = 1L;

  //Table containg class-set data
  protected ClassTable classTable;

  //ComboBox editor for station type
  protected ImagedComboBoxCellEditorFactory comboEditor = new ImagedComboBoxCellEditorFactory();

  //Button that allows to add classes one by one
  protected JButton addClass;

  //Component responsible of setting global number of classes at once
  protected JSpinner classNumSpinner = new JSpinner() {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    {
      addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          //stop editing text inside spinner
          try {
            classNumSpinner.commitEdit();
          } catch (ParseException pe) {
            //if string does not represent a number, return
            return;
          }
          //new number of classes
          int x = -1;
          try {
            x = ((Integer) classNumSpinner.getValue()).intValue();
          } catch (NumberFormatException nfe) {
          } catch (ClassCastException cce) {
          }
          //if new number is valid, proceed updating number
          if (x != -1) {
            setNumberOfClasses(x);
          } else {
            //otherwise, reset to 0
            classNumSpinner.setValue(new Integer(0));
          }
        }
      });
    }
  };

  //Interface linking to underlying implementation layer
  protected ClassDefinition data;

  //Index for temporary class name assignment
  protected int classNameIndex = 0;

  //deletion of classes after a multiple selection
  protected AbstractAction deleteSelectedClasses = new AbstractAction("Delete selected classes") {
    /**
    *
    */
    private static final long serialVersionUID = 1L;

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

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

  //deletion of one class
  protected AbstractAction deleteClass = new AbstractAction("") {
    /**
    *
    */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.SHORT_DESCRIPTION, "Delete");
      putValue(Action.SMALL_ICON, JMTImageLoader.loadImage("Delete"));
    }

    public void actionPerformed(ActionEvent e) {
      int index = classTable.getSelectedRow();
      if (index >= 0 && index < classTable.getRowCount()) {
        deleteClass(index);
      }
    }
  };

  //addition of a class one by one
  protected AbstractAction addNewClass = new AbstractAction("Add Class") {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.ALT_MASK));
      putValue(Action.SHORT_DESCRIPTION, "Adds a new class");
    }

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

  //editing of arrival time distribution
  protected AbstractAction editDistribution = new AbstractAction("Edit") {
    /**
    *
    */
    private static final long serialVersionUID = 1L;

    {
      putValue(Action.SHORT_DESCRIPTION, "Edits distribution parameters");
    }

    public void actionPerformed(ActionEvent e) {
      // ---- Bertoli Marco ----
      int index = classTable.getSelectedRow();
      if (index >= 0 && index < classTable.getRowCount()) {
        Object key = data.getClassKeys().elementAt(index);
        DistributionsEditor editor = DistributionsEditor.getInstance(ClassesPanel.this.getParent(), (Distribution) data
            .getClassDistribution(key));
        // Sets editor window title
        editor.setTitle("Editing " + data.getClassName(key) + " distribution...");
        // Shows editor window
        editor.show();
        // Sets new Distribution to selected class
        data.setClassDistribution(editor.getResult(), key);

        // Updates table view. This is needed as Distribution is not contained
        // into edited cell (but in its left one)
        classTable.repaint();
      }
      // ---- end ----
    }
  };

  /**Creates a new instance of <code>ClassesPanel</code> given a model definition.*/
  public ClassesPanel(ClassDefinition cd) {
    super();
    classTable = new ClassTable();
    initComponents();
    //forbid column to be moved
    classTable.getTableHeader().setReorderingAllowed(false);
    setData(cd);
  }

  /**Default constructor, used to extend this panel for JModel*/
  public ClassesPanel() {
    super();
  }

  /**Sets data model for this panel.
   * Instantly all of the panel components are assigned their specific value.
   * @param cd: data for class definition.*/
  public void setData(ClassDefinition cd) {
    data = cd;
    classTable.setModel(new ClassTableModel());
    classNumSpinner.setValue(new Integer(data.getClassKeys().size()));
    comboEditor.clearCache();
  }

  /**Gets data model for this panel.
   * @return : data for class definition.*/
  public ClassDefinition getData() {
    return data;
  }

  /**
   * called by the Wizard when the panel becomes active
   */
  @Override
  public void gotFocus() {
    comboEditor.clearCache();
  }

  //Builds internal structure of the panel. Sets up layout of components
  protected void initComponents() {
    //create margins for this panel.
    Box vBox = Box.createVerticalBox();
    Box hBox = Box.createHorizontalBox();
    vBox.add(Box.createVerticalStrut(20));
    vBox.add(hBox);
    vBox.add(Box.createVerticalStrut(20));
    hBox.add(Box.createHorizontalStrut(20));

    //build central panel
    JPanel componentsPanel = new JPanel(new BorderLayout());
    //new BoxLayout(componentsPanel, BoxLayout.Y_AXIS);

    //build upper part of central panel
    JPanel upperPanel = new JPanel(new BorderLayout());
    JLabel descrLabel = new JLabel(CLASSES_DESCRIPTION);
    //descrLabel.setMaximumSize(new Dimension(300, 1000));
    upperPanel.add(descrLabel, BorderLayout.CENTER);

    //build upper right corner of the main panel
    JPanel upRightPanel = new JPanel(new BorderLayout());
    addClass = new JButton(addNewClass);
    addClass.setMinimumSize(DIM_BUTTON_S);
    upRightPanel.add(addClass, BorderLayout.CENTER);

    //build spinner panel
    JPanel spinnerPanel = new JPanel();
    JLabel spinnerDescrLabel = new JLabel("Classes:");
    //rangesNumSpinner = new JSpinner();
    classNumSpinner.setPreferredSize(DIM_BUTTON_XS);
    spinnerPanel.add(spinnerDescrLabel);
    spinnerPanel.add(classNumSpinner);

    //add all panels to the mail panel
    upRightPanel.add(spinnerPanel, BorderLayout.SOUTH);
    upperPanel.add(upRightPanel, BorderLayout.EAST);
    componentsPanel.add(upperPanel, BorderLayout.NORTH);
    componentsPanel.add(new JScrollPane(classTable), BorderLayout.CENTER);
    hBox.add(componentsPanel);
    hBox.add(Box.createHorizontalStrut(20));
    this.setLayout(new GridLayout(1, 1));
    this.add(vBox);
  }

  //returns name to be displayed on the tab, when inserted in a wizard tabbed pane
  @Override
  public String getName() {
    return "Classes";
  }

  //adds a new class to the table and, simultaneously to the underlying model data structure
  protected void addClass() {
    data.addClass(Defaults.get("className") + (++classNameIndex), Defaults.getAsInteger("classType").intValue(), Defaults.getAsInteger(
        "classPriority").intValue(), Defaults.getAsInteger("classPopulation"), Defaults.getAsNewInstance("classDistribution"));
    refreshComponents();
  }

  //synchronizes components to display coherently global number of classes
  protected void refreshComponents() {
    classTable.tableChanged(new TableModelEvent(classTable.getModel()));
    try {
      classNumSpinner.setValue(new Integer(data.getClassKeys().size()));
    } catch (NumberFormatException nfe) {
    }
    if (data.getClassKeys().size() >= MAX_NUMBER_OF_CLASSES) {
      addClass.setEnabled(false);
    } else {
      addClass.setEnabled(true);
    }
  }

  /*delete a class from model given the index the class to be deleted is displayed at
  inside the table.*/
  protected void deleteClass(int index) {
    data.deleteClass(data.getClassKeys().get(index));
    refreshComponents();
  }

  /*Multiple deletion of classes. Indexes to ship call to precedent method, are retrieved
  through classtable methods (get selected rows)*/
  protected void deleteSelectedClasses() {
    int[] rows = classTable.getSelectedRows();
    for (int i = rows.length - 1; i >= 0; i--) {
      deleteClass(rows[i]);
    }
  }

  /*Modify global number of classes for this model all at once.*/
  protected void setNumberOfClasses(int newNumber) {
    /*If new number is greater than a certain number, don't do anything and cancel
    number modification inside spinner*/
    if (newNumber > MAX_NUMBER_OF_CLASSES) {
      setNumberOfClasses(MAX_NUMBER_OF_CLASSES);
      return;
    }
    /*If new number is not valid, reset to 0*/
    if (newNumber < 0) {
      setNumberOfClasses(0);
      return;
    }
    int oldNumber = data.getClassKeys().size();
    /*If new number is greater than former one, just add */
    if (newNumber > oldNumber) {
      for (int i = oldNumber; i < newNumber; i++) {
        addClass();
      }
    } else if (newNumber < oldNumber) {
      /*otherwise, just delete*/
      for (int i = oldNumber - 1; i >= newNumber; i--) {
        deleteClass(i);
      }
    }
    refreshComponents();
  }

  //---------------------------- Table containing classes parameters --------------------------
  /*Table that must display all of data about user classes. Customization of table settings is
  obtained via inheritation of <code>JTable</code> Class.*/

  protected class ClassTable extends JTable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /* for selection of class types. Must be inserted in ComboBoxCellEditor*/
    protected Object[] classTypes = new Object[] { "Closed", "Open" };

    /*This button allow a single userclass to be deleted directly from the table.
    Corresponding value contained into cell must be zero.*/
    public JButton deleteButton = new JButton() {
      /**
       *
       */
      private static final long serialVersionUID = 1L;

      {
        setAction(deleteClass);
        setFocusable(false);
      }
    };

    /*This button activates the distribution editor. Returning value must be sent
    to underlying model definition, and then diplayed in another column contained*/
    protected JButton editDistributionButton = new JButton() {
      /**
       *
       */
      private static final long serialVersionUID = 1L;

      {
        setText("Edit");
      }
    };

    /*Set of column dimensions*/
    protected int[] columnSizes = new int[] { 120, 50, 50, 50, 150, 38, 18 };

    //Sets a table model for visualization and editing of data
    public void setModel(ClassTableModel tabMod) {
      super.setModel(tabMod);
      sizeColumnsAndRows();
      setDefaultRenderer(String.class, new jmt.gui.exact.table.DisabledCellRenderer());
      setDefaultEditor(Object.class, new jmt.gui.exact.table.ExactCellEditor());
      setRowHeight(ROW_HEIGHT);
    }

    //returns a component to be contained inside a table column(or cell)
    @Override
    public TableCellRenderer getCellRenderer(int row, int column) {
      if (column == 1) {
        return comboEditor.getRenderer();
      } else if (column == 5) {
        /*if distribution column contains null value, no editor must be displayed,
        as this class is a closed one (e.g. described by population)*/
        if (getValueAt(row, column - 1) != null) {
          return new ButtonCellEditor(editDistributionButton);
        } else {
          return getDefaultRenderer(String.class);
        }
      }
      //Addition of column that contains delete buttons
      if (column == 6) {
        return new ButtonCellEditor(deleteButton);
      } else {
        return getDefaultRenderer(getModel().getColumnClass(column));
      }
    }

    /*returns customized editor for table cells.*/
    @Override
    public TableCellEditor getCellEditor(int row, int column) {
      if (column == 1) {
        return comboEditor.getEditor(classTypes);
      } else if (column == 5 && getValueAt(row, column - 1) != null) {
        return new ButtonCellEditor(new JButton(editDistribution));
      } else if (column == 6) {
        return new ButtonCellEditor(new JButton(deleteClass));
      } else {
        return super.getCellEditor(row, column);
      }
    }

    //set sizes for columns and rows of this table.
    protected void sizeColumnsAndRows() {
      for (int i = 0; i < columnSizes.length && i < getColumnCount(); i++) {
        this.getColumnModel().getColumn(i).setPreferredWidth(columnSizes[i]);
        if (i == columnSizes.length - 1) {
          //delete button and containing table cells as well, must be square
          this.getColumnModel().getColumn(i).setMaxWidth(columnSizes[i]);
          this.setRowHeight(columnSizes[i]);
        }
      }
    }
  }

  //------------------------------------Table model for classes panel --------------------------
  /*Table data model to implement customized data editing*/

  protected class ClassTableModel extends AbstractTableModel {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    //Names of columns contained in table. Columns containing buttons have empty names
    protected String[] columnNames = new String[] { "Name", "Type", "Priority", "Population", "Interarrival Time Distribution", "", "" };

    //Class declarations for this table's columns.
    protected Class[] colClasses = new Class[] { String.class, JComboBox.class, String.class, String.class, String.class, Object.class,
        JButton.class };

    /**Creates a new instance of class table model*/
    public ClassTableModel() {
      super();
    }

    /**returns number of rows to be displayed in the table. In this case, global
     * number of classes*/
    public int getRowCount() {
      if (data.getClassKeys() != null) {
        return data.getClassKeys().size();
      } else {
        return 0;
      }
    }

    /**Returns total number of columns*/
    public int getColumnCount() {
      return columnNames.length;
    }

    /**Returns name for each column (given its index) to be displayed
     * inside table header*/
    @Override
    public String getColumnName(int columnIndex) {
      if (columnIndex < columnNames.length) {
        return columnNames[columnIndex];
      } else {
        return null;
      }
    }

    /**Returns class describing data contained in specific column.*/
    @Override
    public Class getColumnClass(int columnIndex) {
      if (columnIndex < colClasses.length) {
        return colClasses[columnIndex];
      } else {
        return Object.class;
      }
    }

    /**Tells wether data contained in a specific cell(given row and column index)
     * is editable or not. In this case distribution column is not editable, as
     * editing functionality is implemented via edit button*/
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      if (columnIndex == 3 && (getValueAt(rowIndex, 1).equals("Open"))) {
        return false;
      }
      if (columnIndex == 5 && (getValueAt(rowIndex, 1).equals("Closed"))) {
        return false;
      }
      if (columnIndex == 4) {
        return false;
      }
      return true;
    }

    /**retrieves value to be displayed in table cell from the underlying model
     * data structure implementation.*/
    public Object getValueAt(int rowIndex, int columnIndex) {
      Object key = data.getClassKeys().get(rowIndex);
      switch (columnIndex) {
        case (0): {
          return data.getClassName(key);
        }
        case (1): {
          int type = data.getClassType(key);
          if (type == CLASS_TYPE_CLOSED) {
            return "Closed";
          } else if (type == CLASS_TYPE_OPEN) {
            return "Open";
          }
        }
        case (2): {
          return new Integer(data.getClassPriority(key));
        }
        case (3): {
          return data.getClassPopulation(key);
        }
        case (4): {
          return data.getClassDistribution(key);
        }
        default: {
          return null;
        }
      }
    }

    /**Puts edited values to the underlying data structure for model implementation*/
    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
      Object key = data.getClassKeys().get(rowIndex);
      switch (columnIndex) {
        case (0): {
          data.setClassName((String) aValue, key);
          break;
        }
        case (1): {
          if ((aValue).equals("Closed")) {
            data.setClassType(CLASS_TYPE_CLOSED, key);
          } else if ((aValue).equals("Open")) {
            data.setClassType(CLASS_TYPE_OPEN, key);
          }
          break;
        }
        case (2): {
          try {
            int priority = Integer.parseInt((String) aValue);
            if (priority >= 0) {
              data.setClassPriority(priority, key);
            }
          } catch (NumberFormatException nfe) {
          }
          break;
        }
        case (3): {
          try {
            Integer population = Integer.decode((String) aValue);
            if (population.intValue() > 0) {
              data.setClassPopulation(population, key);
            }
          } catch (NumberFormatException nfe) {
          }
          break;
        }/*case(5):{
                             data.setClassDistribution(aValue, key);
                             break;
                         }*/
      }
      /*if editing cell belongs to class type column, i must update population and
      distribution cells*/
      if (columnIndex == 1) {
        repaint();
      }
    }

  }

  /**
   * called by the Wizard before when switching to another panel
   */
  @Override
  public void lostFocus() {
    // Aborts editing of table
    TableCellEditor editor = classTable.getCellEditor();
    if (editor != null) {
      editor.stopCellEditing();
    }
    // Preloads jobs
    ((SimulationDefinition) data).manageJobs();
  }

}
TOP

Related Classes of jmt.gui.jsim.panels.ClassesPanel

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.