QuickSetupStepPanel.java revision 6292beaede500c125091a84263ed7cda454ba299
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2015 ForgeRock AS.
*/
package org.opends.quicksetup.ui;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.HashMap;
import java.util.HashSet;
import javax.swing.Box;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import org.opends.quicksetup.event.ButtonActionListener;
import org.opends.quicksetup.event.ButtonEvent;
import org.opends.quicksetup.ProgressDescriptor;
import org.opends.quicksetup.UserData;
import org.opends.quicksetup.util.HtmlProgressMessageFormatter;
import org.opends.quicksetup.util.ProgressMessageFormatter;
import org.opends.quicksetup.util.URLWorker;
import org.forgerock.i18n.LocalizableMessage;
import static org.opends.messages.QuickSetupMessages.*;
/**
* This is an abstract class that is extended by all the classes that are in
* the CardLayout of CurrentStepPanel. All the panels that appear on the
* top-right side of the dialog extend this class: WelcomePane, ReviewPanel,
* etc.
*
*/
public abstract class QuickSetupStepPanel extends QuickSetupPanel
implements HyperlinkListener
{
private static final long serialVersionUID = -1983448318085588324L;
private JPanel inputContainer;
private Component inputPanel;
private HashSet<ButtonActionListener> buttonListeners = new HashSet<>();
private ProgressMessageFormatter formatter;
private static final String INPUT_PANEL = "input";
private static final String CHECKING_PANEL = "checking";
private boolean isCheckingVisible;
/**
* We can use a HashMap (not multi-thread safe) because all
* the calls to this object are done in the event-thread.
*/
private HashMap<String, URLWorker> hmURLWorkers = new HashMap<>();
/**
* Creates a default instance.
* @param application Application this panel represents
*/
public QuickSetupStepPanel(GuiApplication application) {
super(application);
}
/**
* Initializes this panel. Called soon after creation. In general this
* is where maps should be populated etc.
*/
public void initialize() {
createLayout();
}
/**
* Called just before the panel is shown: used to update the contents of the
* panel with new UserData (used in particular in the review panel).
*
* @param data the new user data.
*/
public void beginDisplay(UserData data)
{
}
/**
* Called just after the panel is shown: used to set focus properly.
*/
public void endDisplay()
{
}
/**
* Tells whether the method beginDisplay can be long and so should be called
* outside the event thread.
* @return <CODE>true</CODE> if the method beginDisplay can be long and so
* should be called outside the event thread and <CODE>true</CODE> otherwise.
*/
public boolean blockingBeginDisplay()
{
return false;
}
/**
* Called when a progress change must be reflected in the panels. Only
* ProgressPanel overwrites this method and for all the others it stays empty.
* @param descriptor the descriptor of the Installation progress.
*/
public void displayProgress(ProgressDescriptor descriptor)
{
}
/**
* Implements HyperlinkListener. When the user clicks on a link we will
* try to display the associated URL in the browser of the user.
*
* @param e the HyperlinkEvent.
*/
public void hyperlinkUpdate(HyperlinkEvent e)
{
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
{
String url = e.getURL().toString();
if (!isURLWorkerRunning(url))
{
/*
* Only launch the worker if there is not already a worker trying to
* display this URL.
*/
URLWorker worker = new URLWorker(this, url);
startWorker(worker);
}
}
}
/**
* Returns the value corresponding to the provided FieldName.
* @param fieldName the FieldName for which we want to obtain the value.
* @return the value corresponding to the provided FieldName.
*/
public Object getFieldValue(FieldName fieldName)
{
return null;
}
/**
* Marks as invalid (or valid depending on the value of the invalid parameter)
* a field corresponding to FieldName. This basically implies udpating the
* style of the JLabel associated with fieldName (the association is done
* using the LabelFieldDescriptor class).
* @param fieldName the FieldName to be marked as valid or invalid.
* @param invalid whether to mark the field as valid or invalid.
*/
public void displayFieldInvalid(FieldName fieldName, boolean invalid)
{
}
/**
* Returns the minimum width of the panel. This is used to calculate the
* minimum width of the dialog.
* @return the minimum width of the panel.
*/
public int getMinimumWidth()
{
// Just take the preferred width of the inputPanel because the
// instructionsPanel
// are too wide.
int width = 0;
if (inputPanel != null)
{
width = (int) inputPanel.getPreferredSize().getWidth();
}
return width;
}
/**
* Returns the minimum height of the panel. This is used to calculate the
* minimum height of the dialog.
* @return the minimum height of the panel.
*/
public int getMinimumHeight()
{
return (int) getPreferredSize().getHeight();
}
/**
* Adds a button listener. All the button listeners will be notified when
* the buttons are clicked (by the user or programatically).
* @param l the ButtonActionListener to be added.
*/
public void addButtonActionListener(ButtonActionListener l)
{
buttonListeners.add(l);
}
/**
* Removes a button listener.
* @param l the ButtonActionListener to be removed.
*/
public void removeButtonActionListener(ButtonActionListener l)
{
buttonListeners.remove(l);
}
/**
* This method displays a working progress icon in the panel.
* @param visible whether the icon must be displayed or not.
*/
public void setCheckingVisible(boolean visible)
{
if (visible != isCheckingVisible && inputContainer != null)
{
CardLayout cl = (CardLayout) inputContainer.getLayout();
if (visible)
{
cl.show(inputContainer, CHECKING_PANEL);
}
else
{
cl.show(inputContainer, INPUT_PANEL);
}
isCheckingVisible = visible;
}
}
/**
* Returns the text to be displayed in the progress label for a give icon
* type.
* @param iconType the icon type.
* @return the text to be displayed in the progress label for a give icon
* type.
*/
protected LocalizableMessage getTextForIcon(UIFactory.IconType iconType)
{
LocalizableMessage text;
if (iconType == UIFactory.IconType.WAIT)
{
text = INFO_GENERAL_CHECKING_DATA.get();
}
else
{
text = LocalizableMessage.EMPTY;
}
return text;
}
/**
* Notifies the button action listeners that an event occurred.
* @param ev the button event to be notified.
*/
protected void notifyButtonListeners(ButtonEvent ev)
{
for (ButtonActionListener l : buttonListeners)
{
l.buttonActionPerformed(ev);
}
}
/**
* Creates the layout of the panel.
*
*/
protected void createLayout()
{
setLayout(new GridBagLayout());
setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
Component titlePanel = createTitlePanel();
Component instructionsPanel = createInstructionsPanel();
inputPanel = createInputPanel();
boolean somethingAdded = false;
if (titlePanel != null)
{
gbc.weightx = 1.0;
gbc.weighty = 0.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets.left = 0;
add(titlePanel, gbc);
somethingAdded = true;
}
if (instructionsPanel != null)
{
if (somethingAdded)
{
gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD;
} else
{
gbc.insets.top = 0;
}
gbc.insets.left = 0;
gbc.weightx = 1.0;
gbc.weighty = 0.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.NORTHWEST;
add(instructionsPanel, gbc);
somethingAdded = true;
}
if (inputPanel != null)
{
inputContainer = new JPanel(new CardLayout());
inputContainer.setOpaque(false);
if (requiresScroll())
{
inputContainer.add(UIFactory.createBorderLessScrollBar(inputPanel),
INPUT_PANEL);
}
else
{
inputContainer.add(inputPanel, INPUT_PANEL);
}
JPanel checkingPanel = UIFactory.makeJPanel();
checkingPanel.setLayout(new GridBagLayout());
checkingPanel.add(UIFactory.makeJLabel(UIFactory.IconType.WAIT,
INFO_GENERAL_CHECKING_DATA.get(),
UIFactory.TextStyle.PRIMARY_FIELD_VALID),
new GridBagConstraints());
inputContainer.add(checkingPanel, CHECKING_PANEL);
if (somethingAdded)
{
gbc.insets.top = UIFactory.TOP_INSET_INPUT_SUBPANEL;
} else
{
gbc.insets.top = 0;
}
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets.left = 0;
add(inputContainer, gbc);
}
else
{
addVerticalGlue(this);
}
}
/**
* Creates and returns the panel that contains the layout specific to the
* panel.
* @return the panel that contains the layout specific to the
* panel.
*/
protected abstract Component createInputPanel();
/**
* Returns the title of this panel.
* @return the title of this panel.
*/
protected abstract LocalizableMessage getTitle();
/**
* Returns the instruction of this panel.
* @return the instruction of this panel.
*/
protected abstract LocalizableMessage getInstructions();
/**
* Commodity method that adds a vertical glue at the bottom of a given panel.
* @param panel the panel to which we want to add a vertical glue.
*/
protected void addVerticalGlue(JPanel panel)
{
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = UIFactory.getEmptyInsets();
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.VERTICAL;
panel.add(Box.createVerticalGlue(), gbc);
}
/**
* This method is called by the URLWorker when it has finished its task.
* @param worker the URLWorker that finished its task.
*/
public void urlWorkerFinished(URLWorker worker)
{
hmURLWorkers.remove(worker.getURL());
}
/**
* Tells whether the input panel should have a scroll or not.
* @return <CODE>true</CODE> if the input panel should have a scroll and
* <CODE>false</CODE> otherwise.
*/
protected boolean requiresScroll()
{
return true;
}
/**
* Returns the formatter that will be used to display the messages in this
* panel.
* @return the formatter that will be used to display the messages in this
* panel.
*/
ProgressMessageFormatter getFormatter()
{
if (formatter == null)
{
formatter = new HtmlProgressMessageFormatter();
}
return formatter;
}
/**
* Creates and returns the title panel.
* @return the title panel.
*/
private Component createTitlePanel()
{
Component titlePanel = null;
LocalizableMessage title = getTitle();
if (title != null)
{
JPanel p = new JPanel(new GridBagLayout());
p.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.0;
gbc.gridwidth = GridBagConstraints.RELATIVE;
JLabel l =
UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, title,
UIFactory.TextStyle.TITLE);
p.add(l, gbc);
gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
p.add(Box.createHorizontalGlue(), gbc);
titlePanel = p;
}
return titlePanel;
}
/**
* Creates and returns the instructions panel.
* @return the instructions panel.
*/
protected Component createInstructionsPanel()
{
Component instructionsPanel = null;
LocalizableMessage instructions = getInstructions();
if (instructions != null)
{
JEditorPane p =
UIFactory.makeHtmlPane(instructions, UIFactory.INSTRUCTIONS_FONT);
p.setOpaque(false);
p.setEditable(false);
p.addHyperlinkListener(this);
instructionsPanel = p;
}
return instructionsPanel;
}
/**
* Returns <CODE>true</CODE> if there is URLWorker running for the given url
* and <CODE>false</CODE> otherwise.
* @param url the url.
* @return <CODE>true</CODE> if there is URLWorker running for the given url
* and <CODE>false</CODE> otherwise.
*/
private boolean isURLWorkerRunning(String url)
{
return hmURLWorkers.get(url) != null;
}
/**
* Starts a worker.
* @param worker the URLWorker to be started.
*/
private void startWorker(URLWorker worker)
{
hmURLWorkers.put(worker.getURL(), worker);
worker.startBackgroundTask();
}
}