View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.misc.gui;
17  
18  import java.awt.BorderLayout;
19  import java.awt.Component;
20  import java.awt.Font;
21  import java.awt.Toolkit;
22  import java.awt.Window;
23  import java.util.List;
24  import java.util.logging.Level;
25  
26  import javax.swing.AbstractButton;
27  import javax.swing.DefaultListModel;
28  import javax.swing.ImageIcon;
29  import javax.swing.JButton;
30  import javax.swing.JComponent;
31  import javax.swing.JDialog;
32  import javax.swing.JFileChooser;
33  import javax.swing.JLabel;
34  import javax.swing.JOptionPane;
35  import javax.swing.JPanel;
36  import javax.swing.JRadioButton;
37  
38  import org.jamesii.SimSystem;
39  import org.jamesii.gui.utils.BasicUtilities;
40  
41  import p3j.gui.P3J;
42  
43  import com.jgoodies.forms.layout.CellConstraints;
44  
45  /**
46   * Class to store static GUI helper functions.
47   * 
48   * Created on 4 February 4, 2007
49   * 
50   * @author Roland Ewald
51   */
52  public final class GUI {
53  
54    /** Number of pixels in the gaps of the standard border layout. */
55    public static final int STD_LAYOUT_GAP = 5;
56  
57    /** The font-size of the wait-message. */
58    private static final int FONT_SIZE_WAIT_MSG = 25;
59  
60    /** The normal font-size. */
61    private static final int FONT_SIZE_MEDIUM = 15;
62  
63    /**
64     * The number of rows used for a single 'content' row in the layout (for
65     * stand-alone dialogs).
66     */
67    public static final int ROW_SKIP_LAYOUT = 2;
68  
69    /**
70     * The index of the column at which the keys are added to the content panel
71     * (for stand-alone dialogs).
72     */
73    public static final int KEYS_COLUMN_INDEX = 2;
74  
75    /**
76     * The index of the column at which the input elements (textfields etc.) are
77     * added to the content panel (for stand-alone dialogs).
78     */
79    public static final int INPUT_COLUMN_INDEX = 4;
80  
81    /**
82     * Flag to determine whether we are in head-less mode (no GUI, therefore no
83     * need to display error messages in dialogs). This is particularly convenient
84     * for GUI tests.
85     */
86    private static boolean headless = false;
87  
88    /**
89     * This class should not be instantiated.
90     */
91    private GUI() {
92    }
93  
94    /**
95     * Get standard border layout. With 5 pixels gaps vertically/horizontally.
96     * 
97     * @return standard border layout
98     */
99    public static BorderLayout getStdBorderLayout() {
100     return new BorderLayout(STD_LAYOUT_GAP, STD_LAYOUT_GAP);
101   }
102 
103   /**
104    * Centre a given window on the screen.
105    * 
106    * @param window
107    *          a Window
108    */
109   public static void centerOnScreen(Window window) {
110     int locationX = (int) Math.round((Toolkit.getDefaultToolkit()
111         .getScreenSize().getWidth() - window.getWidth()) / 2);
112     int locationY = (int) Math.round((Toolkit.getDefaultToolkit()
113         .getScreenSize().getHeight() - window.getHeight()) / 2);
114     window.setLocation(locationX, locationY);
115   }
116 
117   /**
118    * Sets the head-less mode.
119    * 
120    * @param headless
121    *          the new head-less mode
122    */
123   public static void setHeadless(boolean headless) {
124     GUI.headless = headless;
125   }
126 
127   /**
128    * Checks the headless mode.
129    * 
130    * @return true if currently running head-less
131    */
132   public static boolean isHeadless() {
133     return GUI.headless;
134   }
135 
136   /**
137    * Prints an error message.
138    * 
139    * @param parent
140    *          the parent component for the dialog
141    * @param title
142    *          the title of the error dialog
143    * @param message
144    *          the message to be displayed
145    */
146   public static void printErrorMessage(Component parent, String title,
147       Object message) {
148     if (isHeadless()) {
149       return;
150     }
151     JOptionPane.showMessageDialog(parent, message, title,
152         JOptionPane.ERROR_MESSAGE);
153   }
154 
155   /**
156    * Prints an error message and the stack trace of the corresponding exception.
157    * 
158    * @param parent
159    *          the parent component for the dialog
160    * @param title
161    *          the title of the error dialog
162    * @param message
163    *          the message to be displayed
164    * @param throwable
165    *          the throwable (may provide additional info)
166    */
167   public static void printErrorMessage(Component parent, String title,
168       Object message, Throwable throwable) {
169     SimSystem.report(Level.SEVERE, title, throwable);
170     throwable.printStackTrace();
171     printErrorMessage(parent, title, message);
172   }
173 
174   /**
175    * Prints an error message with the P3J main window as parent instance. Uses
176    * {@link P3J#getInstance()} to retrieve it.
177    * 
178    * @param title
179    *          the title of the error dialog
180    * @param throwable
181    *          the throwable (may provide additional info)
182    */
183   public static void printErrorMessage(String title, Throwable throwable) {
184     SimSystem.report(Level.SEVERE, title, throwable);
185     printErrorMessage(P3J.getInstance(), title, throwable.getMessage(),
186         throwable);
187   }
188 
189   /**
190    * Creates a button with an icon.
191    * 
192    * @param iconFileName
193    *          the icon file name
194    * @param defaultText
195    *          the default text to be displayed when the icon cannot be loaded
196    * @return the button
197    */
198   public static JButton createIconButton(String iconFileName, String defaultText) {
199     return decorateButtonWithIconOrText(new JButton(),
200         retrieveIcon(iconFileName), defaultText);
201   }
202 
203   /**
204    * Creates a radio button with an icon.
205    * 
206    * @param iconFileName
207    *          the icon file name
208    * @param defaultText
209    *          the default text to be displayed when the icon cannot be loaded
210    * @return the button
211    */
212   public static JRadioButton createIconRadioButton(String iconFileName,
213       String defaultText) {
214     return decorateButtonWithIconOrText(new JRadioButton(),
215         retrieveIcon(iconFileName), defaultText);
216   }
217 
218   /**
219    * Decorate button with icon or text.
220    * 
221    * @param <B>
222    *          the generic type of the button
223    * @param button
224    *          the button
225    * @param icon
226    *          the icon
227    * @param defaultText
228    *          the default text
229    * @return the decorated button
230    */
231   public static <B extends AbstractButton> B decorateButtonWithIconOrText(
232       B button, ImageIcon icon, String defaultText) {
233     if (icon.getImage() != null) {
234       button.setIcon(icon);
235     } else {
236       button.setText(defaultText);
237     }
238     return button;
239   }
240 
241   /**
242    * Retrieves icon.
243    * 
244    * @param iconFileName
245    *          the icon file name
246    * @return the image icon
247    */
248   public static ImageIcon retrieveIcon(String iconFileName) {
249     return new ImageIcon(GUI.class.getResource("/p3j/icons/" + iconFileName));
250   }
251 
252   /**
253    * Prints a message.
254    * 
255    * @param parent
256    *          the parent component for the dialog
257    * @param title
258    *          the title of the error dialog
259    * @param message
260    *          the message to be displayed
261    */
262   public static void printMessage(Component parent, String title, Object message) {
263     if (isHeadless()) {
264       return;
265     }
266     JOptionPane.showMessageDialog(parent, message, title,
267         JOptionPane.INFORMATION_MESSAGE);
268   }
269 
270   /**
271    * Prints a question message.
272    * 
273    * @param parent
274    *          the parent component for the dialog
275    * @param title
276    *          the title of the dialog
277    * @param message
278    *          the question
279    * 
280    * @return true, if user chose yes, otherwise false
281    */
282   public static boolean printQuestion(Component parent, String title,
283       Object message) {
284 
285     if (isHeadless()) {
286       throw new UnsupportedOperationException(
287           "Cannot print question while in head-less mode.");
288     }
289 
290     int decision = JOptionPane.showConfirmDialog(parent, message, title,
291         JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
292 
293     if (decision == JOptionPane.YES_OPTION) {
294       return true;
295     }
296 
297     return false;
298   }
299 
300   /**
301    * Replaces the contents o a default list model.
302    * 
303    * @param model
304    *          the list model to be filled
305    * @param newContent
306    *          the list containing the content
307    */
308   public static void replaceListContents(DefaultListModel<Object> model,
309       List<?> newContent) {
310     model.clear();
311     if (newContent != null) {
312       for (Object element : newContent) {
313         model.addElement(element);
314       }
315     }
316   }
317 
318   /**
319    * Shows modal dialog without blocking (by setting visible to true via a
320    * separate runnable in the EDT).
321    * 
322    * @param dialogToShow
323    *          the dialog to show
324    */
325   public static void showModalDialog(final JDialog dialogToShow) {
326     BasicUtilities.invokeLaterOnEDT(new Runnable() {
327       @Override
328       public void run() {
329         dialogToShow.setVisible(true);
330         BasicUtilities.repaintOnEDT(dialogToShow);
331       }
332     });
333   }
334 
335   /**
336    * Gets a file chooser configured to select a directory.
337    * 
338    * @param dialogTitle
339    *          the dialog title
340    * 
341    * @return the directory chooser
342    */
343   public static JFileChooser getDirectoryChooser(String dialogTitle) {
344     JFileChooser fileChooser = new JFileChooser();
345     fileChooser.setMultiSelectionEnabled(false);
346     fileChooser.setDialogTitle(dialogTitle);
347     fileChooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
348     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
349     return fileChooser;
350   }
351 
352   /**
353    * Gets the label to wait.
354    * 
355    * @return the label to wait
356    */
357   public static JLabel getLabelToWait() {
358     JLabel msg = new JLabel("This may take a while. Please be patient...");
359     msg.setFont(getDefaultFontLarge());
360     return msg;
361   }
362 
363   /**
364    * Gets the large default font.
365    * 
366    * @return the large default font
367    */
368   public static Font getDefaultFontLarge() {
369     return new Font("Sans", Font.BOLD, FONT_SIZE_WAIT_MSG);
370   }
371 
372   /**
373    * Gets the default bold font.
374    * 
375    * @return the default bold font
376    */
377   public static Font getDefaultFontBold() {
378     return new Font("Sans", Font.BOLD, FONT_SIZE_MEDIUM);
379   }
380 
381   /**
382    * Adds a pair of key and input components to the given panel panel.
383    * 
384    * @param panel
385    *          the panel
386    * @param key
387    *          the name of the label to be used
388    * @param input
389    *          the input component
390    * @param currentRow
391    *          the current row in the layout
392    * @return the new row in the layout
393    */
394   public static int addRowToPanel(JPanel panel, String key, JComponent input,
395       int currentRow) {
396     CellConstraints c = new CellConstraints();
397     panel.add(new JLabel(key), c.xy(KEYS_COLUMN_INDEX, currentRow));
398     panel.add(input, c.xy(INPUT_COLUMN_INDEX, currentRow));
399     return currentRow + ROW_SKIP_LAYOUT;
400   }
401 }