/* * This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH * written by Rasto Levrinc. * * Copyright (C) 2009, LINBIT HA-Solutions GmbH. * Copyright (C) 2011-2012, Rastislav Levrinc. * * DRBD Management Console is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your option) * any later version. * * DRBD Management Console is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with drbd; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ package lcmc.common.ui; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.inject.Inject; import javax.inject.Named; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.border.TitledBorder; import lcmc.cluster.ui.widget.WidgetFactory; import lcmc.common.domain.CancelCallback; import lcmc.common.ui.utils.SwingUtils; import lcmc.logger.Logger; import lcmc.logger.LoggerFactory; import lcmc.common.ui.utils.MyButton; import lcmc.common.domain.util.Tools; /** * This class creates titled pane with progress bar and functions that update * the progress bar. */ @Named public final class ProgressBar implements ActionListener { private static final Logger LOG = LoggerFactory.getLogger(ProgressBar.class); private static final int DEFAULT_TIMEOUT = 50 * 1000; /** This is threshold to catch threads that are out of the line. * TODO: not for production. */ private static final int DEBUG_THRESHOLD = 120000; /** Max value in the progress bar. */ private static final int MAX_PB_VALUE = 100; private static final ImageIcon CANCEL_ICON = Tools.createImageIcon(Tools.getDefault("ProgressBar.CancelIcon")); private JProgressBar progressBar; /** Progress bar panel. */ private JPanel pbPanel; @Inject private SwingUtils swingUtils; private volatile boolean stopNow = false; /** Whether to hold the progress bar. */ private boolean holdIt = false; /** Progress of the progress bar. */ private int progress = 0; /** Timethat passed in the progress bar. */ private int time = 0; /** Timeout for the progress bar in milliseconds. */ private int timeout; /** Thread with progress bar. */ private Thread progressThread = null; private MyButton cancelButton = null; /** Cancel callback function that will be called, when cancel was pressed. */ private CancelCallback cancelCallback; @Inject private WidgetFactory widgetFactory; void init(final String title, final CancelCallback cancelCallback, final int width, final int height) { this.cancelCallback = cancelCallback; swingUtils.isSwingThread(); progressBar = new JProgressBar(0, MAX_PB_VALUE); progressBar.setPreferredSize(new Dimension(width, height)); progressBar.setBackground(Tools.getDefaultColor("ProgressBar.Background")); progressBar.setForeground(Tools.getDefaultColor("ProgressBar.Foreground")); pbPanel = new JPanel(); if (title != null) { final TitledBorder titledBorder = BorderFactory.createTitledBorder(title); pbPanel.setBorder(titledBorder); } pbPanel.add(progressBar); if (cancelCallback != null) { cancelButton = widgetFactory.createButton(Tools.getString("ProgressBar.Cancel"), CANCEL_ICON); cancelButton.setEnabled(false); cancelButton.addActionListener(this); pbPanel.add(cancelButton); } final Dimension d = new Dimension(Integer.MAX_VALUE, (int) pbPanel.getPreferredSize().getHeight()); pbPanel.setMaximumSize(d); pbPanel.setPreferredSize(d); progressBar.setVisible(false); if (cancelButton != null) { cancelButton.setVisible(false); } } void init(final CancelCallback cancelCallbackA, final int width, final int height) { this.init(null, cancelCallbackA, width, height); } public void init(final String title, final CancelCallback cancelCallbackA) { this.init(title, cancelCallbackA, Tools.getDefaultInt("ProgressBar.DefaultWidth"), Tools.getDefaultInt("ProgressBar.DefaultHeight")); } public void init(final CancelCallback cancelCallbackA) { this.init(null, cancelCallbackA, Tools.getDefaultInt("ProgressBar.DefaultWidth"), Tools.getDefaultInt("ProgressBar.DefaultHeight")); } /** Enables or disables cancel button if it exists. */ public void setCancelEnabled(final boolean enable) { if (cancelButton != null) { cancelButton.setEnabled(enable); } } /** Starts progress bar thread. */ public void start(final int t) { timeout = t; stopNow = false; if (timeout == 0) { timeout = DEFAULT_TIMEOUT; } if (progressThread == null) { final Runnable runnable = new Runnable() { @Override public void run() { LOG.debug2("start: running postgresbar timeout: " + timeout); final int sleepTime = Tools.getDefaultInt("ProgressBar.Sleep"); final int progressBarDelay = Tools.getDefaultInt("ProgressBar.Delay"); int threshold = DEBUG_THRESHOLD; boolean isVisible = false; while (!stopNow) { try { Thread.sleep(sleepTime); } catch (final InterruptedException ex) { Thread.currentThread().interrupt(); } /* show progress bar after delay */ if (time > progressBarDelay && !isVisible) { isVisible = true; swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setVisible(true); if (cancelButton != null) { cancelButton.setVisible(true); } } }); } if (!holdIt) { swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setValue(progress * MAX_PB_VALUE / timeout); } }); progress += sleepTime; } time += sleepTime; if (time > threshold) { LOG.appWarning("start: thread with timeout: " + timeout + " is running way too long"); threshold += DEBUG_THRESHOLD; } if (progress >= timeout) { /* premature end */ swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setIndeterminate(true); } }); } } swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setIndeterminate(false); progressBar.setValue(MAX_PB_VALUE); } }); progressThread = null; } }; progressThread = new Thread(runnable); progressThread.start(); } else { progress = 0; time = 0; } } /** Returns progress bar panel. */ public JPanel getProgressBarPane() { return pbPanel; } /** Stops progress bar and sets it to the maximum position. */ public void done() { if (cancelButton != null) { cancelButton.setEnabled(false); } stopNow = true; progress = timeout; swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setIndeterminate(false); progressBar.setValue(MAX_PB_VALUE); } }); } /** Stops progress bar and sets it to 0. */ public void doneError() { if (cancelButton != null) { cancelButton.setEnabled(false); } stopNow = true; progress = 0; swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setIndeterminate(false); progressBar.setValue(0); } }); } /** * Holds progress bar until cont() is called and sets it in indeterminate * state. */ public void hold() { swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setVisible(true); if (cancelButton != null) { cancelButton.setVisible(true); } progressBar.setIndeterminate(true); } }); holdIt = true; } /** * Starts progress bar again from the position it was before calling * hold(). */ public void cont() { swingUtils.invokeLater(new Runnable() { @Override public void run() { progressBar.setIndeterminate(false); } }); holdIt = false; } /** cancels ssh connection. */ @Override public void actionPerformed(final ActionEvent e) { final String command = e.getActionCommand(); if (command.equals(Tools.getString("ProgressBar.Cancel"))) { LOG.debug1("actionPerformed: cancel button pressed"); cancelCallback.cancel(); } } }