// ============================================================================
// File:               RJComboBox.java
//
// Project:            I18n support.
//
// Purpose:            A combo box with changeable items.
//
// Author:             Rammi
//-----------------------------------------------------------------------------
// Copyright Notice:   (c) 2002  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================

package de.caff.i18n.swing;

import de.caff.i18n.I18n;
import de.caff.i18n.Localizable;

import javax.swing.*;
import java.awt.*;
import java.util.Locale;


/**
 *  A combo box with resource.
 *  @author <a href="mailto:rammi@caff.de">Rammi</a>
 *  @version $Revision$
 */
public class RJComboBox 
  extends    JComboBox 
  implements Localizable 
{
  protected boolean   localeUnknown = true;          // flag wether Locale is already known
  protected String[]  resTags = new String[0];       // resource tags for items

  /**
   *  Constructs a new RJComboBox.
   */
  public RJComboBox() {
    setEditable(false);
  }

  /**
   * Notifies this component that it now has a parent component.
   * When this method is invoked, the chain of parent components is
   * set up with <code>KeyboardAction</code> event listeners.
   */
  public void addNotify()
  {
    super.addNotify();
    I18n.addLocalizationChangeListener(this);
  }

  /**
   * Overrides <code>JComponent.removeNotify</code> to check if
   * this button is currently set as the default button on the
   * <code>RootPane</code>, and if so, sets the <code>RootPane</code>'s
   * default button to <code>null</code> to ensure the
   * <code>RootPane</code> doesn't hold onto an invalid button reference.
   */
  public void removeNotify()
  {
    I18n.removeLocalizationChangeListener(this);
    super.removeNotify();
  }


  /**
   *  Adds an resourced item to this choice.
   *  @param  tag   resource tag
   */
  public void add(String tag) {
    addItemTag(tag);
  }

  /**
   *  Adds an resourced item to this choice.
   *  @param  tag   resource tag
   */
  public void addItemTag(String tag) {
    // --- add to Choice ---
    super.addItem(I18n.getString(tag, getLocale()));

    // --- add resource ---
    String[] newTags = new String[resTags.length+1];
    if (resTags.length > 0) {
      System.arraycopy(resTags, 0, newTags, 0, resTags.length);
    }
    newTags[resTags.length] = tag;
    resTags = newTags;
  }

  /**
   *  Get the resource of the specified index.
   *  @param  index   the index
   *  @return resource tag of the item belonging to index
   */
  public String getTag(int index) {
    return resTags[index];
  }

  /**
   *  Get the resource of the selected item.
   *  @return resource tag of the selected item
   */
  public String getSelectedTag() {
    return resTags[getSelectedIndex()];
  }

  /**
   *  Inserts the resourced item into this choice at the specified position.
   *  @param  tag   resource tag
   *  @param  index position to insert
   */
  public void insertItemAt(String tag, int index) {
    // --- insert in Choice ---
    super.insertItemAt(I18n.getString(tag, getLocale()), index);

    // --- insert resource ---
    String[] newTags = new String[resTags.length+1];
    if (index > 0) {
      System.arraycopy(resTags, 0, newTags, 0, index);
    }
    newTags[index] = tag;
    if (index < resTags.length) {
      System.arraycopy(resTags, index, newTags, index+1, resTags.length-index);
    }
    resTags = newTags;
  }

  /**
   *  Removes the indexed item from the choice.
   *  @param  index  index to remove
   */
  public void remove(int index) {
    // --- remove in Choice ---
    super.remove(index);

    // --- remove in resource ---
    String[] newTags = new String[resTags.length-1];
    if (index > 0) {
      System.arraycopy(resTags, 0, newTags, 0, index);
    }
    if (index < resTags.length-1) {
      System.arraycopy(resTags, index+1, newTags, index, resTags.length-index-1);
    }
    resTags = newTags;
  }

  /**
   *  Removes the first occurence of given resource tag.
   *  @param  tag   tag to remove
   */
  public void remove(String tag) {
    // --- find tag ...
    for (int i = 0;   i < resTags.length;   i++) {
      if (resTags[i].equals(tag)) {
	// ... and remove ---
	remove(i);
	return;
      }
    }
  }

  /**
   *  Removes all items.
   */
  public void removeAll() {
    super.removeAll();
    resTags = new String[0];
  }


  /**
   *  Select the resourced item.
   *  @param  tag   resource tag of item
   */
  public void setSelectedIndex(String tag) {
    // --- find tag ...
    for (int i = 0;   i < resTags.length;   i++) {
      if (resTags[i].equals(tag)) {
	// ... and select ---
	setSelectedIndex(i);
	return;
      }
    }
  }

  /**
   *  Change the locale.
   *  @param  l   new locale
   */
  public void setLocale(Locale l) {
    Locale oldLocale = getLocale();
    super.setLocale(l);

    if (oldLocale != null  &&  !oldLocale.equals(l)) {
      int selected = getSelectedIndex();
      for (int i = getItemCount()-1;   i >= 0;  i--) {
        super.remove(i);
      }
      for (int t = 0;   t < resTags.length;   t++) {
        super.addItem(I18n.getString(resTags[t], getLocale()));
      }
      setSelectedIndex(selected);
    
      invalidate();
    }
  }

  /**
   *  Get the locale. Instead of throwing an <code>IllegalComponentStateException</code>
   *  when there's no locale we just return null.
   *  @return the Locale of this Label or null
   */
  public Locale getLocale() {
    try {
      localeUnknown = false;
      return super.getLocale();
    } catch (IllegalComponentStateException x) {
      localeUnknown = true;
      return null;
    }
  }


  /**
   *  If we paint without knowing the locale we try to get and set it.
   *  @param  g   graphics context
   */
  public void update(Graphics g) {
    if (localeUnknown) {
      setLocale(getLocale());
      // no need to paint
    }
    else {
      super.update(g);
    }
  }
}
