package hirondelle.movies.util.ui;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

  <b>Standard dialog</b>, centralizing various display policies.
  <P>Using a standard class for all dialogs increases the uniformity of the application's
  appearance, and eliminates code repetition.
  <P>This standard dialog has the following characteristics :
  <li>it's centered on its owner
  <li>it can't be resized
  <li>it has a border of standard dimensions
  <li>it inherits the parent frame's icon
  <li>the title has standardized content
  <li>a row of buttons are placed at the bottom of the dialog, centered, 
  and with fixed spacing
  <li>the escape key performs the same operation as the {@link OnClose} value passed to
  the constructor
  <li>preserves the usual ALT+TAB behavior when switching between applications
  <P> Taken individually, such policies are relatively minor. Taken as a group, they form an
  effective way of establish the overall feel of your application.
  <P><b>Login dialogs</b><br>
  Login dialogs represent a special case, since they have no parent JFrame. Thus, they
  cannot inherit an icon. In JDK 6, this can be fixed, by adding a method to this class to
  specify the icon.
  <P>In addition, closing a login dialog should cause the application to exit. However,
  {@link JDialog#setDefaultCloseOperation(int)} does not allow for that behavior, while 
  this class does.
  <P><em>This class does not extend {@link JDialog}, since it 
    doesn't need to</em>. As a pleasant side-effect of this choice, the javadoc for this 
    class is <em>greatly</em> simplified.
public final class StandardDialog {

   Construct a standard dialog.
   @param aOwner the frame which is the owner/caller/parent of this dialog. This dialog
   gets its icon and its position from the owner. Possibly null. It's strongly recommened to use 
   a non-null owner.
   @param aTitle the text to appear on the title bar of this dialog
   @param aIsModal controls whether this dialog is modal: if <tt>true</tt>, then this
   dialog must be dismissed before you are allowed to return to the main window.
   @param aOnClose specifies desired behavior when this dialog closes 
   @param aBody the body of the dialog, where the user enters information
   @param aButtons a row of buttons appearing at the bottom of this dialog
  public StandardDialog (
    JFrame aOwner, String aTitle, boolean aIsModal, OnClose aOnClose, 
    JPanel aBody, java.util.List<JButton> aButtons
  ) {
    String title = UiUtil.getDialogTitle(aTitle);
    fDialog = new JDialog(aOwner, title, aIsModal);
    JPanel content = new JPanel();
    content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));

   Display the dialog.
   <P> The dialog is not automatically displayed in the constructor. This is because some
   callers may want to build a dialog upon startup, but only display it later. (Such a
   style might be chosen in order to slightly improve the apparent responsiveness of the
  public void display() {

  /** Assign a default button for this dialog. */
  public void setDefaultButton(JButton aButton) {

  /** Call <tt>dispose</tt> on the underlying dialog object. */
  public void dispose() {

  /** Return the underlying dialog object.   */
  public JDialog getDialog() {
    return fDialog;

  private JDialog fDialog;

    Force the escape key to call the same action as the default {@link OnClose} operation
    passed to the constructor. In some special cases, this does not always work.
  private void addCancelByEscapeKey(final OnClose aOnClose) {
    int noModifiers = 0;
    KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, noModifiers, false);
    InputMap inputMap = fDialog.getRootPane().getInputMap(
    inputMap.put(escapeKey, CANCEL_ACTION_KEY);
    AbstractAction cancelAction = new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        if (OnClose.DO_NOTHING == aOnClose) {
          // do nothing
        else if (OnClose.DISPOSE == aOnClose) {
        else if (OnClose.HIDE == aOnClose) {
        else if (OnClose.EXIT == aOnClose) {
        else {
          throw new AssertionError("Unexpected branch for this value of OnClose: " + aOnClose);
    fDialog.getRootPane().getActionMap().put(CANCEL_ACTION_KEY, cancelAction);

  private JPanel buildButtonPanel(java.util.List<JButton> aButtons) {
    JPanel result = new JPanel();
    result.setLayout(new BoxLayout(result, BoxLayout.LINE_AXIS));
    int count = 0;
    for (JButton button : aButtons) {
      if (count < aButtons.size()) {
    return result;