001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.quicksetup.ui;
018
019import static com.forgerock.opendj.util.OperatingSystem.isMacOS;
020
021import java.awt.Component;
022import java.awt.Dimension;
023import java.awt.GridBagConstraints;
024import java.awt.GridBagLayout;
025import java.awt.Toolkit;
026import java.awt.Window;
027import java.util.StringTokenizer;
028
029import javax.swing.Box;
030import javax.swing.JButton;
031import javax.swing.JFrame;
032import javax.swing.JLabel;
033import javax.swing.JOptionPane;
034import javax.swing.JPanel;
035import javax.swing.text.JTextComponent;
036
037import org.forgerock.i18n.LocalizableMessage;
038
039/**
040 * A set of utilities specific to GUI QuickSetup applications.
041 */
042public class Utilities {
043
044  /**
045   * Creates a panel with a field and a browse button.
046   * @param lbl JLabel for the field
047   * @param tf JTextField for holding the browsed data
048   * @param but JButton for invoking browse action
049   * @return the created panel.
050   */
051  public static JPanel createBrowseButtonPanel(JLabel lbl,
052                                         JTextComponent tf,
053                                         JButton but)
054  {
055    GridBagConstraints gbc = new GridBagConstraints();
056
057    JPanel panel = UIFactory.makeJPanel();
058    panel.setLayout(new GridBagLayout());
059
060    gbc.insets = UIFactory.getEmptyInsets();
061    gbc.gridwidth = 4;
062    gbc.weightx = 0.0;
063    gbc.fill = GridBagConstraints.HORIZONTAL;
064    panel.add(lbl, gbc);
065
066    gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
067    gbc.gridwidth--;
068    gbc.weightx = 0.1;
069    panel.add(tf, gbc);
070
071    gbc.insets.left = UIFactory.LEFT_INSET_BROWSE;
072    gbc.gridwidth = GridBagConstraints.RELATIVE;
073    panel.add(but, gbc);
074
075    gbc.weightx = 1.0;
076    gbc.gridwidth = GridBagConstraints.REMAINDER;
077    panel.add(Box.createHorizontalGlue(), gbc);
078
079    return panel;
080  }
081
082  /**
083   * Sets a frames image icon to the standard OpenDS icon appropriate
084   * for the running platform.
085   *
086   * @param frame for which the icon will be set
087   */
088  public static void setFrameIcon(JFrame frame)
089  {
090    UIFactory.IconType ic;
091    if (isMacOS()) {
092      ic = UIFactory.IconType.MINIMIZED_MAC;
093    } else {
094      ic = UIFactory.IconType.MINIMIZED;
095    }
096    frame.setIconImage(UIFactory.getImageIcon(ic).getImage());
097  }
098
099  /**
100   * Center the component location based on its preferred size. The code
101   * considers the particular case of 2 screens and puts the component on the
102   * center of the left screen
103   *
104   * @param comp the component to be centered.
105   */
106  public static void centerOnScreen(Component comp)
107  {
108    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
109
110    int width = (int) comp.getPreferredSize().getWidth();
111    int height = (int) comp.getPreferredSize().getHeight();
112
113    boolean multipleScreen = screenSize.width / screenSize.height >= 2;
114
115    if (multipleScreen)
116    {
117      comp.setLocation(screenSize.width / 4 - width / 2,
118          (screenSize.height - height) / 2);
119    } else
120    {
121      comp.setLocation((screenSize.width - width) / 2,
122          (screenSize.height - height) / 2);
123    }
124  }
125
126  /**
127   * Center the component location of the ref component.
128   *
129   * @param comp the component to be centered.
130   * @param ref the component to be used as reference.
131   *
132   */
133  public static void centerOnComponent(Window comp, Component ref)
134  {
135    comp.setLocationRelativeTo(ref);
136  }
137
138  /**
139   * Displays a confirmation message dialog.
140  *
141  * @param parent
142   *          the parent frame of the confirmation dialog.
143   * @param msg
144  *          the confirmation message.
145  * @param title
146  *          the title of the dialog.
147  * @return <CODE>true</CODE> if the user confirms the message, or
148  * <CODE>false</CODE> if not.
149  */
150 public static boolean displayConfirmation(Component parent, LocalizableMessage msg,
151     LocalizableMessage title)
152 {
153   return JOptionPane.YES_OPTION == JOptionPane.showOptionDialog(
154           parent, wrapMsg(String.valueOf(msg), 100), String.valueOf(title),
155           JOptionPane.YES_NO_OPTION,
156           JOptionPane.QUESTION_MESSAGE,
157           null, // don't use a custom Icon
158           null, // the titles of buttons
159           null); // default button title
160 }
161
162  /**
163   * Displays an error message dialog.
164   *
165   * @param parent
166   *          the parent component of the error dialog.
167   * @param msg
168 *          the error message.
169   * @param title
170   *          the title for the dialog.
171   */
172  public static void displayError(Component parent, LocalizableMessage msg, LocalizableMessage title)
173  {
174    JOptionPane.showMessageDialog(parent,
175            wrapMsg(String.valueOf(msg), 100),
176            String.valueOf(title), JOptionPane.ERROR_MESSAGE);
177  }
178
179  /**
180   * Displays an information message dialog.
181   *
182   * @param parent
183   *          the parent frame of the information dialog.
184   * @param msg
185 *          the error message.
186   * @param title
187   *          the title for the dialog.
188   */
189  public static void displayInformationMessage(JFrame parent, LocalizableMessage msg,
190      LocalizableMessage title)
191  {
192    JOptionPane.showMessageDialog(parent,
193            wrapMsg(String.valueOf(msg), 100), String.valueOf(title),
194            JOptionPane.INFORMATION_MESSAGE);
195  }
196
197  /**
198   * Private method used to wrap the messages that are displayed in dialogs
199   * of type JOptionPane.
200   * @param msg the message.
201   * @param width the maximum width of the column.
202   * @return the wrapped message.
203   */
204  private static String wrapMsg(String msg, int width)
205  {
206    StringBuilder   buffer        = new StringBuilder();
207    StringTokenizer lineTokenizer = new StringTokenizer(msg, "\n", true);
208    while (lineTokenizer.hasMoreTokens())
209    {
210      String line = lineTokenizer.nextToken();
211      if (line.equals("\n"))
212      {
213        // It's an end-of-line character, so append it as-is.
214        buffer.append(line);
215      }
216      else if (line.length() < width)
217      {
218        // The line fits in the specified width, so append it as-is.
219        buffer.append(line);
220      }
221      else
222      {
223        // The line doesn't fit in the specified width, so it needs to be
224        // wrapped.  Do so at space boundaries.
225        StringBuilder   lineBuffer    = new StringBuilder();
226        StringBuilder   delimBuffer   = new StringBuilder();
227        StringTokenizer wordTokenizer = new StringTokenizer(line, " ", true);
228        while (wordTokenizer.hasMoreTokens())
229        {
230          String word = wordTokenizer.nextToken();
231          if (word.equals(" "))
232          {
233            // It's a space, so add it to the delim buffer only if the line
234            // buffer is not empty.
235            if (lineBuffer.length() > 0)
236            {
237              delimBuffer.append(word);
238            }
239          }
240          else if (word.length() > width)
241          {
242            // This is a long word that can't be wrapped, so we'll just have to
243            // make do.
244            if (lineBuffer.length() > 0)
245            {
246              buffer.append(lineBuffer);
247              buffer.append("\n");
248              lineBuffer = new StringBuilder();
249            }
250            buffer.append(word);
251
252            if (wordTokenizer.hasMoreTokens())
253            {
254              // The next token must be a space, so remove it.  If there are
255              // still more tokens after that, then append an EOL.
256              wordTokenizer.nextToken();
257              if (wordTokenizer.hasMoreTokens())
258              {
259                buffer.append("\n");
260              }
261            }
262
263            if (delimBuffer.length() > 0)
264            {
265              delimBuffer = new StringBuilder();
266            }
267          }
268          else
269          {
270            // It's not a space, so see if we can fit it on the current line.
271            int newLineLength = lineBuffer.length() + delimBuffer.length() +
272            word.length();
273            if (newLineLength < width)
274            {
275              // It does fit on the line, so add it.
276              lineBuffer.append(delimBuffer).append(word);
277            }
278            else
279            {
280              // It doesn't fit on the line, so end the current line and start
281              // a new one.
282              buffer.append(lineBuffer);
283              buffer.append("\n");
284
285              lineBuffer = new StringBuilder();
286              lineBuffer.append(word);
287            }
288
289            if (delimBuffer.length() > 0)
290            {
291              delimBuffer = new StringBuilder();
292            }
293          }
294        }
295
296        // If there's anything left in the line buffer, then add it to the
297        // final buffer.
298        buffer.append(lineBuffer);
299      }
300    }
301    return buffer.toString();
302  }
303}