/*
* 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 2008-2010 Sun Microsystems, Inc.
*/
package org.opends.guitools.controlpanel.ui;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.QuickSetupMessages.INFO_CLOSE_BUTTON_LABEL;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.text.html.HTMLDocument;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.event.PrintStreamListener;
import org.opends.guitools.controlpanel.ui.components.BasicExpander;
import org.opends.guitools.controlpanel.util.ApplicationPrintStream;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
/**
* The dialog that is used to display progress in a task.
*
*/
public class ProgressDialog extends GenericDialog
{
private static final long serialVersionUID = -6462866257463062629L;
private ProgressPanel progressPanel;
/**
* Constructor of the dialog.
* @param parentFrame the parent frame.
* @param relativeTo the component to use as reference to set the position
* of this dialog.
* @param title the title of the dialog.
* @param info the control panel information.
*/
public ProgressDialog(JFrame parentFrame, Component relativeTo,
Message title, ControlPanelInfo info)
{
super(parentFrame, getPanel(info));
Utilities.centerGoldenMean(this, relativeTo);
setTitle(title.toString());
progressPanel = (ProgressPanel)panel;
getRootPane().setDefaultButton(progressPanel.closeButton);
}
/**
* Creates the panel that will be contained in the dialog.
* @param info the control panel information.
* @return the panel that will be contained in the dialog.
*/
private static StatusGenericPanel getPanel(ControlPanelInfo info)
{
ProgressPanel panel = new ProgressPanel();
panel.setInfo(info);
return panel;
}
/**
* Adds two print stream listeners.
* @param outPrintStream the output stream listener.
* @param errorPrintStream the error stream listener.
*/
public void addPrintStreamListeners(ApplicationPrintStream outPrintStream,
ApplicationPrintStream errorPrintStream)
{
errorPrintStream.addListener(new PrintStreamListener()
{
public void newLine(final String msg)
{
SwingUtilities.invokeLater(new Runnable()
{
/**
* {@inheritDoc}
*/
public void run()
{
progressPanel.appendErrorLine(msg);
}
});
}
});
outPrintStream.addListener(new PrintStreamListener()
{
public void newLine(final String msg)
{
/**
* {@inheritDoc}
*/
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
progressPanel.appendOutputLine(msg);
}
});
}
});
}
/**
* Returns the progress bar of the dialog.
* @return the progress bar of the dialog.
*/
public JProgressBar getProgressBar()
{
return progressPanel.getProgressBar();
}
/**
* Appends some text in HTML format to the 'Details' section of the dialog.
* @param text the text in HTML format to be appended.
*/
public void appendProgressHtml(String text)
{
progressPanel.appendHtml(text);
}
/**
* Resets the contents of the 'Details' section of the dialog.
*
*/
public void resetProgressLogs()
{
progressPanel.resetLogs();
}
/**
* Sets the text to be displayed in the summary area of the progress
* dialog.
* @param text the text to be displayed.
*/
public void setSummary(Message text)
{
progressPanel.setSummary(text);
}
/**
* {@inheritDoc}
*/
public void setEnabledClose(boolean enable)
{
progressPanel.closeButton.setEnabled(enable);
}
/**
* Note: this will make the dialog to be closed asynchronously. So that
* sequential calls to setTaskIsOver(true) and setTaskIsOver(false) on the
* event thread are guaranteed not to close the dialog.
* @param taskIsOver whether the task is finished or not.
*/
public void setTaskIsOver(boolean taskIsOver)
{
progressPanel.taskIsOver = taskIsOver;
progressPanel.closeWhenOverClicked();
}
/**
* The panel contained in the progress dialog.
*
*/
static class ProgressPanel extends StatusGenericPanel
{
private static final long serialVersionUID = -364496083928260306L;
private BasicExpander details;
private JEditorPane logs;
private JScrollPane scroll;
private JCheckBox closeWhenOver;
private final String LASTID = "lastid";
private final String INIT_TEXT = " ";
private JProgressBar progressBar;
private Component extraStrut;
private JButton closeButton;
private static final String FAKE_PROGRESS_TEXT =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"+
"
"+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
private int heightDiff;
private int lastCollapsedHeight = -1;
private int lastExpandedHeight = -1;
private static boolean lastShowDetails = false;
private static boolean lastCloseWhenOver = false;
private boolean taskIsOver;
/**
* Default constructor.
*
*/
public ProgressPanel()
{
super();
createLayout();
}
/**
* {@inheritDoc}
*/
public Message getTitle()
{
return null;
}
/**
* {@inheritDoc}
*/
public boolean requiresScroll()
{
return false;
}
/**
* {@inheritDoc}
*/
public boolean requiresBorder()
{
return false;
}
/**
* {@inheritDoc}
*/
public boolean isDisposeOnClose()
{
return true;
}
/**
* Appends a line to the logs (Details are) section of the panel. The text
* will have a new-line char at the end (is similar to println()).
* @param msg the HTML formatted text to be appended.
*/
public void appendErrorLine(String msg)
{
msg = filterForBugID4988885(msg+"
");
msg = Utilities.applyFont(msg, ColorAndFontConstants.progressFont);
appendHtml(msg);
}
/**
* Sets the text to be displayed in the summary area of the progress
* dialog.
* @param msg the text to be displayed.
*/
public void setSummary(Message msg)
{
errorPane.setText(msg.toString());
if (!details.isSelected() && isVisible())
{
Message wrappedText = Utilities.wrapHTML(msg, 70);
JEditorPane pane = new JEditorPane();
pane.setContentType("text/html");
pane.setText(wrappedText.toString());
ProgressDialog dlg = (ProgressDialog)Utilities.getParentDialog(this);
int width = Math.max(pane.getPreferredSize().width + 40,
dlg.getWidth());
int height = Math.max(pane.getPreferredSize().height + 40 +
extraStrut.getHeight() + details.getPreferredSize().height,
dlg.getHeight());
// We might want to resize things.
if (width > dlg.getWidth() || height > dlg.getHeight())
{
Dimension newDim = new Dimension(width, height);
dlg.setSize(newDim);
}
}
}
/**
* Appends a line to the logs (Details are) section of the panel. The text
* will be preceded by a new line (is similar to println()).
* @param msg the HTML formatted text to be appended.
*/
public void appendOutputLine(String msg)
{
appendErrorLine(msg);
}
/**
* Appends text to the logs (Details are) section of the panel. The text
* will be appended as it is (is similar to print()).
* @param msg the HTML formatted text to be appended.
*/
public void appendHtml(String msg)
{
HTMLDocument doc = (HTMLDocument)logs.getDocument();
try
{
msg = filterForBugID4988885(msg);
doc.insertBeforeStart(doc.getElement(LASTID), msg);
}
catch (Throwable t)
{
// Bug
t.printStackTrace();
}
}
/**
* Resets the contents of the logs (Details) section.
*
*/
public void resetLogs()
{
logs.setText(INIT_TEXT);
}
/**
* Creates the layout of the panel (but the contents are not populated
* here).
*
*/
private void createLayout()
{
GridBagConstraints gbc = new GridBagConstraints();
addErrorPane(gbc);
errorPane.setVisible(true);
errorPane.setText(Utilities.applyFont(
INFO_CTRL_PANEL_PLEASE_WAIT_SUMMARY.get().toString(),
ColorAndFontConstants.defaultFont));
gbc.anchor = GridBagConstraints.WEST;
gbc.gridwidth = 1;
gbc.gridx = 0;
gbc.gridy = 1;
progressBar = new JProgressBar();
progressBar.setMaximum(100);
gbc.weightx = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(10, 20, 0, 30);
add(progressBar, gbc);
gbc.insets.top = 10;
gbc.insets.bottom = 5;
details =
new BasicExpander(INFO_CTRL_PANEL_PROGRESS_DIALOG_DETAILS_LABEL.get());
gbc.gridy ++;
add(details, gbc);
logs = Utilities.makeHtmlPane(FAKE_PROGRESS_TEXT,
ColorAndFontConstants.progressFont);
gbc.gridy ++;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets.top = 5;
gbc.insets.right = 20;
gbc.insets.bottom = 5;
scroll = Utilities.createScrollPane(logs);
scroll.setOpaque(false);
scroll.getViewport().setOpaque(false);
add(scroll, gbc);
Dimension scrollDim = scroll.getPreferredSize();
gbc.weighty = 1.0;
extraStrut = Box.createRigidArea(new Dimension(scrollDim.width, 50));
add(extraStrut, gbc);
gbc.gridy ++;
gbc.weighty = 0.0;
add(Box.createHorizontalStrut(scrollDim.width), gbc);
heightDiff = scrollDim.height - extraStrut.getHeight();
logs.setText(INIT_TEXT);
scroll.setPreferredSize(scrollDim);
updateVisibility(lastShowDetails);
details.addActionListener(new ActionListener()
{
/**
* {@inheritDoc}
*/
public void actionPerformed(ActionEvent ev)
{
lastShowDetails = details.isSelected();
updateVisibility(lastShowDetails);
}
});
// The button panel
gbc.gridy ++;
gbc.weighty = 0.0;
gbc.insets = new Insets(0, 0, 0, 0);
add(createButtonsPanel(), gbc);
}
private JPanel createButtonsPanel()
{
JPanel buttonsPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = 1;
gbc.gridy = 0;
closeWhenOver = Utilities.createCheckBox(
INFO_CTRL_PANEL_CLOSE_WINDOW_WHEN_OPERATION_COMPLETES_LABEL.get());
closeWhenOver.setOpaque(false);
closeWhenOver.addActionListener(new ActionListener()
{
/**
* {@inheritDoc}
*/
public void actionPerformed(ActionEvent ev)
{
closeWhenOverClicked();
}
});
closeWhenOver.setSelected(lastCloseWhenOver);
gbc.insets = new Insets(10, 10, 10, 10);
buttonsPanel.add(closeWhenOver, gbc);
gbc.weightx = 1.0;
gbc.gridx ++;
buttonsPanel.add(Box.createHorizontalStrut(150));
buttonsPanel.add(Box.createHorizontalGlue(), gbc);
buttonsPanel.setOpaque(true);
buttonsPanel.setBackground(ColorAndFontConstants.greyBackground);
gbc.gridx ++;
gbc.weightx = 0.0;
buttonsPanel.add(Box.createHorizontalStrut(100));
gbc.gridx ++;
closeButton = Utilities.createButton(INFO_CLOSE_BUTTON_LABEL.get());
closeButton.setOpaque(false);
gbc.gridx ++;
gbc.insets.left = 5;
gbc.insets.right = 10;
buttonsPanel.add(closeButton, gbc);
closeButton.addActionListener(new ActionListener()
{
/**
* {@inheritDoc}
*/
public void actionPerformed(ActionEvent ev)
{
closeClicked();
}
});
buttonsPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
ColorAndFontConstants.defaultBorderColor));
return buttonsPanel;
}
private void updateVisibility(boolean showDetails)
{
scroll.setVisible(showDetails);
extraStrut.setVisible(!showDetails);
details.setSelected(showDetails);
if (showDetails)
{
final Window dialog = Utilities.getParentDialog(this);
if (dialog != null)
{
lastCollapsedHeight = dialog.getSize().height;
if (lastExpandedHeight == -1)
{
dialog.setSize(new Dimension(dialog.getSize().width,
dialog.getSize().height + heightDiff));
}
else
{
dialog.setSize(new Dimension(dialog.getSize().width,
lastExpandedHeight));
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
invalidate();
dialog.invalidate();
dialog.repaint();
}
});
}
}
else
{
final Window dialog = Utilities.getParentDialog(this);
if (dialog != null)
{
lastExpandedHeight = dialog.getSize().height;
if (lastCollapsedHeight == -1)
{
packParentDialog();
}
else
{
dialog.setSize(new Dimension(dialog.getSize().width,
lastCollapsedHeight));
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
invalidate();
dialog.invalidate();
dialog.repaint();
}
});
}
}
}
}
/**
* {@inheritDoc}
*/
public GenericDialog.ButtonType getButtonType()
{
return GenericDialog.ButtonType.NO_BUTTON;
}
/**
* {@inheritDoc}
*/
public void configurationChanged(ConfigurationChangeEvent ev)
{
}
/**
* {@inheritDoc}
*/
public Component getPreferredFocusComponent()
{
return details;
}
/**
* {@inheritDoc}
*/
public void okClicked()
{
Utilities.getParentDialog(this).setVisible(false);
}
/**
* Returns the progress bar of the dialog.
* @return the progress bar of the dialog.
*/
public JProgressBar getProgressBar()
{
return progressBar;
}
/**
* Checks if the 'Close when over' check box is selected and if it is the
* case, closes the dialog after waiting for 2 seconds (so that the user
* can see the result, or cancel the automatic closing of the dialog).
*
*/
private void closeWhenOverClicked()
{
lastCloseWhenOver = closeWhenOver.isSelected();
if (lastCloseWhenOver && taskIsOver)
{
Thread t = new Thread(new Runnable()
{
/**
* {@inheritDoc}
*/
public void run()
{
try
{
Thread.sleep(2000);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (closeWhenOver.isSelected() && taskIsOver)
{
closeClicked();
}
}
});
}
catch (Throwable t)
{
}
}
});
t.start();
}
}
}
/**
* This is necessary because of bug 4988885.
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4988885
* @param msg the message.
* @return the message filtered.
*/
private static String filterForBugID4988885(String msg)
{
return msg.replaceAll("
", "
");
}
}