ConfigWindow.java

/*
 * $RCSfile: ConfigWindow.java,v $
 * $Id: ConfigWindow.java,v 1.6 1998/11/30 02:21:07 devnull Exp $
 * by Lee Wilson, http://www.ad1440.net/~devnull
 * Development started on 1998 10 01
 * (c) Devnull Software, LLC. (http://www.devnullsoftware.com)
 */

package com.devnullsoftware.config;

/**
 * Comfigurable Component System Window.
 *
 * @version 1.0 $Date$
 * @author Lee Wilson (devnull@ad1440.net)
 */

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import matthew.awt.StrutLayout;
import com.devnullsoftware.objlist.*;

public class ConfigWindow 
  extends JFrame
  implements ActionListener, ChangeListener, Serializable
{
  //-------------------------------------------------------------------
  // Global Constants
  //


  //-------------------------------------------------------------------
  // Instance Variables
  //
  private Configable pData;
  private Objlist pConfigComponentList;
  private int iMaxPoints;
  private int iSpentPoints;
  private transient JLabel pMaxPointsLabel;
  private transient JLabel pAvailPointsLabel;
  private transient JLabel pSpentPointsLabel;
  private transient JLabel pErrorLabel;
  private String sErrorText = null;
  private boolean bInChange = false;


  //-------------------------------------------------------------------
  // Constructors
  //
  public ConfigWindow (Configable pData)  {
    super ("Config Window");
    this.pData = pData;
    iMaxPoints = 0;
    init();
  }

  public ConfigWindow (Configable pData, int iMaxPoints)  {
    super ("Config Window");
    this.pData = pData;
    this.iMaxPoints = iMaxPoints;
    init();
  }

  private void init ()  {
    int i;
    Vector pParameters = pData.getParams();
    int iNumTabs = 0;
    try  {
      iNumTabs = ((Integer)pParameters.elementAt(0)).intValue();
    }
    catch (ClassCastException e)  {
      System.out.println("blah 1");
    }
    ConfigComponent cc;
    JPanel [] pTabPanel;
    StrutLayout [] pTabLayout;
    pConfigComponentList = new Objlist();

    JPanel pMainPanel = new JPanel(new BorderLayout());
    JPanel pPointsPanel;
    if (iMaxPoints > 0)  {
      pPointsPanel = new JPanel(new BorderLayout());
      JPanel pPointLabelPanel = new JPanel();
      pMaxPointsLabel = new JLabel();
      pAvailPointsLabel = new JLabel();
      pSpentPointsLabel = new JLabel();
      pErrorLabel = new JLabel();
      pPointLabelPanel.add(pMaxPointsLabel);
      pPointLabelPanel.add(pAvailPointsLabel);
      pPointLabelPanel.add(pSpentPointsLabel);
      pPointsPanel.add ("Center", pPointLabelPanel);
      pPointsPanel.add ("North", pErrorLabel);
      updatePointLabels();
      pMainPanel.add("North", pPointsPanel);
    }
    JPanel pButtonPanel = new JPanel();
    pButtonPanel.add(button("Ok"));
    pButtonPanel.add(button("Cancel"));
    JTabbedPane pMainTabPanel = new JTabbedPane();
    JScrollPane pTabScrollPane = new JScrollPane(pMainTabPanel);
    pMainPanel.add("Center", pTabScrollPane);
    pMainPanel.add("South", pButtonPanel);
    getContentPane().add(pMainPanel);
    pTabPanel = new JPanel [iNumTabs];
    pTabLayout = new StrutLayout [iNumTabs];

    Vector pTitles = null;
    try  {
      pTitles = (Vector)pParameters.elementAt(1);
    }
    catch (ClassCastException e)  {
      System.out.println("blah 2");
    }
    for (i = 0; i < iNumTabs; i++)  {
      Vector pItems = null;
      try  {
	pItems = (Vector)pParameters.elementAt(i+2);
      }
      catch (ClassCastException e)  {
	System.out.println("blah 3");
      }
      catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("ArrayIndex out of bounds: i == "+i+", iNumTabs == "+iNumTabs);
      }
      pTabLayout[i] = new StrutLayout();
      pTabPanel[i] = new JPanel(pTabLayout[i]);
      try  {
	pMainTabPanel.addTab((String)pTitles.elementAt(i), pTabPanel[i]);
      }
      catch (ClassCastException e)  {
	System.out.println("blah 4");
      }
      JLabel pNameLabel = null;
      JComponent pPreviousComponent = null;
      JComponent pCurrentComponent = null;
      JScrollPane pScrollPane = null;
      StrutLayout.SizeGroup pLabelSizeGroup = pTabLayout[i].createSizeGroup();
      StrutLayout.SizeGroup pValueSizeGroup = pTabLayout[i].createSizeGroup();
      for (Enumeration enum = pItems.elements() ;
	   enum.hasMoreElements() ;) {
	cc = null;
	Object blah = null;
	try  {
	  blah = enum.nextElement();
	  cc = (ConfigComponent)blah;
	}
	catch (ClassCastException e)  {
	  System.out.println("blah 5\n");
	}
	try  {
	  pConfigComponentList.add(cc);
	}
	catch (Exception e)  {
	  System.out.println("blah 7\n");
	}
	pNameLabel = new JLabel(cc.getName());
	pLabelSizeGroup.add(pNameLabel, StrutLayout.SIZE_WIDTH);
	pValueSizeGroup.add((JComponent)cc.getAWTItem(),
                            StrutLayout.SIZE_WIDTH);
	switch (cc.getComponentType())  {
	case ConfigComponent.TEXTAREA:
	  pScrollPane = new JScrollPane ((JTextArea)cc.getAWTItem());
	  pCurrentComponent = pScrollPane;
	  break;
	default:
	  pCurrentComponent = (JComponent)cc.getAWTItem();
	  break;
	}
	if (pPreviousComponent == null)  {
	  pTabPanel[i].add(pCurrentComponent);
	}
	else  {
	  pTabPanel[i].add(pCurrentComponent,
			   new StrutLayout.StrutConstraint
			   (pPreviousComponent,
			    StrutLayout.BOTTOM_LEFT,
			    StrutLayout.TOP_LEFT,
			    StrutLayout.SOUTH));
	}
	pPreviousComponent = pCurrentComponent;
	pTabPanel[i].add(pNameLabel,
			 new StrutLayout.StrutConstraint
			 (pCurrentComponent,
			  StrutLayout.MID_LEFT,
			  StrutLayout.MID_RIGHT,
			  StrutLayout.WEST));
	if (iMaxPoints > 0)  {
	  switch (cc.getComponentType())  {
	  case ConfigComponent.CHOICE2:
	    {
	      JComboBox2 pCB2 = (JComboBox2)cc.getAWTItem();
	      if (pCB2.getSelectedPointValue() != JComboBox2.NO_ASSIGNED_VALUE) {
		iSpentPoints += pCB2.getSelectedPointValue();
		pCB2.setPrevSelectedIndex (pCB2.getSelectedIndex());
		pCB2.addActionListener(this);
		updatePointLabels();
	      }
	    }
	    break;
	  case ConfigComponent.CHECKBOX2:
	    {
	      JCheckBox2 pCB2 = (JCheckBox2)cc.getAWTItem();
	      if (pCB2.getPointValue() != JCheckBox2.NO_ASSIGNED_VALUE) {
		if (pCB2.isSelected())  {
		  iSpentPoints += pCB2.getPointValue();
		  updatePointLabels();
		}
		pCB2.addChangeListener (this);
	      }
	    }
	    break;
	  default:
	    break;
	  }
	}
      }
      
    }
    
    setSize(500,400);
    pack();
    setVisible(true);
    //    setDoubleBuffered(false);
  }


  //-------------------------------------------------------------------
  // Accessors & Mutators
  //


  //-------------------------------------------------------------------
  // Security
  //


  //-------------------------------------------------------------------
  // Methods
  //
  public JButton button (String label)  {
    JButton b = new JButton(label);
    b.addActionListener(this);
    return (b);
  }

  private void updatePointLabels ()  {
    pMaxPointsLabel.setText("Max Points: "+iMaxPoints);
    pAvailPointsLabel.setText("Available Points: "+(iMaxPoints-iSpentPoints));
    pSpentPointsLabel.setText("Spent Points: "+iSpentPoints);
    if (sErrorText != null && sErrorText.equals(""))  {
      pErrorLabel.setText (sErrorText);
      sErrorText = null;
    }
    else  {
      pErrorLabel.setText("");
    }
  }

  public boolean setInteger (Field f, String s)  {
    boolean pRightType = false;
    boolean NoErrors = true; 

    try  {
      try  {
	f.setInt(pData, Integer.parseInt(s));
	pRightType = true;
      }
      catch (NumberFormatException ex)  {
	ex.printStackTrace();
	System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"");
	NoErrors = false;
      }
      catch (IllegalArgumentException ex)  {
	// do nothing yet
      }
      if (!pRightType)  {
	try  {
	  f.setShort(pData,(short)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  // do nothing yet
	}
      }
      if (!pRightType)  {
	try  {
	  f.setByte(pData,(byte)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  // do nothing yet
	}
      }
      if (!pRightType)  {
	try  {
	  f.setLong(pData,(long)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"");
	  NoErrors = false;
	}
      }
    }
    catch (IllegalAccessException ex)  {
      ex.printStackTrace();
      System.out.println ("Integer \""+s+"\" for field \""+f+"\" is not accessible");
      NoErrors = false;
    }
    return NoErrors;
  }


  public boolean setArrayInteger (ConfigComponent cc, String s)  {
    boolean pRightType = false;
    boolean NoErrors = true;
    Field f = null;
    Object pArray = null;
    try  {
      f = cc.getCl().getDeclaredField(cc.getVarName());
      pArray = f.get(pData);
    }
    catch  (Exception ex)  {
      System.out.println ("Bad Field \""+cc.toString()+"\"\n");
      ex.printStackTrace();
      NoErrors = false;
    }
    int iIndex = 0;

    for (int i = 1; i <= cc.getArrayNum().size() && !pRightType; i++)  {
      if (i >= cc.getArrayNum().size())  {
	iIndex = ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue();
	pRightType = true;
      }
      else  {
	pArray = Array.get(pArray, ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
      }
    }

    try  {
      try  {
	Array.setInt (pArray, iIndex, Integer.parseInt(s));
	pRightType = true;
      }
      catch (NumberFormatException ex)  {
	ex.printStackTrace();
	System.out.println ("Unparsable Integer: \""+s+"\" for field \""+pArray+"\"\n");
	NoErrors = false;
      }
      catch (IllegalArgumentException ex)  {
	// do nothing yet
      }
      if (!pRightType)  {
	try  {
	  Array.setShort (pArray, iIndex, (short)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"\n");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  // do nothing yet
	}
      }
      if (!pRightType)  {
	try  {
	  Array.setByte (pArray, iIndex, (byte)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"\n");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  // do nothing yet
	}
      }
      if (!pRightType)  {
	try  {
	  Array.setLong (pArray, iIndex, (long)(Integer.parseInt(s)));
	  pRightType = true;
	}
	catch (NumberFormatException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"\n");
	  NoErrors = false;
	}
	catch (IllegalArgumentException ex)  {
	  ex.printStackTrace();
	  System.out.println ("Unparsable Integer: \""+s+"\" for field \""+f+"\"\n");
	  NoErrors = false;
	}
      }
    }  
    catch (ArrayIndexOutOfBoundsException ex)  {
      ex.printStackTrace();
      System.out.println ("Integer \""+s+"\" for field \""+f+"\" in index "
		   +iIndex+" is out of bounds\n");
      NoErrors = false;
    }
    return NoErrors;
  }


  //--------------------------------------------------------------------------
  // ActionListener Interface
  //
  public void actionPerformed(ActionEvent e)  {
    String arg = e.getActionCommand();
    ConfigComponent cc;
    Field f;
    boolean NoErrors = true;
    String sFieldContents;

    if (   "Ok".equals(arg))  {
      for (cc = (ConfigComponent)pConfigComponentList.first();
           cc != null;
           cc = (ConfigComponent)pConfigComponentList.next())  {
        try  {
          switch(cc.getComponentType())  {
          case ConfigComponent.CHECKBOX:
          case ConfigComponent.CHECKBOX2:
            f = cc.getCl().getDeclaredField(cc.getVarName());
	    if (cc.getArrayNum() != null)  {
	      Object pArray = f.get(pData);
	      for (int i = 1; i <= cc.getArrayNum().size(); i++)  {
		if (i >= cc.getArrayNum().size())  {
		  Array.setBoolean
		    (pArray, 
		     ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue(),
		     ((JCheckBox)cc.getAWTItem()).isSelected());
		  }
		  else  {
		    pArray = Array.get
		      (pArray,
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
		  }
		}
	      }
	      else  {
		f.setBoolean(pData,((JCheckBox)cc.getAWTItem()).isSelected());
	      }
            break;
          case ConfigComponent.CHOICE:
            f = cc.getCl().getDeclaredField(cc.getVarName());
            if (cc.getDataType() == ConfigComponent.COLOR)  {
              Color c =
                ConfigComponent.stringToColor
		  ((String)(((JComboBox)cc.getAWTItem()).getSelectedItem()));
              f.set(pData,c);
              c = (Color)f.get(pData);
            }
            else if (cc.getDataType() == ConfigComponent.STRING)  {
              f.set(pData,((JComboBox)cc.getAWTItem()).getSelectedItem());
            }
            else if (cc.getDataType() == ConfigComponent.INTEGER)  {
	      NoErrors = setInteger
		(f, (String)(((JComboBox)cc.getAWTItem()).getSelectedItem()));
            }
	    break;
          case ConfigComponent.CHOICE2:
            f = cc.getCl().getDeclaredField(cc.getVarName());
	    sFieldContents
	      = (String)((JComboBox2)cc.getAWTItem()).getSelectedItem();
            if (cc.getDataType() == ConfigComponent.STRING)  {
	      if (cc.getArrayNum() != null)  {
		Object pArray = f.get(pData);
		for (int i = 1; i <= cc.getArrayNum().size(); i++)  {
		  if (i >= cc.getArrayNum().size())  {
		    Array.set
		      (pArray,
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue(),
		       sFieldContents);
		  }
		  else  {
		    pArray = Array.get
		      (pArray, 
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
		  }
		}
	      }
	      else  {
		f.set(pData,sFieldContents);
	      }
            }
            else if (cc.getDataType() == ConfigComponent.INTEGER)  {
	      if (cc.getArrayNum() != null)  {
		NoErrors = setArrayInteger
		  (cc, ""+((JComboBox2)cc.getAWTItem()).getSelectedValue());
	      }
	      else  {
		NoErrors = setInteger
		  (f, ""+((JComboBox2)cc.getAWTItem()).getSelectedValue());
	      }
	    }
            break;
          case ConfigComponent.TEXTFIELD:
          case ConfigComponent.TEXTAREA:
          case ConfigComponent.FILEFIELD:
	    if (cc.getComponentType() == ConfigComponent.TEXTAREA)  {
	      sFieldContents = ((JTextArea)cc.getAWTItem()).getText();
	    }
	    else  {
	      sFieldContents = ((JTextField)cc.getAWTItem()).getText();
	    }
            f = cc.getCl().getDeclaredField(cc.getVarName());
            if (cc.getDataType() == ConfigComponent.STRING)  {
	      if (cc.getArrayNum() != null)  {
		Object pArray = f.get(pData);
		for (int i = 1; i <= cc.getArrayNum().size(); i++)  {
		  if (i >= cc.getArrayNum().size())  {
		    Array.set 
		      (pArray,
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue(),
		       sFieldContents);
		  }
		  else  {
		    pArray = Array.get
		      (pArray,
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
		  }
		}
	      }
	      else  {
		f.set(pData,sFieldContents);
	      }
            }
            else if (cc.getDataType() == ConfigComponent.LABELVALUE)  {
	      if (cc.getArrayNum() != null)  {
		Object pArray = f.get(pData);
		for (int i = 1; i <= cc.getArrayNum().size(); i++)  {
		  if (i >= cc.getArrayNum().size())  {
		    LabelValue pLV = (LabelValue)Array.get
			(pArray,
			 ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
		    pLV.setValue(sFieldContents);
		  }
		  else  {
		    pArray = Array.get
		      (pArray,
		       ((Integer)(cc.getArrayNum().elementAt(i-1))).intValue());
		  }
		}
	      }
	      else  {
		f.set(pData,sFieldContents);
	      }
            }
            else if (cc.getDataType() == ConfigComponent.INTEGER)  {
	      if (cc.getArrayNum() != null)  {
		NoErrors = setArrayInteger (cc, sFieldContents);
	      }
	      else  {
		NoErrors = setInteger (f, sFieldContents);
	      }
            }
            else if (cc.getDataType() == ConfigComponent.TIME)  {
              try  {
                f.setLong
		  (pData, ConfigComponent.stringToTime (sFieldContents));
              }
              catch (Exception ex)  {
		ex.printStackTrace();
                System.out.println ("Unparsable Time: \""
			     +sFieldContents+"\" for field \""
			     +cc.toString()+"\"");
                NoErrors = false;
              }
            }
            break;
          default:
            break;
          }
        }
        catch  (Exception ex)  {
          System.out.println ("Bad Field \""+cc.toString()+"\"\n");
          ex.printStackTrace();
          NoErrors = false;
        }
      }
      if (NoErrors)  {
        try  {
          pData.postConfig();
        }
        catch  (Exception ex)  {
          System.out.println ("Post-Config Error\n");
          ex.printStackTrace();
          NoErrors = false;
        }
      }
    }
    else if ("comboBoxChanged".equals (arg))  {
      JComboBox2 pCB2 = (JComboBox2)e.getSource();
      iSpentPoints -= pCB2.getPointValueAt(pCB2.getPrevSelectedIndex());
      if (iSpentPoints + pCB2.getSelectedPointValue() <= iMaxPoints)  {
	iSpentPoints += pCB2.getSelectedPointValue();
	pCB2.setPrevSelectedIndex (pCB2.getSelectedIndex());
      }
      else  {
	sErrorText = "Not Enough Points!";
	iSpentPoints += pCB2.getPointValueAt(pCB2.getPrevSelectedIndex());
	pCB2.setSelectedIndex (pCB2.getPrevSelectedIndex());
      }
      updatePointLabels();
    }


    if ((   "Ok".equals(arg)
         || "Cancel".equals(arg))
        && NoErrors)  {
      dispose();
    }
  }


  //--------------------------------------------------------------------------
  // ChangeListener Interface
  //
  public void stateChanged (ChangeEvent e)  {
    while (bInChange)  {
      try  {
	Thread.sleep(250);
      }
      catch (InterruptedException ex)  {
      }
    }
    bInChange = true;
    JCheckBox2 pJCB2 = (JCheckBox2)e.getSource();
    if (pJCB2.isSelected())  {
      if ((iSpentPoints + pJCB2.getPointValue()) <= iMaxPoints)  {
	iSpentPoints += pJCB2.getPointValue();
      }
      else  {
	sErrorText = "Not Enough Points!";
	pJCB2.setSelected(false);
      }
    }
    else  {
      if ((iSpentPoints - pJCB2.getPointValue()) <= iMaxPoints)  {
	iSpentPoints -= pJCB2.getPointValue();
      }
      else  {
	sErrorText = "Not Enough Points!";
	pJCB2.setSelected(true);
      }
    }
    updatePointLabels();
    bInChange = false;
  }

}