001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.GridBagConstraints; 008import java.awt.GridBagLayout; 009import java.awt.event.ActionListener; 010import java.awt.event.ComponentAdapter; 011import java.awt.event.ComponentEvent; 012 013import javax.swing.BorderFactory; 014import javax.swing.JButton; 015import javax.swing.JDialog; 016import javax.swing.JLabel; 017import javax.swing.JPanel; 018import javax.swing.JProgressBar; 019import javax.swing.JScrollPane; 020import javax.swing.UIManager; 021 022import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor.ProgressMonitorDialog; 023import org.openstreetmap.josm.gui.util.GuiHelper; 024import org.openstreetmap.josm.gui.widgets.JosmTextArea; 025import org.openstreetmap.josm.spi.preferences.Config; 026import org.openstreetmap.josm.tools.GBC; 027import org.openstreetmap.josm.tools.ImageProvider; 028 029/** 030 * This is a dialog that displays the progress of an action to the user. 031 */ 032public class PleaseWaitDialog extends JDialog implements ProgressMonitorDialog { 033 034 private final JProgressBar progressBar = new JProgressBar(); 035 036 private final JLabel currentAction = new JLabel(""); 037 private final JLabel customText = new JLabel(""); 038 039 private JButton btnCancel; 040 private JButton btnInBackground; 041 /** the text area and the scroll pane for the log */ 042 private final JosmTextArea taLog = new JosmTextArea(5, 50); 043 private final JScrollPane spLog = new JScrollPane(taLog); 044 045 046 /** 047 * Constructs a new {@code PleaseWaitDialog}. 048 * @param parent the {@code Component} from which the dialog is displayed. Can be {@code null}. 049 */ 050 public PleaseWaitDialog(Component parent) { 051 super(GuiHelper.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL); 052 initDialog(); 053 } 054 055 private void initDialog() { 056 setLayout(new GridBagLayout()); 057 JPanel pane = new JPanel(new GridBagLayout()); 058 pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 059 pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL)); 060 pane.add(customText, GBC.eol().fill(GBC.HORIZONTAL)); 061 pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL)); 062 JPanel buttons = new JPanel(new GridBagLayout()); 063 btnCancel = new JButton(tr("Cancel")); 064 btnCancel.setIcon(ImageProvider.get("cancel")); 065 btnCancel.setToolTipText(tr("Click to cancel the current operation")); 066 buttons.add(btnCancel); 067 btnInBackground = new JButton(tr("In background")); 068 btnInBackground.setToolTipText(tr("Click to run job in background")); 069 buttons.add(btnInBackground, GBC.std().fill(GBC.VERTICAL).insets(5, 0, 0, 0)); 070 pane.add(buttons, GBC.eol().anchor(GBC.CENTER)); 071 GridBagConstraints gc = GBC.eol().fill(GBC.BOTH); 072 gc.weighty = 1.0; 073 gc.weightx = 1.0; 074 pane.add(spLog, gc); 075 spLog.setVisible(false); 076 setContentPane(pane); 077 setCustomText(""); 078 setLocationRelativeTo(getParent()); 079 addComponentListener(new ComponentAdapter() { 080 @Override 081 public void componentResized(ComponentEvent ev) { 082 int w = getWidth(); 083 if (w > 200) { 084 Config.getPref().putInt("progressdialog.size", w); 085 } 086 } 087 }); 088 } 089 090 @Override 091 public void setIndeterminate(boolean newValue) { 092 UIManager.put("ProgressBar.cycleTime", UIManager.getInt("ProgressBar.repaintInterval") * 100); 093 progressBar.setIndeterminate(newValue); 094 } 095 096 protected void adjustLayout() { 097 invalidate(); 098 setDropTarget(null); // Workaround to JDK bug 7027598/7100524/7169912 (#8613) 099 pack(); 100 setSize(Config.getPref().getInt("progressdialog.size", 600), getSize().height); 101 } 102 103 /** 104 * Sets a custom text line below currentAction. Can be used to display additional information. 105 * @param text custom text 106 */ 107 @Override 108 public void setCustomText(String text) { 109 if (text == null || text.trim().isEmpty()) { 110 customText.setVisible(false); 111 adjustLayout(); 112 return; 113 } 114 customText.setText(text); 115 if (!customText.isVisible()) { 116 customText.setVisible(true); 117 adjustLayout(); 118 } 119 } 120 121 @Override 122 public void setCurrentAction(String text) { 123 currentAction.setText(text); 124 } 125 126 /** 127 * Appends a log message to the progress dialog. If the log area isn't visible yet 128 * it becomes visible. The height of the progress dialog is slightly increased too. 129 * 130 * @param message the message to append to the log. Ignore if null or white space only. 131 */ 132 @Override 133 public void appendLogMessage(String message) { 134 if (message == null || message.trim().isEmpty()) 135 return; 136 if (!spLog.isVisible()) { 137 spLog.setVisible(true); 138 taLog.setVisible(true); 139 adjustLayout(); 140 } 141 taLog.append(message); 142 taLog.append("\n"); 143 spLog.getVerticalScrollBar().setValue(spLog.getVerticalScrollBar().getMaximum()); 144 } 145 146 /** 147 * Sets whether the cancel button is enabled or not. 148 * 149 * @param enabled true, if the cancel button is enabled; false otherwise 150 * @see #setCancelCallback(ActionListener) 151 */ 152 public void setCancelEnabled(boolean enabled) { 153 btnCancel.setEnabled(enabled); 154 } 155 156 /** 157 * Enables / disables a button that can be pressed to run the task in background. 158 * 159 * @param value <code>true</code> iff that button should be displayed. 160 * @see #setInBackgroundCallback(ActionListener) 161 */ 162 public void setInBackgroundPossible(boolean value) { 163 btnInBackground.setVisible(value); 164 } 165 166 /** 167 * Installs a callback for the cancel button. If callback is null, all action listeners 168 * are removed from the cancel button. 169 * 170 * @param callback the cancel callback 171 */ 172 public void setCancelCallback(ActionListener callback) { 173 if (callback == null) { 174 ActionListener[] listeners = btnCancel.getActionListeners(); 175 for (ActionListener l: listeners) { 176 btnCancel.removeActionListener(l); 177 } 178 } else { 179 btnCancel.addActionListener(callback); 180 } 181 } 182 183 /** 184 * Installs a callback for the "In background" button. If callback is null, all action listeners 185 * are removed from the cancel button. 186 * 187 * @param callback the cancel callback 188 */ 189 public void setInBackgroundCallback(ActionListener callback) { 190 if (callback == null) { 191 ActionListener[] listeners = btnInBackground.getActionListeners(); 192 for (ActionListener l: listeners) { 193 btnInBackground.removeActionListener(l); 194 } 195 } else { 196 btnInBackground.addActionListener(callback); 197 } 198 } 199 200 @Override 201 public void updateProgress(int progress) { 202 this.progressBar.setValue(progress); 203 this.progressBar.repaint(); 204 } 205 206 /** 207 * Sets the maximum progress value. 208 * @param progressBarMax The value that represents the rightmost point of the progress bar (100%). 209 * @since 11672 210 */ 211 public void setMaximumProgress(int progressBarMax) { 212 this.progressBar.setMaximum(progressBarMax); 213 } 214}