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


// @(#)ListBoxWidget.java, 1.26, 12/18/96





package marimba.gui;





import java.awt.*;





import marimba.persist.*;





/**


 * A ListBoxWidget; a generic scrolling list of strings.


 *


 * @author	Arthur van Hoff


 * @version 	1.26, 12/18/96


 */


public class ListBoxWidget extends ChoiceWidget {


    /**


     * The possible options for the fillmode.


     * @see #getFillOptions


     * @see #fillMode


     */


    public static Options fillOptions = new Options();


    static {


	fillOptions.add("none", NONE);


	fillOptions.add("content", CONTENT);


	fillOptions.add("scrollbar", SCROLLBAR);


	fillOptions.add("both", FILLED);


    }





    /**


     * The fillmode of the ListBox: none, content, scrollbar or filled.


     * This means it can fill the content, the scrollbar or both.


     * @see #getFillMode


     * @see #setFillMode


     * @see #fillOptions


     * @see WidgetConstants


     */


    public int  fillMode = NONE;





    /**


     * The ListWidget used to display the list of choices.


     * @see #getList


     * @see #newList


     */


    public ListWidget  list = null;





    /**


     * The mode for the horizontal scrollbar:


     * never, optional or always.


     * @see #getHorzmode


     * @see #setHorzmode


     */


    public int horzmode = OPTIONAL;





    /**


     * The mode for the vertical scrollbar:


     * never, optional or always.


     * @see #getVertmode


     * @see #setVertmode


     */


    public int vertmode = ALWAYS;





    


    /**


     * Constructor.


     */


    public ListBoxWidget() {


	super();


	newList();


	makeItems();


	setHilite(new Color(232, 232, 232));


    }





    /**


     * Constructor for a ListBox with given choices.


     */


    public ListBoxWidget(int nchoices, String choices[]) {


	super(nchoices, choices);


	newList();


	makeItems();


	setHilite(new Color(232, 232, 232));


    }





    /**


     * Get the properties of this widget.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


	list.setOption("horizontal", ListWidget.horzOptions, horzmode, OPTIONAL);


	list.setOption("vertical", ListWidget.vertOptions, vertmode, ALWAYS);


	list.setOption("fillmode", fillOptions, fillMode, NONE);


    }





    /**


     * Set the properties of this widget.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	horzmode = list.getOption("horizontal", ListWidget.horzOptions, OPTIONAL);


	vertmode = list.getOption("vertical", ListWidget.vertOptions, ALWAYS);


	fillMode = list.getOption("fillmode", fillOptions, NONE);


	transparent = (fillMode != FILLED);


	newList();


	makeItems();


    }





    /**


     * Get the possible options for the fillMode.


     * @see #fillOptions


     */


    public Options getFillOptions() {


	return fillOptions;


    }





    /**


     * Get the mode for the horizontal scrollbar.


     * @see #horzmode


     */


    public int getHorzmode() {


	return horzmode;


    }





    /**


     * Set the mode for the horizontal scrollbar.


     * @see #horzmode


     */


    public void setHorzmode(int horzmode) {


	if (horzmode==NEVER || horzmode==OPTIONAL || horzmode==ALWAYS) {


	    this.horzmode = horzmode;


	    if (list != null) {


		list.setHorzmode(horzmode);


	    }


	}


    }





    /**


     * Get the mode for the vertical scrollbar.


     * @see #vertmode


     */


    public int getVertmode() {


	return vertmode;


    }





    /**


     * Set the mode for the vertical scrollbar.


     * @see #vertmode


     */


    public void setVertmode(int vertmode) {


	if (vertmode==NEVER || vertmode==OPTIONAL || vertmode==ALWAYS) {


	    this.vertmode = vertmode;


	    if (list != null) {


		list.setVertmode(vertmode);


	    }


	}


    }





    /**


     * Set choices and update the list.


     */


    public void setChoices(String choices[], String names[]) {


	super.setChoices(choices, names);


	makeItems();


    }





    /**


     * Check what the ListBoxWidget fills.


     * @see #fillMode


     */


    public int getFillMode() {


	return fillMode;


    }





    /**


     * Let the ListBoxWidget fill something.


     * @see #fillMode


     */


    public void setFillMode(int fillMode) {


        GroupWidget  content = (GroupWidget)list.getContent();


	if (this.fillMode != fillMode) {


	    switch (fillMode) {


		case NONE:


		    content.setFillMode(NONE);


		    list.setFillMode(NONE);


		    break;


		case CONTENT:


		    content.setFillMode(SOLID);


		    list.setFillMode(NONE);


		    break;


		case SCROLLBAR:


		    content.setFillMode(NONE);


		    list.setFillMode(SCROLLBAR);


		    break;


		case FILLED:


		    content.setFillMode(SOLID);


		    list.setFillMode(SCROLLBAR);


		    break;


	    }


	    this.fillMode = fillMode;


	    transparent = (fillMode != FILLED);


	    repaint();


	}


    }





    /**


     * The list that is used for this ListBoxWidget.


     * @see #list


     */


    public ListWidget getList() {


	return list;


    }





    /**


     * Create a new List.


     * @see #list


     */


    protected void newList() {


	list = new ListBoxContent();


	updateList();


    }





    /**


     * Update the properties of the list, to let


     * them match those of this ListBox.


     */


    public void updateList() {


	if (list != null) {


	    list.horzmode = horzmode;


	    list.vertmode = vertmode;


	    list.disable(disabled);


	    list.setBackground(background);


	    list.setHilite(hilite);


	    list.setValue(list.getItem(current));


	    if (fillMode==CONTENT || fillMode==FILLED) {


        	GroupWidget content = (GroupWidget)list.getContent();


        	content.setFillMode(SOLID);


	    }


	    if (fillMode==SCROLLBAR || fillMode==FILLED) {


		list.setFillMode(SCROLLBAR);


	    }


	    add(list);


	}


    }





    /**


     * Create the items using the current choices.


     * The list is being cleared first.


     */


    public void makeItems() {


	// empty the list before making the items again


	if (list.countItems() > 0) {


	    list.clear();


	}


	for (int i = 0 ; i < choices.length ; i++) {


	    ListBoxItemWidget item = new ListBoxItemWidget(choices[i]);


	    list.addItem(item);


	    if (current == i) {


		item.select();


	    }


	}


	layout();


    }





    /**


     * Disable the list, when disabling/enabling.


     */


    public void disable(boolean disabled) {


	if (this.disabled != disabled) {


	    this.disabled = disabled;


	    list.disable(disabled);


	}


    }





    /**


     * Set the current choice given the index.


     */


    public void setValue(int value) {


	int oldcurrent = current;


	super.setValue(value);


	if (oldcurrent != current && list != null) {


	    list.setValue(list.getItem(current));


	}


    }





    /**


     * Layout the container.


     */


    public void layout() {


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


    }





    /**


     * Event handler.


     */


    public boolean handleEvent(Event evt) {


	if (disabled) {


	    return true;


	}


	switch (evt.id) {


	    case Event.GOT_FOCUS:


		ListItemWidget  selected = list.selectedItem();


		if (selected != null) {


		    selected.repaint();


		}


		return true;





	    case Event.MOUSE_DOWN:


		requestFocus();


		super.handleEvent(evt);


		return false;





	    case Event.KEY_ACTION:


		switch(evt.key) {


		    case Event.RIGHT:


		    case Event.DOWN:


			ListItemWidget  next = list.getItem(list.indexOf(list.selectedItem()) + 1);


			if (next != null) {


			    list.setValue(next);


			    list.focusContent(next.x, next.y, next.width, next.height + 5);


			}


			return true;





		    case Event.LEFT:


		    case Event.UP:


			ListItemWidget  previous = list.getItem(list.indexOf(list.selectedItem()) - 1);


			if (previous != null) {


			    list.setValue(previous);


			    list.focusContent(previous.x, previous.y, previous.width, previous.height);


			}


			return true;





		    case Event.HOME:


			ListItemWidget  first = list.getItem(0);


			list.setValue(first);


			list.focusContent(first.x, first.y, first.width, first.height);


			return true;





		    case Event.END:


			ListItemWidget  last = list.getItem(list.countItems() - 1);


			list.setValue(last);


			list.focusContent(last.x, last.y, last.width, last.height + 5);


			return true;


		}


		break;


	}





	if (evt.target == list) {


	    switch (evt.id) {


		case Event.ACTION_EVENT:


		    action();


		    return true;





		case Event.LIST_SELECT:


		    requestFocus();


		    setValue(list.getIntegerValue());


		    return false;


	    }


	}


	return super.handleEvent(evt);


    }





    /**


     * Supports input focus.


     */


    public boolean focusInterest() {


	return !disabled && list.countItems() > 0;


    }


}








/**


 * The list used for the listbox does not restrict the


 * items to be the width of the list itself, items


 * can be wider.


 *


 * @author	Klaas Waslander


 * @version 	1.26, 12/18/96


 */


class ListBoxContent extends ListWidget {


    /**


     * Layout the content.


     */


    public void layout(Widget w) {


	if (w.nwidgets == 0) {


	    setContentSize(0, 0);


	    return;


	}





	FontMetrics  fm = getFontMetrics(font);


	int  maxWidth = 0;


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


	    Widget item = w.widgets[i];


	    maxWidth = Math.max(maxWidth, fm.stringWidth(item.getText()));


	}


	int y = 5;


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


	    Widget item = w.widgets[i];


	    item.reshape(7, y, maxWidth + 7, fm.getHeight() + 2);


	    item.validate();


	    y += item.height;


	}


	setContentSize(maxWidth + 14, y + 5);


    }





    /**


     * Allocate the content and disable the inline editor.


     */


    public Widget newContent() {


	GroupWidget  result = (GroupWidget)super.newContent();


	result.setEditing(false);


	return result;


    }


}


