/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ModalProgressMonitor.java
* Creation date: Jan 20, 2006.
* By: Joseph Wong
*/
package org.openquark.gems.client;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
/**
* This class implements a modal dialog for monitoring the progress of some operation. This class contrasts
* with {@link javax.swing.ProgressMonitor} in a number of ways:
*
* <ul>
* <li>This class implements a modal dialog which blocks the UI, unless it is either closed (when the operation
* finishes) or is dismissed. The standard Swing ProgressMonitor implements a non-modal dialog which pops up only
* when the operation takes longer than a certain threshold amount of time to finish. Having a modal dialog
* is handy if the length operation cannot occur in parallel with other user operations.
*
* <li>The dialog is not closed automatically when the progress reaches the maximum value.
* </ul>
*
* @author Joseph Wong
*/
class ModalProgressMonitor {
/**
* The JLabels for the messages above the progress bar.
*/
private final JLabel[] messageLabels;
/**
* The progress bar.
*/
private final JProgressBar progressBar;
/**
* The label for displaying the progress as a percentage value.
*/
private final JLabel percentageDone;
/**
* The option to be used in the JOptionPane for the cancel button.
*/
private final String cancelOption;
/**
* The JOptionPane which encapsulates the message labels and the progress bar.
*/
private final JOptionPane optionPane;
/**
* The actual dialog that hosts the option pane.
*/
private final JDialog dialog;
/**
* The flag which, when set to true, indicates that the operation is done, that the dialog should be closed, and
* that if showDialog() is called afterwards, that the dialog not be shown.
*/
private boolean isDone;
/**
* Constructs a progress monitor.
* @param parent the parent component for the dialog box.
* @param title the title of the dialog box, or null for an empty title.
* @param nMessages the number of messages that will be shown above the progress bar.
* @param min the lower bound of the possible range of progress values.
* @param max the upper bound of the possible range of progress values.
*/
public ModalProgressMonitor(Component parent, String title, int nMessages, int min, int max) {
messageLabels = new JLabel[nMessages];
for (int i = 0; i < nMessages; i++) {
messageLabels[i] = new JLabel("XXX"); // put a string in the labels so that the dialog packing is done properly
}
progressBar = new JProgressBar(min, max);
progressBar.setValue(min);
percentageDone = new JLabel();
percentageDone.setMinimumSize(new Dimension(50, 0));
percentageDone.setPreferredSize(new Dimension(50, 0));
percentageDone.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
JPanel progressPanel = new JPanel(new BorderLayout());
progressPanel.add(progressBar, BorderLayout.CENTER);
progressPanel.add(percentageDone, BorderLayout.EAST);
cancelOption = GemCutterMessages.getString("CancelButton");
Object[] paneMessages = new Object[nMessages + 1];
System.arraycopy(messageLabels, 0, paneMessages, 0, nMessages);
paneMessages[nMessages] = progressPanel;
optionPane = new JOptionPane(paneMessages,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.DEFAULT_OPTION,
null,
new Object[] {cancelOption},
null);
dialog = optionPane.createDialog(parent, title);
dialog.setModal(true);
// reset the message strings after the dialog is done packing
for (int i = 0; i < nMessages; i++) {
messageLabels[i].setText(" ");
}
isDone = false;
}
/**
* Sets the preferred width of the dialog.
* @param width the preferred width.
*/
public void setPreferredWidth(int width) {
Dimension dimension = new Dimension(width, optionPane.getHeight());
optionPane.setMinimumSize(dimension);
optionPane.setPreferredSize(dimension);
dialog.pack();
}
/**
* Specifies the minimum value - the lower bound of the possible range of progress values.
* @param min the minimum value.
*/
public void setMinimum(int min) {
progressBar.setMinimum(min);
}
/**
* Returns the minimum value - the lower bound of the possible range of progress values.
* @return the minimum value.
*/
public int getMinimum() {
return progressBar.getMinimum();
}
/**
* Specifies the maximum value - the upper bound of the possible range of progress values.
* @param max the maximum value.
*/
public void setMaximum(int max) {
progressBar.setMaximum(max);
}
/**
* Returns the maximum value - the upper bound of the possible range of progress values.
* @return the maximum value.
*/
public int getMaximum() {
return progressBar.getMaximum();
}
/**
* Sets the title of the progress monitor dialog.
* @param title the title string, or null for an empty title.
*/
public void setTitle(String title) {
dialog.setTitle(title);
}
/**
* Specifies the message to be displayed on a particular line above the progress bar.
* @param index the position of the message label.
* @param message the message to be displayed.
*/
public void setMessage(int index, String message) {
messageLabels[index].setText(message);
}
/**
* Updates the progress of the operation being monitored.
* @param progress the current progress value, between the minimum and maximum specified for this monitor.
*/
public void setProgress(int progress) {
progressBar.setValue(progress);
percentageDone.setText(GemCutterMessages.getString("ProgressPercentage", new Double(progressBar.getPercentComplete())));
}
/**
* Increments the progress of the operation by 1.
* @see #setProgress
*/
public void incrementProgress() {
setProgress(progressBar.getValue() + 1);
}
/**
* Returns the progress of the operation as registered with the monitor.
* @return the current progress value.
*/
public int getProgress() {
return progressBar.getValue();
}
/**
* Shows the progress monitor dialog in a modal fashion. If done() has already been called on this instance,
* then the dialog with not be shown.
*/
public synchronized void showDialog() {
if (!isDone) {
dialog.setVisible(true);
}
}
/**
* Signals the monitor that the operation is done, and that the dialog, if displayed, should be closed.
*/
public synchronized void done() {
isDone = true;
dialog.dispose();
}
/**
* @return true if the user has canceled the operation via the cancel button in the dialog.
*/
public boolean isCanceled() {
Object userChoice = optionPane.getValue();
return userChoice == cancelOption;
}
}