com.actelion.research.gui.JProgressDialog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright (c) 1997 - 2016
* Actelion Pharmaceuticals Ltd.
* Gewerbestrasse 16
* CH-4123 Allschwil, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the the copyright holder 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.
*
* @author Thomas Sander
*/
package com.actelion.research.gui;
import com.actelion.research.calc.ProgressController;
import com.actelion.research.gui.hidpi.HiDPIHelper;
import info.clearthought.layout.TableLayout;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JProgressDialog extends JDialog implements ActionListener,ProgressController,Runnable {
private static final long serialVersionUID = 0x20070301;
private static final int sActionDispose = 2;
private static final int sActionStart = 4;
private static final int sActionUpdate = 8;
private static final int sActionMessage = 16;
private static final int sActionStop = 32;
private JProgressBar mProgressBar;
private JLabel mProgressLabel,mLabelRemainingTime;
private Frame mNewFrontFrame;
private String mBusyText;
private volatile String mProgressMessage;
private volatile boolean mProcessCancelled;
private volatile int mProgressMin,mProgressMax,mProgressValue,mAction;
private volatile long mProgressStart,mLastUpdate;
private volatile float mProgressFactor;
/**
* Creates a JProgressDialog and schedule it with invokeLater()
* to be set visible without blocking the calling thread.
* @param owner
*/
public JProgressDialog(Frame owner) {
this(owner, true);
}
/**
* Creates a JProgressDialog. If invokeSetVisible is true,
* then the dialog is scheduled to be set visible with invokeLater()
* without blocking the current thread. Otherwise, the caller needs
* to call setVisible() manually.
* @param owner
* @param invokeSetVisible
*/
public JProgressDialog(Frame owner, boolean invokeSetVisible) {
// initialized and shows the modal dialog without blocking the thread
super(owner, true);
initialize();
setLocationRelativeTo(owner);
if (invokeSetVisible)
SwingUtilities.invokeLater(() -> setVisible(true) );
}
public void startProgress(String text, int min, int max) {
// may be called safely from any thread
mProgressStart = System.currentTimeMillis();
mBusyText = text;
mProgressMin = min;
mProgressValue = min;
mProgressMax = max;
mProgressFactor = (max - min <= 10000) ? 1.0f : 10000.0f / (max - min);
mAction |= sActionStart;
update();
}
/**
* Update progress status in an absolute or relative way.
* @param value if negative, its abs value is added to current progress.
*/
public void updateProgress(int value) {
// may be called safely from any thread
int newValue = (value >= 0) ? value : mProgressValue-value;
if (mProgressValue < newValue) {
mProgressValue = newValue;
mAction |= sActionUpdate;
update();
}
}
/**
* Update progress status in an absolute or relative way.
* This method also updates the message of the progress dialog
* @param value if negative, its abs value is added to current progress.
* @param message
*/
public void updateProgress(int value, String message) {
// may be called safely from any thread
int newValue = (value >= 0) ? value : mProgressValue-value;
if (mProgressValue < newValue) {
mProgressValue = newValue;
mProgressMessage = message;
mAction |= sActionUpdate | sActionMessage;
update();
}
}
/**
* Sets progress back to zero, hides the progress bar, but keeps the dialog open.
* May be called safely from any thread
*/
public void stopProgress() {
mAction |= sActionStop;
update();
}
/**
* Closes and disposes the dialog.
* If you need to move a newly created window to the front, then use close(Frame newFrontFrame).
* May be called safely from any thread
*/
public void close() {
close(null);
}
/**
* Disposes of the progress dialog and optionally moves the specified
* frame to the front. This may be called safely from any thread.
* @param newFrontFrame null or frame to be moved to the front
*/
public void close(Frame newFrontFrame) {
mAction |= sActionDispose;
mNewFrontFrame = newFrontFrame;
update();
}
public void showErrorMessage(final String message) {
if (SwingUtilities.isEventDispatchThread()) {
showMessage(message);
}
else {
try {
SwingUtilities.invokeAndWait(() -> showMessage(message) );
}
catch (Exception e) {}
}
}
private void showMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
public boolean threadMustDie() {
return mProcessCancelled;
}
public void actionPerformed(ActionEvent e) {
mProcessCancelled = true;
mAction |= sActionStop;
update();
}
private void initialize() {
double[][] size = { {8, HiDPIHelper.scale(200), 8, TableLayout.PREFERRED, 8},
{8, TableLayout.PREFERRED, 8, TableLayout.PREFERRED, 16, TableLayout.PREFERRED, 8} };
getContentPane().setLayout(new TableLayout(size));
mProgressLabel = new JLabel(" ");
getContentPane().add(mProgressLabel, "1,1,3,1");
mProgressBar = new JProgressBar();
mProgressBar.setVisible(false);
getContentPane().add(mProgressBar, "1,3,3,3");
mLabelRemainingTime = new JLabel();
getContentPane().add(mLabelRemainingTime, "1,5");
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this);
getContentPane().add(cancelButton, "3,5");
pack();
}
private void update() {
long millis = System.currentTimeMillis();
if ((mAction & ~sActionUpdate) != 0 || millis - mLastUpdate > 100) {
if (SwingUtilities.isEventDispatchThread()) {
mLastUpdate = millis;
run();
}
else {
// try {
mLastUpdate = millis;
SwingUtilities.invokeLater(this);
// }
// catch (Exception e) {}
}
}
}
public void run() {
if ((mAction & sActionDispose) != 0) {
mAction &= ~sActionDispose;
setVisible(false);
dispose();
if (mNewFrontFrame != null)
mNewFrontFrame.toFront();
return;
}
if ((mAction & sActionStart) != 0) {
mAction &= ~sActionStart;
if (mProgressMin == mProgressMax) {
mProgressBar.setIndeterminate(true);
}
else {
mProgressBar.setIndeterminate(false);
mProgressBar.setMinimum(Math.round(mProgressFactor * mProgressMin));
mProgressBar.setMaximum(Math.round(mProgressFactor * mProgressMax));
mProgressBar.setValue(Math.round(mProgressFactor * mProgressMin));
}
mProgressBar.setVisible(true);
mProgressLabel.setText(mBusyText);
}
if ((mAction & sActionUpdate) != 0) {
mAction &= ~sActionUpdate;
mProgressBar.setValue(Math.round(mProgressFactor * mProgressValue));
if (mProgressValue > mProgressMin) {
long milliesUsed = System.currentTimeMillis() - mProgressStart;
long milliesToGo = milliesUsed * (mProgressMax - mProgressValue) / (mProgressValue - mProgressMin);
long millis = (mProgressMax == mProgressMin) ? milliesUsed : milliesToGo;
String timeToShow = (millis >= 7200000) ? ""+(millis/3600000)+" hours"
: (millis >= 120000) ? ""+(millis/60000)+" minutes"
: ""+(millis/1000)+" seconds";
String message = (mProgressMax == mProgressMin) ? " waiting" : " remaining";
mLabelRemainingTime.setText(timeToShow+message);
}
if ((mAction & sActionMessage) != 0) {
mAction &= ~sActionMessage;
mProgressLabel.setText(mProgressMessage);
}
}
if ((mAction & sActionStop) != 0) {
mAction &= ~sActionStop;
mProgressLabel.setText(mProcessCancelled ? "Cancelled; cleaning up..." : "");
if (mProcessCancelled)
mProgressBar.setIndeterminate(true);
else {
mProgressBar.setValue(mProgressBar.getMinimum());
mProgressBar.setVisible(false);
}
}
}
}