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