/*
|
* 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-2009 Sun Microsystems, Inc.
|
* Portions Copyright 2013-2014 ForgeRock AS.
|
*/
|
|
package org.opends.quicksetup.ui;
|
|
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowEvent;
|
import java.util.HashSet;
|
import org.forgerock.i18n.LocalizableMessage;
|
import org.forgerock.i18n.slf4j.LocalizedLogger;
|
|
|
import javax.swing.JButton;
|
import javax.swing.JFrame;
|
import javax.swing.JPanel;
|
import javax.swing.SwingUtilities;
|
import javax.swing.WindowConstants;
|
|
import org.opends.quicksetup.*;
|
import org.opends.quicksetup.event.ButtonActionListener;
|
import org.opends.quicksetup.event.ButtonEvent;
|
import org.opends.quicksetup.event.MinimumSizeComponentListener;
|
import org.opends.quicksetup.ProgressDescriptor;
|
/**
|
* This class represents the dialog used by quicksetup applications.
|
*
|
* In its constructor it gets as parameters an object describing the current
|
* installation status and the default values to be proposed to the user
|
* in the panels.
|
*
|
* If we are installing Open DS and the server has already been installed it
|
* will display an error message. In the other cases it will display a wizard.
|
*
|
*/
|
public class QuickSetupDialog
|
{
|
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
|
|
private JFrame frame;
|
|
private QuickSetupErrorPanel installedPanel;
|
|
private JPanel framePanel;
|
|
private StepsPanel stepsPanel;
|
|
private CurrentStepPanel currentStepPanel;
|
|
private ButtonsPanel buttonsPanel;
|
|
private WizardStep displayedStep;
|
|
private CurrentInstallStatus installStatus;
|
|
private HashSet<ButtonActionListener> buttonListeners =
|
new HashSet<ButtonActionListener>();
|
|
private GuiApplication application;
|
|
private QuickSetup quickSetup;
|
|
private boolean forceToDisplay;
|
|
/**
|
* Constructor of QuickSetupDialog.
|
* @param app Application to run in as a wizard
|
* @param installStatus of the current environment
|
* @param qs QuickSetup acting as controller
|
*/
|
public QuickSetupDialog(GuiApplication app,
|
CurrentInstallStatus installStatus,
|
QuickSetup qs)
|
{
|
if (app == null) {
|
throw new IllegalArgumentException("application cannot be null");
|
}
|
this.application = app;
|
this.installStatus = installStatus;
|
this.quickSetup = qs;
|
frame = new JFrame(String.valueOf(application.getFrameTitle()));
|
frame.getContentPane().add(getFramePanel());
|
frame.addWindowListener(new WindowAdapter() {
|
public void windowClosing(WindowEvent e) {
|
application.windowClosing(QuickSetupDialog.this, e);
|
}
|
});
|
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
Utilities.setFrameIcon(frame);
|
}
|
|
/**
|
* Packs and displays this dialog.
|
*
|
*/
|
public void packAndShow()
|
{
|
frame.pack();
|
int minWidth = (int) frame.getPreferredSize().getWidth();
|
int minHeight = (int) frame.getPreferredSize().getHeight();
|
Utilities.centerOnScreen(frame);
|
setFocusOnButton(application.getInitialFocusButtonName());
|
frame.addComponentListener(new MinimumSizeComponentListener(frame,
|
minWidth, minHeight));
|
|
frame.setVisible(true);
|
}
|
|
/**
|
* This method is called when we detected that there is something installed
|
* we inform of this to the user and the user wants to proceed with the
|
* installation destroying the contents of the data and the configuration
|
* in the current installation.
|
*/
|
public void forceToDisplay()
|
{
|
this.forceToDisplay = true;
|
framePanel = null;
|
frame.getContentPane().removeAll();
|
frame.getContentPane().add(getFramePanel());
|
frame.pack();
|
Utilities.centerOnScreen(frame);
|
setFocusOnButton(ButtonName.NEXT);
|
}
|
|
/**
|
* Displays the panel corresponding to the provided step. The panel contents
|
* are updated with the contents of the UserData object.
|
* @param step the step that we want to display.
|
* @param userData the UserData object that must be used to populate
|
* the panels.
|
*/
|
public void setDisplayedStep(WizardStep step, UserData userData)
|
{
|
displayedStep = step;
|
// First call the panels to do the required updates on their layout
|
getButtonsPanel().updateButtons(step);
|
getStepsPanel().setDisplayedStep(step, userData);
|
getCurrentStepPanel().setDisplayedStep(step, userData);
|
}
|
|
/**
|
* Returns the currently displayed step.
|
* @return the currently displayed step.
|
*/
|
public WizardStep getDisplayedStep()
|
{
|
return displayedStep;
|
}
|
|
/**
|
* Forwards to the displayed panel the ProgressDescriptor so that they
|
* can update their contents accordingly.
|
* @param descriptor the descriptor of the Installation progress.
|
*/
|
public void displayProgress(ProgressDescriptor descriptor)
|
{
|
getCurrentStepPanel().displayProgress(descriptor);
|
ProgressStep status = descriptor.getProgressStep();
|
if (status.isLast()) {
|
setButtonEnabled(ButtonName.CLOSE, true);
|
}
|
}
|
|
/**
|
* Displays an error message dialog.
|
*
|
* @param msg
|
* the error message.
|
* @param title
|
* the title for the dialog.
|
*/
|
public void displayError(LocalizableMessage msg, LocalizableMessage title)
|
{
|
Utilities.displayError(getFrame(), msg, title);
|
}
|
|
/**
|
* Displays a confirmation message dialog.
|
*
|
* @param msg
|
* the confirmation message.
|
* @param title
|
* the title of the dialog.
|
* @return <CODE>true</CODE> if the user confirms the message, or
|
* <CODE>false</CODE> if not.
|
*/
|
public boolean displayConfirmation(LocalizableMessage msg, LocalizableMessage title)
|
{
|
return Utilities.displayConfirmation(getFrame(), msg, title);
|
}
|
|
/**
|
* 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 getCurrentStepPanel().getFieldValue(fieldName);
|
}
|
|
/**
|
* 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)
|
{
|
getCurrentStepPanel().displayFieldInvalid(fieldName, invalid);
|
}
|
|
/**
|
* 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)
|
{
|
getButtonsPanel().addButtonActionListener(l);
|
getInstalledPanel().addButtonActionListener(l);
|
getCurrentStepPanel().addButtonActionListener(l);
|
|
buttonListeners.add(l);
|
}
|
|
/**
|
* This method is called to inform that a worker has started (the QuickSetup
|
* is doing some data validation). The worker is doing its tasks outside
|
* the event thread to avoid blocking of the painting and this class is
|
* notified of this fact. The method basically simply the Next and Previous
|
* buttons.
|
*
|
* This method can be called from the event thread or outside the event
|
* thread.
|
*
|
*/
|
public void workerStarted()
|
{
|
Runnable r = new Runnable()
|
{
|
public void run()
|
{
|
displayWorkingProgressImage(true);
|
setButtonEnabled(ButtonName.NEXT, false);
|
setButtonEnabled(ButtonName.PREVIOUS, false);
|
setButtonEnabled(ButtonName.FINISH, false);
|
}
|
};
|
runOnEventThread(r);
|
}
|
|
/**
|
* This method is called to inform that a worker has finished. The method just
|
* enables the Next and Previous buttons.
|
*
|
* This method can be called from the event thread or outside the event
|
* thread.
|
*
|
*/
|
public void workerFinished()
|
{
|
Runnable r = new Runnable()
|
{
|
public void run()
|
{
|
displayWorkingProgressImage(false);
|
setButtonEnabled(ButtonName.NEXT, true);
|
setButtonEnabled(ButtonName.PREVIOUS, true);
|
setButtonEnabled(ButtonName.FINISH, true);
|
}
|
};
|
runOnEventThread(r);
|
}
|
|
/**
|
* Notification telling that the installation/uninstallation is finished.
|
* @param successful a boolean telling whether the setup was successful or
|
* not.
|
*/
|
public void finished(boolean successful)
|
{
|
setButtonEnabled(ButtonName.CLOSE, true);
|
if (!successful)
|
{
|
// Do nothing... all the error messages
|
}
|
}
|
|
/**
|
* Returns the frame containing the dialog.
|
* @return the frame containing the dialog.
|
*/
|
public JFrame getFrame()
|
{
|
return frame;
|
}
|
|
/**
|
* Enables a button associated with the given Button Name.
|
* @param buttonName the button name of the button.
|
* @param enable boolean indicating to enable or to disable the button.
|
*/
|
public void setButtonEnabled(ButtonName buttonName, boolean enable)
|
{
|
getButton(buttonName).setEnabled(enable);
|
}
|
|
/**
|
* Returns the panel of the dialog.
|
* @return the panel of the dialog.
|
*/
|
private JPanel getFramePanel()
|
{
|
if (framePanel == null) {
|
framePanel = application.createFramePanel(this);
|
}
|
return framePanel;
|
}
|
|
/**
|
* Returns the steps panel.
|
* @return the steps panel.
|
*/
|
public StepsPanel getStepsPanel()
|
{
|
if (stepsPanel == null)
|
{
|
stepsPanel = new StepsPanel(application);
|
stepsPanel.setQuickSetup(quickSetup);
|
}
|
return stepsPanel;
|
}
|
|
/**
|
* Returns the current step panel.
|
* @return the current step panel.
|
*/
|
public CurrentStepPanel getCurrentStepPanel()
|
{
|
if (currentStepPanel == null)
|
{
|
currentStepPanel = new CurrentStepPanel(application, quickSetup);
|
}
|
return currentStepPanel;
|
}
|
|
|
/**
|
* Returns the buttons panel.
|
* @return the buttons panel.
|
*/
|
public ButtonsPanel getButtonsPanel()
|
{
|
if (buttonsPanel == null)
|
{
|
buttonsPanel = new ButtonsPanel(application);
|
buttonsPanel.setQuickSetup(quickSetup);
|
}
|
return buttonsPanel;
|
}
|
|
/**
|
* Returns the button corresponding to the buttonName.
|
* @param buttonName the ButtonName for which we want to get the button.
|
* @return the button corresponding to the buttonName.
|
*/
|
private JButton getButton(ButtonName buttonName)
|
{
|
JButton button;
|
if (isInstalled() && !forceToDisplay)
|
{
|
if (buttonName == ButtonName.QUIT)
|
{
|
button = getInstalledPanel().getQuitButton();
|
} else if (buttonName == ButtonName.CONTINUE_INSTALL)
|
{
|
button = getInstalledPanel().getContinueInstallButton();
|
} else
|
{
|
button = getButtonsPanel().getButton(buttonName);
|
}
|
} else
|
{
|
button = getButtonsPanel().getButton(buttonName);
|
}
|
return button;
|
}
|
|
/**
|
* Sets the focus in the button associated with the ButtonName.
|
* @param buttonName the ButtonName associated with the button.
|
*/
|
public void setFocusOnButton(ButtonName buttonName)
|
{
|
JButton button = getButton(buttonName);
|
if (button != null) {
|
button.requestFocusInWindow();
|
} else {
|
logger.debug(LocalizableMessage.raw("Focus requested for unknown button '" +
|
buttonName + "'"));
|
}
|
}
|
|
/**
|
* Sets the default button for the frame.
|
* @param buttonName the ButtonName associated with the button.
|
*/
|
public void setDefaultButton(ButtonName buttonName)
|
{
|
getFrame().getRootPane().setDefaultButton(getButton(buttonName));
|
}
|
|
/**
|
* Method used to execute a Runnable in the event thread. If we are in the
|
* event thread it will be called synchronously and if we are not it will
|
* be executed asynchronously.
|
*
|
* @param r the Runnable to be executed.
|
*/
|
private void runOnEventThread(Runnable r)
|
{
|
if (SwingUtilities.isEventDispatchThread())
|
{
|
r.run();
|
} else
|
{
|
SwingUtilities.invokeLater(r);
|
}
|
}
|
|
/**
|
* Returns <CODE>true</CODE> if the server is already installed and
|
* <CODE>false</CODE> otherwise.
|
* @return <CODE>true</CODE> if the server is already installed and
|
* <CODE>false</CODE> otherwise.
|
*/
|
private boolean isInstalled()
|
{
|
return installStatus.isInstalled();
|
}
|
|
/**
|
* Returns (and creates if it is not already created) the panel that
|
* informs the user that the server is already installed when the
|
* installation has been launched.
|
* @return the panel that is used
|
* to inform the user that the server is already installed when the
|
* installation has been launched.
|
*/
|
public QuickSetupErrorPanel getInstalledPanel()
|
{
|
if (installedPanel == null)
|
{
|
installedPanel = new QuickSetupErrorPanel(
|
application,
|
installStatus);
|
installedPanel.setQuickSetup(quickSetup);
|
}
|
return installedPanel;
|
}
|
|
/**
|
* Notifies the ButtonActionListener objects that an ButtonEvent has occurred
|
* in the button associated with buttonName.
|
* @param buttonName the ButtonName associated with the button.
|
*/
|
public void notifyButtonEvent(ButtonName buttonName)
|
{
|
ButtonEvent be = new ButtonEvent(this, buttonName);
|
for (ButtonActionListener li : buttonListeners)
|
{
|
li.buttonActionPerformed(be);
|
}
|
}
|
|
private void displayWorkingProgressImage(boolean display)
|
{
|
getCurrentStepPanel().setCheckingVisible(display);
|
}
|
}
|