/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.framework.ui.dialog;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.border.EmptyBorder;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext;
import org.eclipse.persistence.tools.workbench.utility.string.StringTools;
/**
* This dialog is similar to it superclass, AbstractDialog, with the added
* value of an error message label below the main panel. A subclass
* can set this error message as needed so that it can inform the user
* something incorrect has been entered.
*
* <pre>
* ________________________________________
* | Title |
* |--------------------------------------|
* | ____________________________________ |
* | | | |
* | | | |
* | | Main panel | |
* | | | |
* | | | |
* | ------------------------------------ |
* | Error Message (or Warning Message) |
* | ____________________________________ |
* | ______ ________ ____ ________ |
* | |Help| |Custom| |OK| |Cancel| |
* | ------ -------- ---- -------- |
* ----------------------------------------
* </pre>
* If there is an error message, it will be shown. If there is a warning
* message, it will only be shown if there is no error message.
* Warning messages have a different icon than error messages.
*
* Subclasses can CALL the following methods:
* - setErrorMessage(String)
* - setErrorMessageKey(String)
* - clearErrorMessage()
* - setWarningMessage(String)
* - setWarningMessageKey(String)
* - clearWarningMessage()
*/
public abstract class AbstractValidatingDialog
extends AbstractDialog
{
/** Shown if there is an error */
private JLabel errorMessageLabel;
/** Shown if there is a warning, but only if there is also no error */
private JLabel warningMessageLabel;
/** Used to fire the accessible event that JAWS will use to read dynamic text. */
JLabel accessibleLabel;
// ********** constructors **********
protected AbstractValidatingDialog(WorkbenchContext context) {
super(context);
}
protected AbstractValidatingDialog(WorkbenchContext context, String title) {
super(context, title);
}
protected AbstractValidatingDialog(WorkbenchContext context, String title, Dialog owner) {
super(context, title, owner);
}
// ********** initialization **********
protected void initializeContentPane() {
this.container.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
container.setOpaque(false);
contentPane.add(container, BorderLayout.CENTER);
// main panel
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.PAGE_START;
constraints.insets = new Insets(5, 5, 0, 5);
this.container.add(this.buildMainPanel(), constraints);
// error message
this.errorMessageLabel = this.buildErrorMessageLabel();
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(5, 5, 0, 5);
this.container.add(this.errorMessageLabel, constraints);
// warning message
this.warningMessageLabel = this.buildWarningMessageLabel();
constraints.gridx = 0;
constraints.gridy = 2;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(5, 5, 0, 5);
this.container.add(this.warningMessageLabel, constraints);
// separator
constraints.gridx = 0;
constraints.gridy = 3;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(10, 5, 10, 5);
this.container.add(new JSeparator(), constraints);
// button panel
JPanel buttonPanel = this.buildButtonPanel();
buttonPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
constraints.gridx = 0;
constraints.gridy = 4;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(0, 0, 0, 0);
this.container.add(buttonPanel, constraints);
// Used for accessibility purposes
StatusBarPane statusBarPane = new StatusBarPane();
constraints.gridx = 0;
constraints.gridy = 5;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.CENTER;
constraints.insets = new Insets(0, 0, 0, 0);
this.container.add(statusBarPane, constraints);
}
// ********** opening **********
/*
* Set the errorMessageLabel to not visible so the dialog
* will not resize or get squished when the error is shown.
* If the label is made invisible before the dialog is
* opened, its size will not be taken into account.
* Blame GridBagLayout....
*/
protected void windowOpened() {
super.windowOpened();
if (StringTools.stringIsEmpty(this.errorMessageLabel.getText())) {
this.errorMessageLabel.setVisible(false);
}
if (this.errorMessageLabel.isVisible() || StringTools.stringIsEmpty(this.warningMessageLabel.getText())) {
this.warningMessageLabel.setVisible(false);
}
}
// ********** error message **********
protected JLabel buildErrorMessageLabel() {
JLabel label = new JLabel();
label.setIcon(this.resourceRepository().getIcon("error"));
label.setPreferredSize(new Dimension(300, 16));
return label;
}
protected void clearErrorMessage() {
this.setErrorMessage(null);
}
protected JLabel getErrorMessageLabel() {
return this.errorMessageLabel;
}
protected void setErrorMessage(String message) {
this.errorMessageLabel.setText(message);
boolean visible = !StringTools.stringIsEmpty(message);
if (this.errorMessageLabel.isVisible() != visible && this.isVisible()) {
this.errorMessageLabel.setVisible(visible);
}
// set the warning message to invisible if the error message is visible
if (this.errorMessageLabel.isVisible() && this.warningMessageLabel.isVisible()) {
this.warningMessageLabel.setVisible(false);
}
this.updateAccessibleMessage(message);
}
/**
* convenience method for simple error message
*/
protected void setErrorMessageKey(String key) {
this.setErrorMessage(this.resourceRepository().getString(key));
}
/**
* convenience method for simple error message
*/
protected void setErrorMessageKey(String key, Object argument) {
this.setErrorMessage(this.resourceRepository().getString(key, argument));
}
// ********** warning message **********
protected JLabel buildWarningMessageLabel() {
JLabel label = new JLabel();
label.setIcon(this.resourceRepository().getIcon("warning"));
label.setPreferredSize(new Dimension(300, 16));
return label;
}
protected void clearWarningMessage() {
this.setWarningMessage(null);
}
protected JLabel getWarningMessageLabel() {
return this.warningMessageLabel;
}
protected void setWarningMessage(String message) {
this.warningMessageLabel.setText(message);
boolean visible = ! StringTools.stringIsEmpty(message) && ! this.errorMessageLabel.isVisible();
if (this.warningMessageLabel.isVisible() != visible && this.isVisible()) {
this.warningMessageLabel.setVisible(visible);
}
this.updateAccessibleMessage(message);
}
/**
* convenience method for simple error message
*/
protected void setWarningMessageKey(String key) {
this.setWarningMessage(this.resourceRepository().getString(key));
}
/**
* convenience method for simple error message
*/
protected void setWarningMessageKey(String key, Object argument) {
this.setWarningMessage(this.resourceRepository().getString(key, argument));
}
/**
* Updates the accessible description. This method does something only if the
* accessible label was initialized.
*/
protected void updateAccessibleMessage(String message) {
if (this.accessibleLabel != null) {
this.accessibleLabel.setText(message);
}
}
/**
* This panel takes care to support accessibility regarding the title and
* description to be read by JAWS.
*/
private class StatusBarPane extends JPanel {
public StatusBarPane() {
super(new BorderLayout());
}
private void buildStatusBar() {
AbstractValidatingDialog.this.accessibleLabel = new AccessibleLabel();
AbstractValidatingDialog.this.accessibleLabel.setVisible(false);
StatusBar statusBar = new StatusBar();
statusBar.setVisible(false);
statusBar.add(AbstractValidatingDialog.this.accessibleLabel);
add(statusBar, BorderLayout.CENTER);
validate();
}
/**
* Returns the <code>AccessibleContext</code> associated with this
* <code>ContentPane</code>.
*
* @return An <code>AccessibleContentPane</code> that serves as the
* <code>AccessibleContext</code> of this <code>ContentPane</code>
*/
public AccessibleContext getAccessibleContext() {
if (this.accessibleContext == null) {
this.accessibleContext = new AccessibleStatusBarPane();
buildStatusBar();
}
return this.accessibleContext;
}
/**
* The <code>AccessibleContext</code> of this pane.
*/
protected class AccessibleStatusBarPane extends AccessibleJPanel {
// nada
}
/**
* This <code>JLabel</code> is intended to fire an event that will ask
* JAWS to read the description.
*/
private class AccessibleLabel extends JLabel {
public void setText(String text) {
String oldText = getText();
super.setText(text);
if (this.accessibleContext != null) {
this.accessibleContext.firePropertyChange(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, oldText, text);
}
}
}
/**
* This <code>StatusBar</code> is required for JAWS to read the accessible
* label when a new text has been set.
*/
private class StatusBar extends JPanel {
public AccessibleContext getAccessibleContext() {
if (this.accessibleContext == null) {
this.accessibleContext = new AccessibleStatusBar();
}
return this.accessibleContext;
}
protected class AccessibleStatusBar extends AccessibleJPanel {
public AccessibleRole getAccessibleRole() {
return AccessibleRole.STATUS_BAR;
}
}
}
}
}