package com.vitco.util.components.progressbar; import com.jidesoft.swing.JideLabel; import com.vitco.util.components.dialog.components.DialogButton; import com.vitco.util.misc.SaveResourceLoader; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; /** * A progress bar that encapsulates a ProgressWorker and displays the status of this action. * * The progress bar blocks all user interaction but prevents the program from freezing. */ public class ProgressDialog extends JDialog { // reference to this instance private final ProgressDialog thisInstance = this; // reference: the progress bar itself private final JProgressBar progressBar; // reference: the cancel button (if visible) private final DialogButton cancelButton; // reference: the JLabel that displays the current activity private final JideLabel activityLabel; // reference to the currently active worker private ProgressWorker worker = null; // owner frame private final Frame owner; // true if currently executing something private boolean running = false; // true if the progress bar should be automatically increased // (only suitable for very short tasks!) private boolean autoIncrease = false; // the current value (as float) of the progress bar private float currentValue = 0; // constructor public ProgressDialog(Frame owner) { // make sure this JDialog is blocking (set modal flag) super(owner, true); // hide title and close button of frame this.setUndecorated(true); // store owner reference this.owner = owner; // set up the wrapper panel (for entire content) JPanel contentPane = new JPanel(); contentPane.setLayout(new GridBagLayout()); contentPane.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createRaisedBevelBorder(), BorderFactory.createEmptyBorder(5, 10, 10, 10) )); // add wrapper for loading button and text right of it JPanel iconTextWrapper = new JPanel(); iconTextWrapper.setLayout(new BorderLayout()); // add loading button Icon icon = new SaveResourceLoader("resource/img/icons/loading.gif").asIconImage(); JideLabel label = new JideLabel(icon); label.setBorder(BorderFactory.createEmptyBorder(0,0,0,6)); iconTextWrapper.add(label, BorderLayout.WEST); // create top over label label = new JideLabel("Processing Task"); label.setFont(label.getFont().deriveFont(Font.BOLD)); iconTextWrapper.add(label, BorderLayout.CENTER); // add wrapper to layout GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(4, 4, 4, 4); gbc.gridx = 0; gbc.gridy = 0; gbc.fill = GridBagConstraints.HORIZONTAL; contentPane.add(iconTextWrapper, gbc); // --------- // create current task label activityLabel = new JideLabel("Initializing Task..."); gbc.gridy++; contentPane.add(activityLabel, gbc); // create progress bar progressBar = new JProgressBar(0, 100); progressBar.setPreferredSize(new Dimension(300, 20)); gbc.gridy++; contentPane.add(progressBar, gbc); // create cancel button cancelButton = new DialogButton("Cancel"); cancelButton.setVisible(false); // hide cancel button by default gbc.fill = GridBagConstraints.NONE; gbc.gridy++; contentPane.add(cancelButton, gbc); // set cancel action cancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { thisInstance.setVisible(false); worker.cancel(true); } }); // add the panel to this JDialog this.setLayout(new BorderLayout()); this.add(contentPane); } // set the visible state of the cancel button (note that cancel needs // to be specifically handles by the processing task!) public final void enableCancel(boolean showCancelButton) { cancelButton.setVisible(showCancelButton); } // start the processing of executing a task public final void start(ProgressWorker worker) { // make sure the dialog is not already running if (!running && worker != null && !isVisible()) { running = true; this.worker = worker; // used to automatically increase the progress value new ProgressWorker() { @Override protected Object doInBackground() throws Exception { // keep alive while the worker is running while (running) { if (autoIncrease) { final float value = thisInstance.getProgress(); thisInstance.setProgress(value + (100 - value) / 4); } Thread.sleep(50); } return null; } }.execute(); // start the worker worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (name.equals("state")) { SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue(); switch (state) { case DONE: // reset the progress to zero (for the next start) setProgress(0); // hide this frame thisInstance.setVisible(false); // remove the reference to the worker thisInstance.worker = null; // not running anymore running = false; break; } } } }); worker.execute(); // show the dialog thisInstance.pack(); thisInstance.setLocationRelativeTo(owner); thisInstance.setVisible(true); } } // set the activity that is currently performed and reset the progress to zero // the auto increase flag indicates whether the bar should progress automatically // or if the worker is explicitly setting the value public final void setActivity(String activity, boolean autoIncrease) { activityLabel.setText(activity); setProgress(0); this.autoIncrease = autoIncrease; } // set the progress (this should only be done if the last // "setActivity" call didn't set the "autoIncrease" flag public final void setProgress(float percent) { synchronized (ProgressDialog.class) { currentValue = percent; progressBar.setValue((int) percent); } } // get the current progress value private float getProgress() { synchronized (ProgressDialog.class) { return currentValue; } } // check if this dialog is canceled public final boolean isCancelled() { return worker == null || worker.isCancelled(); } }