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