//
// @(#)HeaderDialog.java 1.00 4/1/2002
//
// Copyright 2002 Zachary DelProposto. All rights reserved.
// Use is subject to license terms.
//
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// Or from http://www.gnu.org/
//
package dip.gui.dialog;
import dip.gui.swing.*;
import dip.misc.Utils;
import dip.gui.*;
// HIGLayout
import cz.autel.dmi.HIGConstraints;
import cz.autel.dmi.HIGLayout;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import java.awt.Paint;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.geom.Line2D;
import java.awt.Insets;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Component;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.AbstractButton;
import javax.swing.JSeparator;
import javax.swing.BoxLayout;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
import javax.swing.border.EtchedBorder;
import javax.swing.event.*;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.BorderFactory;
/**
* A Dialog with an HTML message header at the top,
* which may be of fixed height (or adjust to fit).
*
* <p>
* A configurable lower bar (usually for buttons)
* is also available. Components other than buttons
* may be added to this lower bar. Any component that
* implements JButton can be used as a default button,
* and/or close button. Components are added from the
* left to right.
*
* <p>
* All buttons <b>must</b> have an action command set
* if they call the close() method. Buttons created with
* the convenience methods will have an action command set.
*
*/
public class HeaderDialog extends XDialog
{
/** Default margin between button bar edge and components */
public final static int BTN_BAR_EDGE = 5;
/** Default spacint between buttun bar buttons */
public final static int BTN_BAR_BETWEEN = 10;
/** OK Button Action Command; constant across languages */
public final static String ACTION_OK = "ACTION_OK";
/** Close Button Action Command; constant across languages */
public final static String ACTION_CLOSE = "ACTION_CLOSE";
/** Cancel Button Action Command; constant across languages */
public final static String ACTION_CANCEL = "ACTION_CANCEL";
/** Accept button Action Command; constant across languages */
public final static String ACTION_ACCEPT = "ACTION_ACCEPT";
private static JButton sizerButton = new JButton(TEXT_CANCEL); // used to size buttons
private String defaultCloseButtonAction = null;
private String returnedAction = null;
private JPanel btnPanel = null;
private JComponent separator = null;
private Container content = new JPanel();
private JPanel btnPanelHolder = null; // holds btnPanel, and separator (if present)
private ArrayList btnList = null;
protected JEditorPane header = null;
/** Create a Dialog with a HTML-aware Header */
public HeaderDialog(JFrame parent, String title, boolean isModal)
{
super(parent, title, isModal);
// create main components
header = new GradientXJEditorPane();
btnPanelHolder = new JPanel(new BorderLayout());
btnPanel = new JPanel();
btnPanel.setLayout( new BoxLayout(btnPanel, BoxLayout.X_AXIS) );
btnPanel.setBorder(BorderFactory.createEmptyBorder(BTN_BAR_EDGE,BTN_BAR_EDGE,BTN_BAR_EDGE,BTN_BAR_EDGE));
btnList = new ArrayList();
// do layout
makeLayout();
}// HeaderDialog()
/**
* Set the dialog content; this may be
* called at any time.
*/
public void setContentPane(Container container)
{
if(container == null) { throw new IllegalArgumentException(); }
Container contentPanel = super.getContentPane();
// remove old content
contentPanel.remove(content);
// add new content
content = container;
contentPanel.add(content, BorderLayout.CENTER);
}// setContentPane()
/** Get the content panel */
public Container getContentPane()
{
return content;
}// getContentPane()
/** Add a component to the button bar (left to right) */
public void addToButtonPanel(Component component)
{
btnPanel.add(component);
if(component instanceof JButton)
{
btnList.add(component);
equalizeButtons();
}
}// addToButtonPanel()
/** Set the button that is focus-selected by default */
public void setDefaultButton(JButton btn)
{
if(btn == null) { throw new IllegalArgumentException(); }
getRootPane().setDefaultButton(btn);
}// setDefaultReturn()
/** Get the default button */
public JButton getDefaultButton()
{
return getRootPane().getDefaultButton();
}// getDefaultButton()
/**
* Get the JButton of the given index; throws an
* exception if index is out of bounds.
* <p>
* Index 0 is the leftmost button.
*/
public JButton getButton(int i)
{
return (JButton) btnList.get(i);
}// getButton()
/**
* Sets the JButton that the close(actionCommand)
* method will have as its argument.
*/
public void setDefaultCloseButton(JButton btn)
{
if(btn == null) { throw new IllegalArgumentException(); }
defaultCloseButtonAction = btn.getActionCommand();
}// setDefaultCloseValue()
/**
* Called when the dialog is closing. Subclasses should
* subclass this method instead of close(); to close
* the dialog, subclasses
*/
protected void close(String actionCommand)
{
returnedAction = actionCommand;
super.close();
}// close()
/**
* Do not override this method!
*/
protected final void close()
{
close(defaultCloseButtonAction);
}// close()
/** Make an "OK" button (i18n); calls close with self. */
public JButton makeOKButton()
{
return makeButton(TEXT_OK, ACTION_OK, true);
}// makeOKButton()
/** Make an "Cancel" button (i18n); calls close with self. */
public JButton makeCancelButton()
{
return makeButton(TEXT_CANCEL, ACTION_CANCEL, true);
}// makeCancelButton()
/** Make an "Close" button (i18n); calls close with self. */
public JButton makeCloseButton()
{
return makeButton(TEXT_CLOSE, ACTION_CLOSE, true);
}// makeCloseButton()
/** Make an "Accept" button (i18n); calls close with self. */
public JButton makeAcceptButton()
{
return makeButton(TEXT_ACCEPT, ACTION_ACCEPT, true);
}// makeAcceptButton()
/** Convenience method: check if action command is OK or Accept */
public boolean isOKorAccept(String actionCommand)
{
if( actionCommand.equals(ACTION_OK) ||
actionCommand.equals(ACTION_ACCEPT) )
{
return true;
}
return false;
}// isOKorAccept()
/** Convenience method: check if action command is Close or Cancel */
public boolean isCloseOrCancel(String actionCommand)
{
if( actionCommand.equals(ACTION_CLOSE) ||
actionCommand.equals(ACTION_CANCEL) )
{
return true;
}
return false;
}// isCloseOrCancel()
/**
* Make a button with the given text; calls close() with self
* if boolean flag is set to 'true'.
*/
public JButton makeButton(String text, String actionCommand, boolean doClose)
{
final JButton btn = new JButton(text);
btn.setMinimumSize(btn.getPreferredSize());
btn.setActionCommand(actionCommand);
if(doClose)
{
btn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
close(btn.getActionCommand());
}
});
}
return btn;
}// makeButton()
/**
* Enable or Disable a button based upon actionCommand.
* Button must have been added to the button panel.
* ActionCommand CANNOT be null.
*/
public void setButtonEnabled(String actionCommand, boolean enabled)
{
if(actionCommand == null)
{
throw new IllegalArgumentException();
}
Iterator iter = btnList.iterator();
while(iter.hasNext())
{
JButton b = (JButton) iter.next();
if( actionCommand.equals(b.getActionCommand()) )
{
b.setEnabled(enabled);
break;
}
}
}// setButtonEnabled()
/** Make a spacer of the desired width in pixels */
public static Component makeSpacer(int width)
{
return Box.createHorizontalStrut(width);
}// makeSpacer()
/** Make a glue component (takes up as much space as possible) */
public static Component makeGlue()
{
return Box.createHorizontalGlue();
}// makeGlue()
/**
* Convenience method: for dialogs with ONE button, and
* no other components to be added to the button bar, adds
* the given button to the button bar, with the appropriate
* spacing. It also sets it as the default and default close
* button.
*/
public void addSingleButton(JButton button)
{
addToButtonPanel( makeGlue() );
addToButtonPanel(button);
setDefaultButton(button);
setDefaultCloseButton(button);
}// addSingleButton()
/**
* Convenience method: for dialogs with TWO buttons, and
* no other components to be added to the button bar, adds
* the given buttons to the button bar, with the appropriate
* spacing. It also sets it as the default and default close
* button, depending upon the boolean value.
* <p>
* Typically, the "cancel" button is the rightmost, and is
* the same as the default dialog close button.
*/
public void addTwoButtons(JButton rightMost, JButton leftMost,
boolean rightDefault, boolean rightClose)
{
addToButtonPanel( makeGlue() );
addToButtonPanel(leftMost);
addToButtonPanel(makeSpacer(BTN_BAR_BETWEEN));
addToButtonPanel(rightMost);
setDefaultButton((rightDefault) ? rightMost : leftMost);
setDefaultCloseButton((rightClose) ? rightMost : leftMost);
}// addTwoButtons()
/**
* Adds 3 buttons:<br>
* Right (right-aligned)<br>
* Middle (closer to Right button)<br>
* Left (left-aligned)<br>
* Default and Default Close actions are also settable.
*/
public void addThreeButtons(JButton left, JButton center, JButton right,
JButton defaultButton, JButton closeButton)
{
addToButtonPanel(left);
addToButtonPanel( makeGlue() );
addToButtonPanel(makeSpacer(BTN_BAR_BETWEEN));
addToButtonPanel(center);
addToButtonPanel(makeSpacer(BTN_BAR_BETWEEN));
addToButtonPanel(right);
setDefaultButton(defaultButton);
setDefaultCloseButton(closeButton);
}// addThreeButtons()
/**
* Creates a default border around the given component,
* of BTN_BAR_EDGE size, except at bottom.
*/
public void createDefaultContentBorder(JComponent comp)
{
comp.setBorder( BorderFactory.createEmptyBorder(BTN_BAR_EDGE,
BTN_BAR_EDGE, 0, BTN_BAR_EDGE) );
}// createDefaultContentBorder()
/**
* Show or Hide the separator between the button and content panels.
* No separator is shown by default. Margin values must be 0 or
* greater.
*/
public void setSeparatorVisible(boolean value, int horizontalMargin, int verticalMargin)
{
if(horizontalMargin < 0 || verticalMargin < 0) { throw new IllegalArgumentException(); }
// remove old separator, if any
if(separator != null)
{
btnPanelHolder.remove(separator);
}
// create and add a new separator
if(value)
{
if(horizontalMargin > 0 || verticalMargin > 0)
{
separator = new JPanel(new BorderLayout());
separator.setBorder(new EmptyBorder(verticalMargin, horizontalMargin,
verticalMargin, horizontalMargin));
separator.add(new JSeparator());
}
else
{
separator = new JSeparator();
}
btnPanelHolder.add(separator, BorderLayout.NORTH);
}
}// setSeparatorVisible()
/**
* Show or hide the header. By default, the header is visible.
*/
public void setHeaderVisible(boolean value)
{
Container contentPanel = super.getContentPane();
if(value)
{
contentPanel.add(header, BorderLayout.NORTH);
}
else
{
contentPanel.remove(header);
}
}// setHeaderVisible()
/** Get the returned JButton ActionCommand used to close the dialog. */
public String getReturnedActionCommand()
{
return returnedAction;
}// getReturnedActionCommand()
/** Set the header text */
public void setHeaderText(String text)
{
header.setText(text);
header.setCaretPosition(0);
}// setText()
/** Called by the constructor to layout the dialog. */
private void makeLayout()
{
btnPanelHolder.add(btnPanel, BorderLayout.CENTER);
Container contentPanel = super.getContentPane();
contentPanel.setLayout(new BorderLayout());
contentPanel.add(header, BorderLayout.NORTH);
contentPanel.add(content, BorderLayout.CENTER);
contentPanel.add(btnPanelHolder, BorderLayout.SOUTH);
}// makeLayout()
/** Equalize the size of the buttons; at least as big as 'Cancel' button. */
private void equalizeButtons()
{
Dimension maxPref = sizerButton.getPreferredSize();
Iterator iter = btnList.iterator();
while(iter.hasNext())
{
JButton btn = (JButton) iter.next();
Dimension size = btn.getPreferredSize();
maxPref.width = (size.width > maxPref.width) ? size.width : maxPref.width;
maxPref.height = (size.height > maxPref.height) ? size.height : maxPref.height;
}
iter = btnList.iterator();
while(iter.hasNext())
{
JButton btn = (JButton) iter.next();
btn.setPreferredSize(maxPref);
}
}// equalizeButtons()
/**
* A gradient-shaded background XJEditorPane with a stylish
* bottom separator.
*/
public static class GradientXJEditorPane extends XJEditorPane
{
// header inset (inner-margin)
private static final int MARGIN = 5;
/** Create a GradientXJEditorPane */
public GradientXJEditorPane()
{
super();
setOpaque(false);
customize();
}// GradientXJEditorPane()
/** We are not opaque; we will paint the background. */
public boolean isOpaque() { return false; }
/** We are not focusable. */
public boolean isFocusable() { return false; }
/** Overridden to provide painting functionality. */
protected void paintComponent(Graphics g)
{
final int width = getWidth();
final int height = getHeight();
Graphics2D g2d = (Graphics2D) g;
// save old paint.
Paint oldPaint = g2d.getPaint();
// paint the gradient.
g2d.setPaint(new GradientPaint(0, 0,
UIManager.getColor("TextField.highlight"),
width, height,
UIManager.getColor("Label.background"), false));
g2d.fillRect(0, 0, width, height);
// paint the separator
g2d.setPaint(UIManager.getColor("Separator.foreground"));
g2d.draw(new Line2D.Float(0,height-2, width,height-2));
g2d.setPaint(UIManager.getColor("Separator.background"));
g2d.draw(new Line2D.Float(0,height-1, width,height-1));
// restore the original paint
g2d.setPaint(oldPaint);
// paint foreground
super.paintComponent(g);
}// paintComponent()
/** jDip-specific setup */
private void customize()
{
setContentType("text/html");
Document doc = getDocument();
if(doc instanceof HTMLDocument)
{
((HTMLDocument)doc).setBase(Utils.getResourceBase());
}
setMargin(new Insets(MARGIN, MARGIN, MARGIN, MARGIN));
setEditable(false);
setHighlighter(null);
setSelectedTextColor(null); // per BugID 4532590
}// customize()
}// nested class GradientXJEditorPane
}// class HeaderDialog