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