// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)ContainerWidget.java, 1.8, 10/19/96





package marimba.gui;





import java.io.*;


import java.awt.*;


import java.util.Vector;





import marimba.util.QuickSort;


import marimba.persist.*;





/**


 * Container widget. All widgets are containers, but this


 * widget has a getContent() field that returns the actual


 * container that contains the child widgets.


 *


 * @author	Arthur van Hoff


 * @version 	1.8, 10/19/96


 */


public class ContainerWidget extends Widget {


    public Widget  content;





    /**


     * Create the container, and create the content area


     * if necessary.


     */


    public ContainerWidget() {


	if ((content = newContent()) != this) {


	    add(content);


	}


    }


    


    /**


     * Don't save the children of this container if the


     * container has a content area.


     */


    public void getChildProperties(PropertyList list) {


	if (content == this) {


	    super.getChildProperties(list);


	} else {


	    list.setObject("content", content, null);


	}


    }





    /**


     * Set the properties.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	content = (Widget)list.getObject("content", null);





	if (content == null) {


	    content = newContent();


	}


	if (content != this) {


	    add(content);


	}


    }





    /**


     * Get the container that holds the child widgets.


     */


    public Widget getContent() {


	return content;


    }





    /**


     * Create the content for this container. This method


     * must be subclassed if the container has a content


     * area.


     */


    public Widget newContent() {


	return this;


    }





    /**


     * Default layout algorithm simply fits the content area


     * to the entire container.


     */


    public void layout() {


	if (content == this) {


	    super.layout();


	} else {


	    content.reshape(0, 0, width, height);


	}


    }








    /**


     * Assign the focus to the first widget within this container.


     */


    public void firstInFocus() {


	// Create an array of focusable widgets within this container


	Vector v = new Vector();


	getInFocusCandidates(v, 0, 0);


	int n = v.size();


	if (n > 0) {


	    FocusCandidate ws[] = new FocusCandidate[n];


	    v.copyInto(ws);





	    // Sort the array based on x,y location


	    QuickSort.sort(ws, 0, ws.length, null);





	    // Pick the first one and check for defaultbutton


	    Widget focus = ws[0].widget;


	    if (focus instanceof CommandButtonWidget) {


		Widget def = getDefaultButton();


		if (def != null) {


		    for (int index = 0; index < ws.length; index++) {


			if (ws[index].widget == def) {


			    focus = def;


			    break;


			}


		    }


		}


	    }


	    focus.requestFocus();


	} else {


	    clearFocus();


	}


    }





    /**


     * Assign the focus to the next widget that is located in this


     * container and to the right or below the current focus.


     */


    public void nextInFocus() {


	findInFocus(true);


    }





    /**


     * Assign the focus to the previous widget that is located within


     * this container and to the left or above the current focus.


     */


    public void previousInFocus() {


	findInFocus(false);


    }





    /**


     * Assign the focus to the previous or next widget in this container.


     */


    void findInFocus(boolean forward) {


	// Create an array of focusable widgets


	Vector v = new Vector();


	getInFocusCandidates(v, 0, 0);


	int n = v.size();


	if (n > 0) {


	    FocusCandidate ws[] = new FocusCandidate[n];


	    v.copyInto(ws);





	    // Sort the array based on x,y location


	    QuickSort.sort(ws, 0, n, null);





	    // Pick the correct candidate


	    Widget w = currentFocus();


	    if (forward) {


		int i = 0;


		if (w != null) {


		    while ((i < ws.length) && (ws[i++].widget != w));


		}


		if (i < ws.length) {


		    ws[i].widget.requestFocus();


		} else {


		    ws[0].widget.requestFocus();


		}


	    } else {


		int i = ws.length - 1;


		if (w != null) {


		    while ((i >= 0) && (ws[i--].widget != w));


		}


		if (i >= 0) {


		    ws[i].widget.requestFocus();


		} else {


		    ws[ws.length - 1].widget.requestFocus();


		}


	    }


	}


    }





    /**


     * Gather all focusable widgets in this container into a vector.


     */


    void getInFocusCandidates(Vector v, int x, int y) {


	x -= tx;


	y -= ty;


	for (int i = 0 ; i < content.nwidgets ; i++) {


	    Widget w = content.widgets[i];


	    if (w.visible) {


		if (w.focusInterest()) {


		    v.addElement(new FocusCandidate(w, x, y));


		}


		w.getFocusCandidates(v, x + w.x, y + w.y);


	    }


	}


    }





    /**


     * Find the widget in the content.


     */


    public Widget findWidget(String name) {


	Widget w = super.findWidget(name);


	return ((w == null) && (content != null) && (content != this)) ?


	    content.findWidget(name) : w;


    }


}


