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.ComponentEvent; 011import java.awt.event.ComponentListener; 012 013import javax.swing.BorderFactory; 014import javax.swing.BoundedRangeModel; 015import javax.swing.JButton; 016import javax.swing.JDialog; 017import javax.swing.JLabel; 018import javax.swing.JOptionPane; 019import javax.swing.JPanel; 020import javax.swing.JProgressBar; 021import javax.swing.JScrollPane; 022import javax.swing.UIManager; 023 024import org.openstreetmap.josm.Main; 025import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor.ProgressMonitorDialog; 026import org.openstreetmap.josm.gui.widgets.JosmTextArea; 027import org.openstreetmap.josm.tools.GBC; 028import org.openstreetmap.josm.tools.ImageProvider; 029 030public class PleaseWaitDialog extends JDialog implements ProgressMonitorDialog { 031 032 private final JProgressBar progressBar = new JProgressBar(); 033 034 private final JLabel currentAction = new JLabel(""); 035 private final JLabel customText = new JLabel(""); 036 public final transient BoundedRangeModel progress = progressBar.getModel(); 037 private JButton btnCancel; 038 private JButton btnInBackground; 039 /** the text area and the scroll pane for the log */ 040 private final JosmTextArea taLog = new JosmTextArea(5, 50); 041 private JScrollPane spLog; 042 043 private void initDialog() { 044 setLayout(new GridBagLayout()); 045 JPanel pane = new JPanel(new GridBagLayout()); 046 pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 047 pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL)); 048 pane.add(customText, GBC.eol().fill(GBC.HORIZONTAL)); 049 pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL)); 050 JPanel buttons = new JPanel(); 051 buttons.setLayout(new GridBagLayout()); 052 btnCancel = new JButton(tr("Cancel")); 053 btnCancel.setIcon(ImageProvider.get("cancel")); 054 btnCancel.setToolTipText(tr("Click to cancel the current operation")); 055 buttons.add(btnCancel); 056 btnInBackground = new JButton(tr("In background")); 057 btnInBackground.setToolTipText(tr("Click to run job in background")); 058 buttons.add(btnInBackground, GBC.std().fill(GBC.VERTICAL).insets(5, 0, 0, 0)); 059 pane.add(buttons, GBC.eol().anchor(GBC.CENTER)); 060 GridBagConstraints gc = GBC.eol().fill(GBC.BOTH); 061 gc.weighty = 1.0; 062 gc.weightx = 1.0; 063 pane.add(spLog = new JScrollPane(taLog), gc); 064 spLog.setVisible(false); 065 setContentPane(pane); 066 setCustomText(""); 067 setLocationRelativeTo(getParent()); 068 addComponentListener(new ComponentListener() { 069 @Override 070 public void componentHidden(ComponentEvent e) {} 071 072 @Override 073 public void componentMoved(ComponentEvent e) {} 074 075 @Override 076 public void componentShown(ComponentEvent e) {} 077 078 @Override 079 public void componentResized(ComponentEvent ev) { 080 int w = getWidth(); 081 if (w > 200) { 082 Main.pref.putInteger("progressdialog.size", w); 083 } 084 } 085 }); 086 } 087 088 /** 089 * Constructs a new {@code PleaseWaitDialog}. 090 * @param parent the {@code Component} from which the dialog is displayed. Can be {@code null}. 091 */ 092 public PleaseWaitDialog(Component parent) { 093 super(JOptionPane.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL); 094 initDialog(); 095 } 096 097 @Override 098 public void setIndeterminate(boolean newValue) { 099 UIManager.put("ProgressBar.cycleTime", UIManager.getInt("ProgressBar.repaintInterval") * 100); 100 progressBar.setIndeterminate(newValue); 101 } 102 103 protected void adjustLayout() { 104 invalidate(); 105 setDropTarget(null); // Workaround to JDK bug 7027598/7100524/7169912 (#8613) 106 pack(); 107 setSize(Main.pref.getInteger("progressdialog.size", 600), getSize().height); 108 } 109 110 /** 111 * Sets a custom text line below currentAction. Can be used to display additional information 112 * @param text custom text 113 */ 114 @Override 115 public void setCustomText(String text) { 116 if (text == null || text.trim().isEmpty()) { 117 customText.setVisible(false); 118 adjustLayout(); 119 return; 120 } 121 customText.setText(text); 122 if (!customText.isVisible()) { 123 customText.setVisible(true); 124 adjustLayout(); 125 } 126 } 127 128 @Override 129 public void setCurrentAction(String text) { 130 currentAction.setText(text); 131 } 132 133 /** 134 * Appends a log message to the progress dialog. If the log area isn't visible yet 135 * it becomes visible. The height of the progress dialog is slightly increased too. 136 * 137 * @param message the message to append to the log. Ignore if null or white space only. 138 */ 139 @Override 140 public void appendLogMessage(String message) { 141 if (message == null || message.trim().isEmpty()) 142 return; 143 if (!spLog.isVisible()) { 144 spLog.setVisible(true); 145 taLog.setVisible(true); 146 adjustLayout(); 147 } 148 taLog.append(message); 149 taLog.append("\n"); 150 spLog.getVerticalScrollBar().setValue(spLog.getVerticalScrollBar().getMaximum()); 151 } 152 153 /** 154 * Sets whether the cancel button is enabled or not 155 * 156 * @param enabled true, if the cancel button is enabled; false otherwise 157 */ 158 public void setCancelEnabled(boolean enabled) { 159 btnCancel.setEnabled(enabled); 160 } 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.progress.setValue(progress); 203 this.progressBar.repaint(); 204 } 205}