//
// GridBagMaster.java -- Grid Bag Manipulation stuff
//
//   Copyright (C) 1997 Javva Brothers <jb@absurd.org>
//
//   url: <http://www.absurd.org/absurd/jb/gbm>  
//
//   This program is covered under GNU General Public License,
//   see file COPYING for details, or get it at
//	<http://www.absurd.org/absurd/jb/gbm/COPYING>
//


import java.applet.*;
import java.awt.*;
import java.util.*;

public class GridBagMaster extends Applet 
{
	Vector		fvec_;		// factory vector
	Vector		cvec_;		// component vector

	Button		new_btn_;
	Button		mod_btn_;
	Button		up_btn_;
	Button		down_btn_;
	Button		del_btn_;
		
	private Button gen_btn_;
	private List   bag_list_;
	private Choice control_choice_;
	private Panel ctl_prop_panel_;
	private TextField ctl_id_txt_;
	
	// GridBagConstraints properties

	private  Label		pos_lbl_;
	private Choice		fill_choice_;
	private Choice		anchor_choice_;
	private TextField	gridx_txt_;
	private TextField	gridy_txt_;
	private TextField	gridw_txt_;
	private TextField	gridh_txt_;
	private TextField	ipadx_txt_;
	private TextField	ipady_txt_;
	private TextField	wgtx_txt_;
	private TextField	wgty_txt_;
	private TextField	ins_top_txt_;
	private TextField	ins_lt_txt_;
	private TextField	ins_rt_txt_;
	private TextField	ins_btm_txt_;	
	
        private Window test_window_;
	private Window code_window_;
	
	private TextField cont_name_txt_;
	
        public void init() 
        {	
		fvec_ = new Vector();
		cvec_ = new Vector();
		// applet (this) panel
		//
		
		this.setLayout(new GridBagLayout());
		Panel ctl_panel = new Panel();
		add( this, ctl_panel,-1, -1, 1, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 1, 0, 0, 10, 0 );
		bag_list_ = new List();
		add( this, bag_list_,-1, -1, 1, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			0, 1, 0, 0, 0, 0 );
		Panel layout_panel = new Panel();
		add( this, layout_panel,-1, -1, 1, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 1, 0, 10, 0, 0 );

		//
		// control panel
		//

		ctl_panel.setLayout(new GridBagLayout());
		control_choice_ = new Choice();
		add( ctl_panel, control_choice_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 0, 0, 0, 0 );
		ctl_prop_panel_ = new Panel();
		add( ctl_panel, ctl_prop_panel_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 1, 0, 0, 0, 5 );
		add( ctl_panel, new Label("Var. name:"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0 );
		ctl_id_txt_ = new TextField();
		add( ctl_panel, ctl_id_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 0, 0, 0, 0 );
		add( ctl_panel, new Label("Container:"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 3, 0, 0, 0 );
		cont_name_txt_ = new TextField("this");
		add( ctl_panel, cont_name_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 0, 3, 0, 0, 0 );
		new_btn_ = new Button("New");
		add( ctl_panel, new_btn_,1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 5, 0, 4, 10 );
		mod_btn_ = new Button("Modify");
		add( ctl_panel, mod_btn_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 5, 2, 2, 10 );
		del_btn_ = new Button("Delete");
		add( ctl_panel, del_btn_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 5, 4, 0, 10 );
		gen_btn_ = new Button("Generate...");
		add( ctl_panel, gen_btn_,1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 0, 0, 0, 0 );
			
		//
		//  GridBagLayout panel
		// 

		layout_panel.setLayout(new GridBagLayout());
		pos_lbl_  = new Label("0,0 x 0,0", Label.CENTER);
		add( layout_panel, pos_lbl_ ,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 10 );
		add( layout_panel, new Label("Fill:"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0 );
		fill_choice_ = new Choice();
		add( layout_panel, fill_choice_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 0, 0, 0, 0 );
		add( layout_panel, new Label("Anchor:"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0 );
		anchor_choice_ = new Choice();
		add( layout_panel, anchor_choice_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 0, 0, 0, 0 );
			
		Panel grid_panel = new Panel();
		add( layout_panel, grid_panel,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 10, 0, 0, 10 );
		Panel grid_panel_1 = new Panel();
		add( layout_panel, grid_panel_1,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 10 );			

		//
		// layout panel -- grid panel
		//

		grid_panel.setLayout(new GridBagLayout());
		add( grid_panel, new Label("Grid", Label.CENTER), -1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 0 );
		add( grid_panel, new Label("x:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 0, 0, 0, 0 );
		gridx_txt_ = new TextField();
		add( grid_panel, gridx_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 0 );
		add( grid_panel, new Label("y:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 0, 0, 0, 0 );
		gridy_txt_ = new TextField();
		add( grid_panel, gridy_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 0 );
		add( grid_panel, new Label("wid:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 5, 0, 0, 0 );
		gridw_txt_ = new TextField();
		add( grid_panel, gridw_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 0, 0, 5, 0, 0, 0 );
		add( grid_panel, new Label("hgt:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 5, 0, 0, 0 );
		gridh_txt_ = new TextField();
		add( grid_panel, gridh_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 0, 0, 5, 0, 0, 0 );
			
		//
		// layout panel -- grid panel 1 (ipad and weight)
		//

		grid_panel_1.setLayout(new GridBagLayout());
		add( grid_panel_1, new Label("ipad:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 0, 0, 0, 10 );
		ipadx_txt_ = new TextField();
		add( grid_panel_1, ipadx_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 10 );
		add( grid_panel_1, new Label(" ", Label.CENTER), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0, 0, 10 );
		ipady_txt_ = new TextField();
		add( grid_panel_1, ipady_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 10 );
		add( grid_panel_1, new Label("weight:"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.EAST,
			0, 0, 0, 0, 0, 0, 0, 0 );
		wgtx_txt_ = new TextField();
		add( grid_panel_1, wgtx_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0, 0, 0 );
		add( grid_panel_1, new Label(" ", Label.CENTER), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0, 0, 0 );
		wgty_txt_ = new TextField();
		add( grid_panel_1, wgty_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 0, 0, 0, 0, 0, 0 );

		//
		// Insets part
		// 			
		ins_top_txt_ = new TextField();
		add( layout_panel, ins_top_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			20, 0, 0, 0, 10, 0, 0, 0 );
		ins_lt_txt_ = new TextField();
		add( layout_panel, ins_lt_txt_,-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			20, 0, 0, 0, 0, 0, 0, 0 );
		add( layout_panel, new Label("insets"), -1, -1, GridBagConstraints.RELATIVE, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 1, 0, 0, 0, 0, 0 );
		ins_rt_txt_ = new TextField();
		add( layout_panel, ins_rt_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			20, 0, 0, 0, 0, 0, 0, 0 );
		ins_btm_txt_ = new TextField();
		add( layout_panel, ins_btm_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.NORTH,
			20, 0, 0, 1, 0, 0, 0, 0 );
		
		// initializing components
		
		fill_choice_.addItem("NONE");
		fill_choice_.addItem("HORIZONTAL");
		fill_choice_.addItem("VERTICAL");
		fill_choice_.addItem("BOTH");
		
		
		for( int i = 0; anchor_str(i, false).length() > 0; i++ )
			anchor_choice_.addItem(anchor_str(i, false));
		
		add_factories();
        }
	
	private void add_factories()
	{
		add(new ButtonFactory());
		add(new CanvasFactory());
		add(new CheckboxFactory());
		add(new ChoiceFactory());
		add(new CustomClassFactory());
		add(new LabelFactory());
		add(new ListFactory());
		add(new PanelFactory());
		add(new ScrollBarFactory());
		add(new TextAreaFactory());
		add(new TextFieldFactory());
		
		ctl_prop_panel_.setLayout(new BorderLayout());
		select_factory(0);
		
		// this is a horrible hack, but it's beyound human 
		// comprehension to find out why Netscape 2.x takes
		// m_i_n_u_t_e to access ComponentShell class very first
		// time after application is loaded -- if it haven't been 
		// created in some of the methods of the (main) applet
		// so we calling this dummy constructor to overcome 
		// such a problem
		 
		ComponentShell cs = new ComponentShell(null, null);
	}

	private void add( ComponentFactory cf )
	{
		fvec_.addElement(cf);
		control_choice_.addItem(cf.className());
	}
	
	private void select_factory( int idx )
	{
		ctl_prop_panel_.removeAll();
		ctl_prop_panel_.add("Center", factory_at(idx));
		ctl_prop_panel_.layout();
		ctl_prop_panel_.validate();
	}
	
	private void select_factory_for( ComponentShell cs )
	{
		if( !cs.className().equals(control_choice_.getSelectedItem()) )
		{
			control_choice_.select(cs.className());
			select_factory(control_choice_.getSelectedIndex());
		}
	}
	
	private ComponentFactory factory_at( int idx )
	{
		return (ComponentFactory)fvec_.elementAt(idx);
	}
	
	private ComponentShell component_at( int idx )
	{
		return (ComponentShell)cvec_.elementAt(idx);
	}
	
	public void start()
	{
		pop_window();
		if( test_window_ != null )
			test_window_.show();
	}
	
	public void stop()
	{
		if( test_window_ != null )	
			test_window_.hide();
		if( code_window_ != null && code_window_.isVisible() )
		{
			code_window_.dispose();
			code_window_ = null;
		}
	}
	
	public void destroy()
	{
		if( test_window_ != null )
		{
			test_window_.dispose();
			test_window_ = null;
		}
	}

	
        public boolean action( Event e, Object arg )
        {
                if( e.target == new_btn_ )
			new_control();
		else if( e.target == mod_btn_ )
			modify_control();
		else if( e.target == del_btn_ )
			delete_control();
		else if( e.target == gen_btn_ )
			generate_code();
		else if( e.target == bag_list_ )
			select_control();
		else if( e.target == control_choice_ )
		{
			select_factory(control_choice_.getSelectedIndex());
		}
                return super.action(e, arg);
	}
	
	public boolean handleEvent( Event e )
	{
		if( e.target == bag_list_ && e.id == Event.LIST_SELECT )
			select_control();
		return super.handleEvent(e);
	}
	
	private void pop_window()
	{
		if( test_window_ != null )
			return;
			
		test_window_ = new Dialog(get_frame(), "GridBagLayout test Window", false);
		test_window_.setLayout(new GridBagLayout());
		
		
		test_window_.resize(300, 100);	// for Netscape 2.01
		test_window_.addNotify();	// for Netscape 2.01
		test_window_.resize(300, 100);		
	}
	
	
	private void new_control()
	{
		int idx = control_choice_.getSelectedIndex();
		if( idx == -1 )
			return;
		
		ComponentShell cs = factory_at(idx).newComponentShell();
		
		cs.setId(ctl_id_txt_.getText());
		int pos = add_item_to_list(cs);
		test_window_.add(cs.component(), pos);
		re_layout();
		get_constraints(cs.component());
	}

	private void modify_control()
	{
		// get the selected control, get all the parameters from
		// the user, and adjust constraints accordingly
		
		// also we need to handle the case when whole control type 
		// has been modified
		
		int sel_idx = bag_list_.getSelectedIndex();
		ComponentShell cs = component_at(sel_idx);
		set_constraints(cs.component());
		cs.setId(ctl_id_txt_.getText());
		cs.modify();
		String list_str = make_list_name(cs);
		if( !list_str.equals(bag_list_.getSelectedItem()) )
			bag_list_.replaceItem(list_str, sel_idx);
			
		re_layout();
		get_constraints(cs.component());	// reflect info we've just set
		bag_list_.select(sel_idx);
	}
		
	private void delete_control()
	{
		int sel_idx = bag_list_.getSelectedIndex();
		if( sel_idx < 0 )
			return;
		bag_list_.delItem(sel_idx);
		test_window_.remove(test_window_.getComponent(sel_idx));
		component_at(sel_idx).cleanup();
		cvec_.removeElementAt(sel_idx);
		re_layout();
		if( sel_idx >= bag_list_.countItems() )
			sel_idx--;
		if( sel_idx < 0 )
			return;
		
		bag_list_.select(sel_idx);	
		select_control();
	}
	
	private void select_control()
	{
		int sel_idx = bag_list_.getSelectedIndex();
		ComponentShell cs = component_at(sel_idx);
		select_factory_for(cs);
		get_constraints(cs.component());
		ctl_id_txt_.setText(cs.getId());
		cs.select();
		cs.component().requestFocus();
	}
	
	
	private void re_layout()
	{
		// by some unknown reason, invalidating the component and
		// then calling "layout" didn't work in Netscape 2.x,
		// so we explicitly laying out the component and
		// invalidating it afterwards
		test_window_.layout();		
		test_window_.validate();	
	}
	
	private int add_item_to_list( ComponentShell cs )
	{
		int idx = bag_list_.getSelectedIndex() + 1;
		bag_list_.addItem(make_list_name(cs), idx);
		bag_list_.select(idx);
		cvec_.insertElementAt(cs, idx);
		return idx;
	}
	
	private String make_list_name( ComponentShell cs )
	{
		String name = cs.getId().length() > 0 ? 
					cs.getId() : cs.className();
		if( cs.getLabel().length() > 0 )
			name += " \"" + cs.getLabel() + "\"";
		return name;
	}
	
	private void get_constraints( Component c )
	{
		// get control constraints structure out of the GridBagLayout
		// and fill up all user-editable fields with this information
		
		display_control_bounds(c);
			
		GridBagLayout gridbag = (GridBagLayout)test_window_.getLayout();
		GridBagConstraints constr = gridbag.getConstraints(c);
		
		if( constr == null )
		{
			System.out.print("ERROR: Cannot get constraints for " + c.toString() + "\n" );
			return;
		}
		
		fill_choice_.select(fill_type_to_idx(constr.fill));
		anchor_choice_.select(anchor_to_idx(constr.anchor));

		gridx_txt_.setText(String.valueOf(constr.gridx));
		gridy_txt_.setText(String.valueOf(constr.gridy));		
		gridw_txt_.setText(wid_to_str(constr.gridwidth));
		gridh_txt_.setText(wid_to_str(constr.gridheight));
		
		wgtx_txt_.setText(String.valueOf(constr.weightx));
		wgty_txt_.setText(String.valueOf(constr.weighty));

		ipadx_txt_.setText(String.valueOf(constr.ipadx));
		ipady_txt_.setText(String.valueOf(constr.ipady));		
		
		ins_top_txt_.setText(String.valueOf(constr.insets.top));
		ins_lt_txt_.setText(String.valueOf(constr.insets.left));
		ins_rt_txt_.setText(String.valueOf(constr.insets.right));
		ins_btm_txt_.setText(String.valueOf(constr.insets.bottom));
	}

	private void set_constraints( Component c )
	{
		// retrieve constraints from user-editable fields and
		// construct GridBagConstraints structure out of it,
		// then 
		GridBagLayout gridbag = (GridBagLayout)test_window_.getLayout();
		GridBagConstraints constr = gridbag.getConstraints(c);
		if( constr == null )
		{
			System.out.print("WARNING: Cannot get constraints for " + c.toString() + "\n" );
			constr = new GridBagConstraints();
		}

		constr.fill = idx_to_fill_type(fill_choice_.getSelectedIndex());
		constr.anchor = idx_to_anchor(anchor_choice_.getSelectedIndex());

		constr.gridx = str_to_int(gridx_txt_.getText(), constr.gridx);
		constr.gridy = str_to_int(gridy_txt_.getText(), constr.gridy);
		constr.gridwidth = str_to_wid(gridw_txt_.getText(), constr.gridwidth);
		constr.gridheight = str_to_wid(gridh_txt_.getText(), constr.gridheight);
			
		if( wgtx_txt_.getText().length() > 0 )	
			constr.weightx = get_double(wgtx_txt_.getText());
		if( wgty_txt_.getText().length() > 0 )	
			constr.weighty = get_double(wgty_txt_.getText());

		constr.ipadx = str_to_int(ipadx_txt_.getText(), constr.ipadx);
		constr.ipady = str_to_int(ipady_txt_.getText(), constr.ipady);

		constr.insets.top = str_to_int(ins_top_txt_.getText(), constr.insets.top);
		constr.insets.left = str_to_int(ins_lt_txt_.getText(), constr.insets.left);
		constr.insets.right = str_to_int(ins_rt_txt_.getText(), constr.insets.right);
		constr.insets.bottom = str_to_int(ins_btm_txt_.getText(), constr.insets.bottom);
		
		gridbag.setConstraints(c, constr);
	}
	
	private void display_control_bounds( Component c )
	{
		Rectangle r = c.bounds();
		pos_lbl_.setText( String.valueOf(r.x) + "," + 
			String.valueOf(r.y) + " x " +
			String.valueOf(r.width) + "," + 
			String.valueOf(r.height) );	
	}
	
	private static final int [] fill_types__ = { GridBagConstraints.NONE, 
				GridBagConstraints.HORIZONTAL,
				GridBagConstraints.VERTICAL,
				GridBagConstraints.BOTH };

	
	private int fill_type_to_idx( int fill )
	{
		for( int i = 0; i < 4; i++ )
			if( fill == fill_types__[i] )
				return i;
		return 0;
	}
	
	private int idx_to_fill_type( int idx )
	{
		if( idx >= 0 && idx < 4 )
			return fill_types__[idx];
		else
			return GridBagConstraints.NONE;
	}

	private static final int [] anchors__ = { GridBagConstraints.CENTER, 
				GridBagConstraints.EAST,
				GridBagConstraints.NORTH,
				GridBagConstraints.NORTHEAST,
				GridBagConstraints.NORTHWEST,
				GridBagConstraints.SOUTH,
				GridBagConstraints.SOUTHEAST,
				GridBagConstraints.SOUTHWEST,
				GridBagConstraints.WEST };
	
	private int anchor_to_idx( int anchor )
	{
		for( int i = 0; i < 9; i++ )
			if( anchor == anchors__[i] )
				return i;
		return 0;
	}
	
	private int idx_to_anchor( int idx )
	{
		if( idx >= 0 && idx < 9 )
			return anchors__[idx];
		else
			return GridBagConstraints.CENTER;
	}
	
	private String anchor_str( int idx, boolean full )
	{
		String [] anchors = { "CENTER", "EAST", "NORTH", "NORTHEAST",
				"NORTHWEST", "SOUTH", "SOUTHEAST",
				"SOUTHWEST", "WEST" };
		if( idx < 0 || idx > 8 )
			return "";
			
		if( full )
			return "GridBagConstraints." + anchors[idx];
		else 
			return anchors[idx];
				
	}
	
	private String wid_to_str( int sz )
	{
		return wid_to_str(sz, false);
	}
	
	private String wid_to_str( int sz, boolean full )
	{
		if( sz == GridBagConstraints.RELATIVE )
			return (full ? "GridBagConstraints.RELATIVE" : "REL");
		else if( sz == GridBagConstraints.REMAINDER )
			return (full ? "GridBagConstraints.REMAINDER" : "REM");
		else
			return String.valueOf(sz);
	}

	private int str_to_wid( String str, int dflt )
	{
		if( str.regionMatches(true, 0, "rel", 0, 3) )
			return GridBagConstraints.RELATIVE;
		if( str.regionMatches(true, 0, "rem", 0, 3) )
			return GridBagConstraints.REMAINDER;
		int w = dflt;
		try { w = Integer.parseInt(str); }
		catch( NumberFormatException nfe ) {}
		return w;
	}

	private int str_to_int( String str, int dflt )
	{
		int w = dflt;
		try { w = Integer.parseInt(str); }
		catch( NumberFormatException nfe ) {}
		return w;
	}
		
	private double get_double( String str )
	{
	        Double val = new Double(0.0);
		try { val = Double.valueOf(str); }
		catch( NumberFormatException nfe ) {}
		return val.doubleValue();
	}
	
	private Frame get_frame()
	{
		Container parent = getParent();
		while( parent != null && !(parent instanceof Frame) )
			parent = parent.getParent();
		return (Frame)parent;
	}
	
	private void generate_code()
	{
		if( code_window_ == null )
		{
	    		code_window_ = new CloseableFrame("Got the code!");
	    		code_window_.setLayout(new BorderLayout());
		}
		else
			code_window_.removeAll();
		
		String cont_name = cont_name_txt_.getText();
		
		String pfx0 = new String("\t");	
		String code_str = new String("//\n// This is automatically generated code.\n//\n\n");
		String ctl_decl = new String();
		String sub_decl = new String("\n");
		sub_decl += pfx0 + "public void init()\n\t{\n";
		
		String str = new String();
		String pfx = new String("\t\t");
		str += pfx + cont_name + ".setLayout(new GridBagLayout());\n";
		
		GridBagLayout gridbag = (GridBagLayout)test_window_.getLayout();
		
		for( int j = 0; j < fvec_.size(); j++ )
			factory_at(j).prepare();
		
		for( int i = 0; i < bag_list_.countItems(); i++ )
		{
			ComponentShell cs = component_at(i);
			String id = cs.getId();
			String class_name = cs.className();
			GridBagConstraints c = gridbag.getConstraints(cs.component());
			
			str += cs.preambleString(pfx);
			
			if( id.length() > 0 )
			{
				ctl_decl += pfx0 + "private " + class_name + "\t\t" + id + ";\n";
				str += pfx + id + " = " + cs.creationString() + ";\n";
				str += pfx + "add( " + cont_name + ", " + id + ",";
			}
			else
			{
				str += pfx + "add( " + cont_name + ", " + cs.creationString() + ", ";
			}
			
			str += generate_constraints(c, pfx) + " );\n";
			
			str += cs.initializationString();
		}
		
		str += pfx0 + "}\n\n";
		
		str += generate_add_routine( pfx0, pfx );
				
		TextArea textarea = new TextArea(code_str + ctl_decl + 
						sub_decl + str, 40, 80);
		textarea.setEditable(false);
		textarea.setBackground( Color.white );
//		textarea.setFont(new Font("courier", Font.PLAIN, 8));
		code_window_.add("Center", textarea);
				
		code_window_.pack();
		if( !code_window_.isVisible() )
			code_window_.show();
		else
		{
			code_window_.repaint();
			code_window_.toFront();
		}
	}


	private static final String [] fill_str__ = { "GridBagConstraints.NONE", 
				"GridBagConstraints.HORIZONTAL",
				"GridBagConstraints.VERTICAL",
				"GridBagConstraints.BOTH" };
	
	private String generate_constraints( GridBagConstraints c, String pfx0 )
	{
		String str = new String();
		String pfx = new String(pfx0 + "\t");
		str += 	String.valueOf(c.gridx) + ", " + 
			String.valueOf(c.gridy) + ", " +
			wid_to_str(c.gridwidth, true) + ", " +
			wid_to_str(c.gridheight, true) + ",\n" + pfx +
			fill_str__[fill_type_to_idx(c.fill)] + ", " +
			anchor_str(anchor_to_idx(c.anchor), true) + ",\n" + pfx +
			String.valueOf(c.ipadx) + ", " +
			String.valueOf(c.ipady) + ", " +
			String.valueOf(c.weightx) + ", " +
			String.valueOf(c.weighty) + ", " +
			String.valueOf(c.insets.top) + ", " +
			String.valueOf(c.insets.left) + ", " +
			String.valueOf(c.insets.right) + ", " +
			String.valueOf(c.insets.bottom);
		return str;	
	}
	
	private String generate_add_routine( String pfx0, String pfx )
	{
		String str = new String();
		str += pfx0 + "// this is automatically generated routine\n\n";
		str += pfx0 + "protected void add( Container container, Component component,\n";
                str += pfx0 + "                  int gridx, int gridy, int gridw, int gridh,\n";
		str += pfx0 + "                  int fill, int anchor, int ipadx, int ipady,\n";
		str += pfx0 + "                  double wgtx, double wgty,\n";
		str += pfx0 + "                  int top, int left, int right, int bottom )\n";
        	str += pfx0 + "{\n";
		str += pfx  + "GridBagConstraints c = new GridBagConstraints();\n";
		str += pfx  + "c.gridx = gridx; c.gridy = gridy;\n";
		str += pfx  + "c.gridwidth = gridw; c.gridheight = gridh;\n";
		str += pfx  + "c.fill = fill; c.anchor = anchor;\n";
		str += pfx  + "c.ipadx = ipadx; c.ipady = ipady;\n";
		str += pfx  + "c.weightx = wgtx; c.weighty = wgty;\n";
		str += pfx  + "c.insets = new Insets(top, left, bottom, right);\n";
                str += pfx  + "((GridBagLayout)(container.getLayout())).setConstraints(component, c);\n";
                str += pfx  + "container.add(component);\n";
        	str += pfx0 + "}\n";
		return str;
	}

	
	// automatically generated routine
	
	private void addcomponent( Container cont,
	                           Component compo,
	                           GridBagConstraints c )
	{
		((GridBagLayout)(cont.getLayout())).setConstraints(compo, c);
		cont.add(compo);
	}	

	// this is automatically generated routine (old one -- w/o insets)

	protected void add( Container container, Component component,
	                  int gridx, int gridy, int gridw, int gridh,
	                  int fill, int anchor, double wgtx, double wgty,
	                  int top, int left, int right, int bottom )
	{
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = gridx; c.gridy = gridy;
		c.gridwidth = gridw; c.gridheight = gridh;
		c.fill = fill; c.anchor = anchor;
		c.weightx = wgtx; c.weighty = wgty;
		c.insets = new Insets(top, left, bottom, right);
		((GridBagLayout)(container.getLayout())).setConstraints(component, c);
		container.add(component);
	}
	
	// this is automatically generated routine
	
	protected void add( Container container, Component component,
	                  int gridx, int gridy, int gridw, int gridh,
	                  int fill, int anchor, int ipadx, int ipady,
	                  double wgtx, double wgty,
	                  int top, int left, int right, int bottom )
	{
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = gridx; c.gridy = gridy;
		c.gridwidth = gridw; c.gridheight = gridh;
		c.fill = fill; c.anchor = anchor;
		c.ipadx = ipadx; c.ipady = ipady;
		c.weightx = wgtx; c.weighty = wgty;
		c.insets = new Insets(top, left, bottom, right);
		((GridBagLayout)(container.getLayout())).setConstraints(component, c);
		container.add(component);
	}		
}

class CloseableFrame extends Frame
{
	CloseableFrame(String title)
	{
		super(title);
	}
	
	public boolean handleEvent( Event e )
	{
		if( e.id == Event.WINDOW_DESTROY )
			dispose();
		return super.handleEvent(e);
	}
}

//---------------------------------------------------------------------------
//
// component stuff
//


class ComponentShell extends Object
{
	private Component c_;
	private String id_;
	private ComponentFactory factory_;
	
	public ComponentShell( ComponentFactory factory, Component c )
	{
		c_ = c;
		factory_ = factory;
		id_ = new String();
	}
	
	public String getId() { return id_; }
	public void setId( String id ) { id_ = new String(id); }
	public ComponentFactory factory() { return factory_; }
	public Component component() { return c_; }
	
	// convinience forwarding methods -- to Factory object
	//
	public String className() { return factory_.className(); }
	public String getLabel() { return factory_.labelString(c_); }
	public void select() { factory_.select(c_); }
	public void modify() { factory_.modify(c_); }
	public void cleanup() { factory_.cleanup(c_); }
	public String creationString() { return factory_.creationString(c_); }
	public String initializationString() { return factory_.initializationString(c_); }
	public String preambleString(String pfx) { return factory_.preambleString(c_, pfx); }
}

abstract class ComponentFactory extends Panel
{
	public abstract ComponentShell newComponentShell();	
	public void prepare() {}	// called before each generation cycle
	
	public abstract String className();
	
	public abstract void select( Component c );
	
	public abstract void modify( Component c );
	
	public void cleanup( Component c ) {}
	
	public String labelString( Component c ) { return ""; }
	
	public abstract String creationString( Component c ); 
						// string used to create this
						// particular component, like
						// "Button("Button 1")"	
	public String initializationString( Component c ) { return ""; }	
						// any source code necessary to
						// initialize the control, like
						// adding items to the list, etc.

	public String preambleString( Component c, String pfx ) { return ""; }	
						// any source code necessary before
						// the control is initialized


	// this is automatically generated routine (old one)

	protected void add( Container container, Component component,
	                  int gridx, int gridy, int gridw, int gridh,
	                  int fill, int anchor, double wgtx, double wgty,
	                  int top, int left, int right, int bottom )
	{
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = gridx; c.gridy = gridy;
		c.gridwidth = gridw; c.gridheight = gridh;
		c.fill = fill; c.anchor = anchor;
		c.weightx = wgtx; c.weighty = wgty;
		c.insets = new Insets(top, left, bottom, right);
		((GridBagLayout)(container.getLayout())).setConstraints(component, c);
		container.add(component);
	}

	// this is automatically generated routine

	protected void add( Container container, Component component,
	                  int gridx, int gridy, int gridw, int gridh,
	                  int fill, int anchor, int ipadx, int ipady,
	                  double wgtx, double wgty,
	                  int top, int left, int right, int bottom )
	{
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = gridx; c.gridy = gridy;
		c.gridwidth = gridw; c.gridheight = gridh;
		c.fill = fill; c.anchor = anchor;
		c.ipadx = ipadx; c.ipady = ipady;
		c.weightx = wgtx; c.weighty = wgty;
		c.insets = new Insets(top, left, bottom, right);
		((GridBagLayout)(container.getLayout())).setConstraints(component, c);
		container.add(component);
	}	

}


abstract class LabeledComponentFactory extends ComponentFactory
{
	private TextField	label_txt_;

	protected LabeledComponentFactory(String label_str)
	{
		this.setLayout(new GridBagLayout());
		add( this, new Label(label_str),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.NORTH,
			0, 0, 5, 0, 0, 0 );
		label_txt_ = new TextField();
		add( this, label_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTH,
			1, 1, 5, 0, 0, 0 );	
	}

	public void select( Component c ) 
	{ 
		label_txt_.setText(fetch_label(c)); 
	}
	public void modify( Component c )
	{
		apply_label(c, label_txt_.getText());
	}
	
	public String labelString( Component c ) { return fetch_label(c); }
	
	public String creationString( Component c )
	{
		if( fetch_label(c).length() > 0 )
			return "new " + className() + "(\"" + fetch_label(c) + "\")";
		else
			return "new " + className() + "()";
	}

	protected String get_label() { return label_txt_.getText(); };

	// this should be overloaded by superclass
	protected abstract String fetch_label( Component c );	
	protected abstract void apply_label( Component c, String lbl );

}

//
// Button factory
//

class ButtonFactory extends LabeledComponentFactory
{
	public ButtonFactory() { super("Label"); }
	public ComponentShell newComponentShell()
	{
		Button btn = (get_label().length() > 0) ? 
				new Button(get_label()) : new Button();
		return new ComponentShell(this, btn);
	}
	public String className() { return "Button"; }
	
	protected String fetch_label( Component c ) 
		{ return ((Button)c).getLabel(); }
	protected void apply_label( Component c, String lbl ) 
		{ ((Button)c).setLabel(lbl); }
}

//
// Label factory
//

class LabelFactory extends ComponentFactory
{
	private TextField		label_txt_;
	private Checkbox		left_cb_;
	private Checkbox		cent_cb_;
	private Checkbox		right_cb_;
	
	public LabelFactory() 
	{
		this.setLayout(new GridBagLayout());
		add( this, new Label("Text"), -1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 0, 0, 5, 0, 0, 0 );
		label_txt_ = new TextField();
		add( this, label_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			0, 0, 1, 0, 5, 0, 0, 0 );
		CheckboxGroup cbgrp = new CheckboxGroup();
		left_cb_ = new Checkbox("Left", cbgrp, true);
		add( this, left_cb_,1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.WEST,
			0, 0, 0, 0, 0, 0, 0, 0 );
		cent_cb_ = new Checkbox("Center", cbgrp, false);
		add( this, cent_cb_,1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.WEST,
			0, 0, 0, 0, 0, 0, 0, 0 );
		right_cb_ = new Checkbox("Right", cbgrp, false);
		add( this, right_cb_,1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.NORTHWEST,
			0, 0, 0, 1, 0, 0, 0, 0 );	
	}
	
	public ComponentShell newComponentShell()
	{
		return new ComponentShell(this, 
			new Label(label_txt_.getText(), get_align()));
	}
	public String className() { return "Label"; }

	public void select( Component c ) 
	{ 
		label_txt_.setText(((Label)c).getText());
		get_group().setCurrent(align_to_cb(((Label)c).getAlignment()));
	}

	public void modify( Component c )
	{
		((Label)c).setText(label_txt_.getText());
		((Label)c).setAlignment(get_align());
	}
	
	public String labelString( Component c ) { return ((Label)c).getText(); }
	
	public String creationString( Component c )
	{
		String name = ((Label)c).getText();
		int align = ((Label)c).getAlignment();
		if( align != Label.LEFT )
			return "new Label(\"" + name + "\", " +  
						align_to_str(align) + ")";
		else if( name.length() > 0 )
			return "new Label(\"" + name + "\")";
		else
			return "new Label()";
	}
		
	private int get_align()
	{
		int [] aligns_ = { Label.LEFT, Label.CENTER, Label.RIGHT };
		return aligns_[get_sel_idx()];
	}
	
	private Checkbox align_to_cb( int align )
	{
		switch( align )
		{
			case Label.CENTER: return cent_cb_;
			case Label.RIGHT:  return right_cb_;
			case Label.LEFT:
			default:	   return left_cb_;
		} 
	}

	private String align_to_str( int align )
	{
		switch( align )
		{
			case Label.CENTER: return "Label.CENTER";
			case Label.RIGHT:  return "Label.RIGHT";
			case Label.LEFT:
			default:	   return "Label.LEFT";
		} 
	}
	
	private int get_sel_idx()
	{
		Checkbox cb = get_group().getCurrent();
		if(cb == left_cb_)		return 0;
		else if(cb == cent_cb_)		return 1;
		else if(cb == right_cb_)	return 2;
		else 				return 0;		
	}
	
	private CheckboxGroup get_group()
		{ return left_cb_.getCheckboxGroup(); }
}

//
// TextField factory
//

class TextFieldFactory extends LabeledComponentFactory
{
	public TextFieldFactory() { super("Text"); }
	public ComponentShell newComponentShell()
	{
		TextField tf = (get_label().length() > 0) ? 
				new TextField(get_label()) : new TextField();
		return new ComponentShell(this, tf);
	}
	public String className() { return "TextField"; }
	
	protected String fetch_label( Component c ) 
		{ return ((TextField)c).getText(); }
	protected void apply_label( Component c, String lbl ) 
		{ ((TextField)c).setText(lbl); }
}


//
// TextArea factory
//

class TextAreaFactory extends LabeledComponentFactory
{
	public TextAreaFactory() { super("Text"); }
	public ComponentShell newComponentShell()
	{
		TextArea ta = (get_label().length() > 0) ? 
				new TextArea(get_label()) : new TextArea();
		return new ComponentShell(this, ta);
	}
	public String className() { return "TextArea"; }
	
	protected String fetch_label( Component c ) 
		{ return ((TextArea)c).getText(); }
	protected void apply_label( Component c, String lbl ) 
		{ ((TextArea)c).setText(lbl); }
}

//
// ScrollBar factory
// 

class ScrollBarFactory extends ComponentFactory
{
	private Checkbox		horz_cb_;
	private Checkbox		vert_cb_;
	
	public ScrollBarFactory()
	{
		this.setLayout(new GridBagLayout());
		CheckboxGroup cbgroup = new CheckboxGroup();
		horz_cb_ = new Checkbox("Horizontal", cbgroup, true);
		add( this, horz_cb_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 0, 20, 10, 0, 0 );
		vert_cb_ = new Checkbox("Vertical", cbgroup, false);
		add( this, vert_cb_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTH,
			0, 1, 0, 10, 0, 0 );	
	}
	
	public ComponentShell newComponentShell()
	{ 
		int orient = horz_cb_.getCheckboxGroup().getCurrent() == 
					horz_cb_ ? Scrollbar.HORIZONTAL :
						   Scrollbar.VERTICAL;
		return new ComponentShell(this, new Scrollbar(orient)); 
	}	
	public String className() { return "ScrollBar"; }
	public void select( Component c ) 
	{
		horz_cb_.getCheckboxGroup().setCurrent(
			((Scrollbar)c).getOrientation() == Scrollbar.HORIZONTAL ?
					horz_cb_ : vert_cb_);
	}
	public void modify( Component c ) {}
	public String creationString( Component c )
	{ 
		return "new Scrollbar(" + 
			(((Scrollbar)c).getOrientation() == Scrollbar.HORIZONTAL ?
				"Scrollbar.HORIZONTAL" : "Scrollbar.VERTICAL") + ")"; 
	}	
}

//
// Choice factory and visible canvas class 
//

class ChoiceFactory extends ComponentFactory
{
	public ComponentShell newComponentShell()
		{ return new ComponentShell(this, new Choice()); }	
	public String className() { return "Choice"; }
	public void select( Component c ){}
	public void modify( Component c ) {}
	public String creationString( Component c )
		{ return "new Choice()"; }	
}

//
// List factory and visible canvas class 
//

class ListFactory extends ComponentFactory
{
	public ComponentShell newComponentShell()
		{ return new ComponentShell(this, new List()); }	
	public String className() { return "List"; }
	public void select( Component c ){}
	public void modify( Component c ) {}
	public String creationString( Component c )
		{ return "new List()"; }	
}


//
// Panel factory and visible panel class 
//

class PanelFactory extends ComponentFactory
{
	public ComponentShell newComponentShell()
		{ return new ComponentShell(this, new VisiblePanel()); }	
	public String className() { return "Panel"; }
	public void select( Component c ){}
	public void modify( Component c ) {}
	public String creationString( Component c )
		{ return "new Panel()"; }	
}

class VisiblePanel extends Panel
{
	public void paint( Graphics g )
	{
		g.setColor(Color.gray);
		g.fillRect(0, 0, size().width - 1, size().height - 1);	
		g.setColor(Color.darkGray);
		g.drawRect(0, 0, size().width - 1, size().height - 1);
	}
}

//
// Canvas factory and visible canvas class 
//

class CanvasFactory extends ComponentFactory
{
	public ComponentShell newComponentShell()
		{ return new ComponentShell(this, new VisibleCanvas()); }	
	public String className() { return "Canvas"; }
	public void select( Component c ){}
	public void modify( Component c ) {}
	public String creationString( Component c )
		{ return "new Canvas()"; }	
}

class VisibleCanvas extends Canvas
{	
	public void paint( Graphics g )
	{
		g.setColor(Color.lightGray);
		g.fillRect(0, 0, size().width - 1, size().height - 1);			
		g.setColor(Color.blue);
		g.drawRect(0, 0, size().width - 1, size().height - 1);
	}
}

//
// Custom class factory and visible canvas class 
//

class CustomClassFactory extends ComponentFactory
{
	private TextField		class_name_txt_;
	
	CustomClassFactory()
	{
		this.setLayout(new GridBagLayout());
		add( this, new Label("Class"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.NORTH,
			0, 0, 3, 0, 0, 0 );
		class_name_txt_ = new TextField();
		add( this, class_name_txt_,-1, -1, 1, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTH,
			1, 1, 5, 0, 0, 0 );	
	}
	
	public ComponentShell newComponentShell()
	{ 
		return new ComponentShell(this, 
			new CustomClassStub(class_name_txt_.getText())); 
	}
	public String className() { return "Custom"; }
	public void select( Component c )
	{
		class_name_txt_.setText(((CustomClassStub)c).getText());
	}
	public void modify( Component c ) 
	{
		((CustomClassStub)c).setText((class_name_txt_.getText()));
	}
	public String creationString( Component c )
	{ 
		return "new " + ((CustomClassStub)c).getText() + "()"; 
	}	
}

class CustomClassStub extends Canvas
{
	private String name_;
	
	public CustomClassStub( String name )
	{
		name_ = fix_name(name);
	}
	
	public String getText() { return name_; }
	public void setText( String name ) 
	{ 
		name_ = fix_name(name);
		repaint(); 
	}
	public Dimension minimumSize() 
	{
		FontMetrics fm = getFontMetrics(getFont());
		return new Dimension(fm.stringWidth(name_) + 4,
				fm.getHeight() + 4); 
	}
	
	public void paint( Graphics g )
	{
		
		g.setColor(Color.white);
		g.fillRect(0, 0, size().width - 1, size().height - 1);
		FontMetrics fm = getFontMetrics(getFont());
		g.setColor(Color.black);
		g.drawString(name_, 2, fm.getMaxAscent() + 2);
		g.setColor(Color.red);
		g.drawRect(0, 0, size().width - 1, size().height - 1);
	}
	
	private static String fix_name( String name )
	{
		return (name.length() > 0) ? name : "???";
	}
}

//
// Checkbox factory
//

class CheckboxFactory extends ComponentFactory
{

	private TextField	label_txt_;
	private List		grp_list_;
	private TextField	grp_name_txt_;
	private Hashtable	tmp_map_;
	private Vector		vgrp_;
	
	public CheckboxFactory()
	{
		this.setLayout(new GridBagLayout());
		add( this, new Label("Label"),-1, -1, 1, 1,
			GridBagConstraints.NONE, GridBagConstraints.CENTER,
			0, 0, 5, 0, 0, 0 );
		label_txt_ = new TextField();
		add( this, label_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,
			1, 0, 5, 0, 0, 0 );
		add( this, new Label("Group:"),-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.NONE, GridBagConstraints.WEST,
			1, 0, 10, 0, 0, 0 );
		grp_list_ = new List();
		add( this, grp_list_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.BOTH, GridBagConstraints.CENTER,
			1, 1, 2, 20, 5, 0 );
		grp_name_txt_ = new TextField();
		add( this, grp_name_txt_,-1, -1, GridBagConstraints.REMAINDER, 1,
			GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTH,
			1, 0, 0, 20, 0, 20 );	
		grp_list_.addItem("<none>");
		
		tmp_map_ = new Hashtable();
		vgrp_ = new Vector();
		vgrp_.addElement(null);
	}

	public boolean handleEvent( Event e )
	{
		if( e.target == grp_list_ && e.id == Event.LIST_SELECT )
			grp_name_txt_.setText(grp_list_.getSelectedIndex() > 0 ? 
						grp_list_.getSelectedItem() : "" );
		return super.handleEvent(e);
	}
	
	public void prepare()
	{
		tmp_map_.clear();
	}
	
	public ComponentShell newComponentShell()
	{ 
		Checkbox cb = (label_txt_.getText().length() > 0) ? 
			new Checkbox(label_txt_.getText()) : new Checkbox();
		CheckboxGruppe cbg;
		String grpname = grp_name_txt_.getText();
		if( (cbg = get_cur_group()) != null && 
					idx_for(grpname) > 0 )
			set_group(cb, cbg);
		else if( grpname.length() > 0 && !grpname.equals("<none>"))
			new_group(cb, grpname);
		return new ComponentShell(this, cb); 
	}
	
	public String className() { return "Checkbox"; }
	public void select( Component c )
	{
		// giving checkbox component, we need to
		// set up proper label text field and
		// select proper checkbox group in the 
		// group list/text field
		
		label_txt_.setText(((Checkbox)c).getLabel());
		CheckboxGruppe cbg = (CheckboxGruppe)((Checkbox)c).getCheckboxGroup();
		int idx;
		if( cbg == null || (idx = idx_for(cbg.name())) < 0 )
			idx = 0;		// no group
		grp_list_.select(idx);
		grp_name_txt_.setText(idx == 0 ? "" : cbg.name());
	}
	
	public void modify( Component c ) 
	{
		((Checkbox)c).setLabel(label_txt_.getText());
		String grpname = grp_name_txt_.getText();
		if( grpname.equals("<none>") || grpname.length() == 0 || 
					grp_list_.getSelectedIndex() == 0 )
		{
			cleanup(c);
			return;
		}
		int idx;
		CheckboxGruppe cbg;
		// do we have this group already ?
		if( (idx = idx_for(grpname)) >= 0 )
		{
			grp_list_.select(idx);
			if( (cbg = get_cur_group()) != group_for(c) )
			{
				cleanup(c);
				set_group((Checkbox)c, cbg);
			}
		}
		else		// nope, start a new group
			new_group((Checkbox)c, grpname);
	}
	
	public void cleanup( Component c )
	{
		CheckboxGruppe cbg = group_for(c);
		if( cbg == null || cbg.deref() > 0 )
			return;
		int idx = idx_for(cbg.name());
		grp_list_.delItem(idx);
		vgrp_.removeElementAt(idx);
		
		if( idx >= grp_list_.countItems() )
			idx--;
		if( idx < 0 )
			return;
		
		grp_list_.select(idx);
		if( idx == 0 )
			grp_name_txt_.setText("");
		else
			grp_name_txt_.setText(grp_list_.getSelectedItem());
	}
	public String creationString( Component c )
	{ 
		CheckboxGruppe cbg = group_for(c);
		String label = ((Checkbox)c).getLabel();
		if( cbg != null )
			return "new Checkbox(\"" + label + "\", " + 
				cbg.name() + ", " + 
				(((Checkbox)c).getState() ? "true" : "false") + ")";
		else if( label.length() > 0 )
			return "new Checkbox(\"" + label + "\")";
		else
			return "new Checkbox()"; 
	}
	public String preambleString( Component c, String pfx ) 
	{ 
		CheckboxGruppe cbg = group_for(c);
		if( cbg == null || tmp_map_.get(cbg) != null )
			return "";
		else
		{
			tmp_map_.put(cbg, new Boolean(true));
			return pfx + "CheckboxGroup " + cbg.name() + 
					" = new CheckboxGroup();\n";
		}
	}
	
	private int idx_for( String name )
	{
		for( int i = 1; i < vgrp_.size(); i++ )
			if( group_at(i).name().equals(name) )
				return i;
		return -1;
	}
	
	private CheckboxGruppe group_for( Component c )
		{ return (CheckboxGruppe)((Checkbox)c).getCheckboxGroup(); }
	private CheckboxGruppe group_at( int idx )
		{ return (CheckboxGruppe)vgrp_.elementAt(idx); }
	
	private CheckboxGruppe new_group( Checkbox cb, String name )
	{
		CheckboxGruppe cbg = new CheckboxGruppe(name);
		set_group(cb, cbg);
		vgrp_.addElement(cbg);
		grp_list_.addItem(cbg.name());
		grp_list_.select(grp_list_.countItems() - 1);
		return cbg;
	}
	
	private CheckboxGruppe get_cur_group()
	{
		int idx = grp_list_.getSelectedIndex();
		if( idx < 1 )
			return null;
		return group_at(idx);
	}
	
	private void set_group( Checkbox cb, CheckboxGruppe cbg )
	{
		cb.setCheckboxGroup(cbg);
		cbg.ref();
	}
}

// customized checkbox group

class CheckboxGruppe extends CheckboxGroup
{
	private String name_;
	private int ref_;
	
	public CheckboxGruppe( String name )
	{
		name_ = name;
		ref_ = 0;
	}
	
	public void ref() { ++ref_; }
	public int deref() 
	{ 
		if( ref_ > 0 ) 
			--ref_; 
		return ref_; 
	}
	public String name() { return name_; }
	public int hashCode() { return name_.hashCode(); }
}

