001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.ui;
028
029import static org.opends.messages.AdminToolMessages.*;
030
031import java.awt.Color;
032import java.awt.Component;
033import java.awt.Container;
034import java.awt.GridBagConstraints;
035import java.awt.GridBagLayout;
036import java.awt.Insets;
037import java.awt.event.ActionEvent;
038import java.awt.event.ActionListener;
039import java.awt.event.FocusAdapter;
040import java.awt.event.FocusEvent;
041import java.awt.event.FocusListener;
042import java.awt.event.KeyEvent;
043import java.awt.event.WindowAdapter;
044import java.awt.event.WindowEvent;
045
046import javax.swing.AbstractButton;
047import javax.swing.BorderFactory;
048import javax.swing.Box;
049import javax.swing.JButton;
050import javax.swing.JComboBox;
051import javax.swing.JComponent;
052import javax.swing.JDialog;
053import javax.swing.JFrame;
054import javax.swing.JList;
055import javax.swing.JMenuBar;
056import javax.swing.JPanel;
057import javax.swing.JScrollPane;
058import javax.swing.JTable;
059import javax.swing.JViewport;
060import javax.swing.KeyStroke;
061import javax.swing.SwingUtilities;
062import javax.swing.border.EmptyBorder;
063import javax.swing.text.JTextComponent;
064
065import org.opends.guitools.controlpanel.util.Utilities;
066import org.opends.server.util.DynamicConstants;
067
068/**
069 * The generic dialog of the Control Panel.  It contains a StatusGenericPanel.
070 */
071public class GenericDialog extends JDialog
072{
073  private static final long serialVersionUID = -2643144936460484112L;
074  private static final Color buttonPanelBackground =
075    ColorAndFontConstants.greyBackground;
076  private JButton okButton;
077
078  /** The close button. */
079  protected JButton closeButton;
080  private JButton cancelButton;
081  /** The panel contained in the dialog. */
082  protected StatusGenericPanel panel;
083  private Component lastComponentWithFocus;
084
085  /** The different combinations of buttons that the dialog can have. */
086  public enum ButtonType
087  {
088    /** The dialog contains OK and CANCEL buttons. */
089    OK_CANCEL,
090    /** The dialog contains a OK button. */
091    OK,
092    /** The dialog contains a CLOSE button. */
093    CLOSE,
094    /** The dialog has no buttons. */
095    NO_BUTTON
096  }
097
098  /**
099   * Constructor of the dialog.
100   * @param parentFrame the parent frame of the dialog.
101   * @param panel the panel contained in this dialog.
102   */
103  public GenericDialog(JFrame parentFrame, StatusGenericPanel panel)
104  {
105    super(parentFrame);
106    this.panel = panel;
107    if (panel.requiresBorder())
108    {
109      setDefaultBorder(panel);
110    }
111    JMenuBar menu = panel.getMenuBar();
112    if (menu != null)
113    {
114      parentFrame.setJMenuBar(menu);
115    }
116    setResizable(true);
117    JScrollPane scroll = Utilities.createScrollPane(panel);
118    JPanel inputPanel = new JPanel(new GridBagLayout());
119    setContentPane(inputPanel);
120    GridBagConstraints gbc = new GridBagConstraints();
121    gbc.weightx = 1.0;
122    gbc.weighty = 1.0;
123    gbc.gridx = 0;
124    gbc.gridy = 0;
125    gbc.fill = GridBagConstraints.BOTH;
126    if (panel.requiresScroll())
127    {
128      inputPanel.add(scroll, gbc);
129    }
130    else
131    {
132      inputPanel.add(panel, gbc);
133    }
134    if (panel.getButtonType() != ButtonType.NO_BUTTON)
135    {
136      gbc.gridy ++;
137      gbc.weighty = 0.0;
138      inputPanel.add(createButtonsPanel(panel), gbc);
139    }
140
141    KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
142    ActionListener actionListener = new ActionListener()
143    {
144      /** {@inheritDoc} */
145      public void actionPerformed(ActionEvent ev)
146      {
147        setVisible(false);
148      }
149    };
150    getRootPane().registerKeyboardAction(actionListener, stroke,
151        JComponent.WHEN_IN_FOCUSED_WINDOW);
152
153    FocusListener focusListener = new FocusAdapter()
154    {
155      /** {@inheritDoc} */
156      public void focusGained(FocusEvent ev)
157      {
158        lastComponentWithFocus = ev.getComponent();
159      }
160    };
161    addFocusListener(focusListener, panel);
162
163    addWindowListener(new WindowAdapter() {
164      /** {@inheritDoc} */
165      public void windowClosing(WindowEvent e) {
166        GenericDialog.this.panel.closeClicked();
167      }
168    });
169
170    pack();
171    if (!SwingUtilities.isEventDispatchThread())
172    {
173      Thread.dumpStack();
174    }
175  }
176
177  /**
178   * Method used to add a focus listeners to all the components in the panel.
179   * This is done to recover the focus on an item when the dialog is closed
180   * and then opened again.
181   * @param focusListener the focus listener.
182   * @param container the container where the components are layed out.
183   */
184  private void addFocusListener(FocusListener focusListener,
185      Container container)
186  {
187    for (int i=0; i < container.getComponentCount(); i++)
188    {
189      Component comp = container.getComponent(i);
190      if (comp instanceof AbstractButton ||
191          comp instanceof JTextComponent ||
192          comp instanceof JList ||
193          comp instanceof JComboBox ||
194          comp instanceof JTable)
195      {
196        comp.addFocusListener(focusListener);
197      }
198      else if (comp instanceof JPanel || comp instanceof JScrollPane
199          || comp instanceof JViewport)
200      {
201        addFocusListener(focusListener, (Container)comp);
202      }
203    }
204  }
205
206  /** {@inheritDoc} */
207  public void setVisible(boolean visible)
208  {
209    if (visible && lastComponentWithFocus == null)
210    {
211      lastComponentWithFocus = panel.getPreferredFocusComponent();
212    }
213    if (visible && lastComponentWithFocus != null && lastComponentWithFocus.isVisible())
214    {
215      if (lastComponentWithFocus == null)
216      {
217        lastComponentWithFocus = panel.getPreferredFocusComponent();
218      }
219      lastComponentWithFocus.requestFocusInWindow();
220    }
221    updateDefaultButton(panel);
222    panel.toBeDisplayed(visible);
223    updateTitle();
224    super.setVisible(visible);
225  }
226
227  /**
228   * Sets the enable state of the OK button.
229   * @param enable whether the OK button must be enabled or not.
230   */
231  public void setEnabledOK(boolean enable)
232  {
233    okButton.setEnabled(enable);
234  }
235
236  /**
237   * Sets the enable state of the Cancel button.
238   * @param enable whether the Cancel button must be enabled or not.
239   */
240  public void setEnabledCancel(boolean enable)
241  {
242    cancelButton.setEnabled(enable);
243  }
244
245  /**
246   * Sets the enable state of the Close button.
247   * @param enable whether the Close button must be enabled or not.
248   */
249  public void setEnabledClose(boolean enable)
250  {
251    closeButton.setEnabled(enable);
252  }
253
254  /** Updates the title of the dialog using the title of the panel. */
255  public void updateTitle()
256  {
257    if (panel.getTitle() != null)
258    {
259      setTitle(INFO_CTRL_PANEL_GENERIC_TITLE.get(
260          DynamicConstants.PRODUCT_NAME, panel.getTitle()).toString());
261    }
262  }
263
264  private void setDefaultBorder(JComponent comp)
265  {
266    Utilities.setBorder(comp, new EmptyBorder(20, 20, 20, 20));
267  }
268
269  private JPanel createButtonsPanel(final StatusGenericPanel panel)
270  {
271    JPanel buttonsPanel = new JPanel(new GridBagLayout());
272    GridBagConstraints gbc = new GridBagConstraints();
273    ButtonType buttonType = panel.getButtonType();
274    gbc.gridx = 0;
275    gbc.weightx = 1.0;
276    gbc.fill = GridBagConstraints.HORIZONTAL;
277    buttonsPanel.add(Box.createHorizontalGlue(), gbc);
278    buttonsPanel.setOpaque(true);
279    buttonsPanel.setBackground(buttonPanelBackground);
280    gbc.insets = new Insets(10, 0, 10, 0);
281    gbc.insets.left = 5;
282
283    if (buttonType == ButtonType.OK_CANCEL)
284    {
285      gbc.gridx ++;
286      gbc.weightx = 0.0;
287      okButton = Utilities.createButton(
288          INFO_CTRL_PANEL_OK_BUTTON_LABEL.get());
289      okButton.setOpaque(false);
290      buttonsPanel.add(okButton, gbc);
291      okButton.addActionListener(new ActionListener()
292      {
293        public void actionPerformed(ActionEvent ev)
294        {
295          panel.okClicked();
296        }
297      });
298      okButton.setEnabled(panel.isEnableOK());
299
300      gbc.gridx ++;
301      cancelButton = Utilities.createButton(
302          INFO_CTRL_PANEL_CANCEL_BUTTON_LABEL.get());
303      cancelButton.setOpaque(false);
304      cancelButton.addActionListener(new ActionListener()
305      {
306        public void actionPerformed(ActionEvent ev)
307        {
308          panel.cancelClicked();
309        }
310      });
311      cancelButton.setEnabled(panel.isEnableCancel());
312      gbc.insets.right = 10;
313      buttonsPanel.add(cancelButton, gbc);
314    }
315
316    if (buttonType == ButtonType.OK)
317    {
318      gbc.gridx ++;
319      gbc.weightx = 0.0;
320      okButton = Utilities.createButton(
321          INFO_CTRL_PANEL_OK_BUTTON_LABEL.get());
322      okButton.setOpaque(false);
323      gbc.insets.right = 10;
324      buttonsPanel.add(okButton, gbc);
325      okButton.addActionListener(new ActionListener()
326      {
327        public void actionPerformed(ActionEvent ev)
328        {
329          panel.okClicked();
330        }
331      });
332      okButton.setEnabled(panel.isEnableOK());
333    }
334
335    if (buttonType == ButtonType.CLOSE)
336    {
337      gbc.gridx ++;
338      gbc.weightx = 0.0;
339      closeButton = Utilities.createButton(
340          INFO_CTRL_PANEL_CLOSE_BUTTON_LABEL.get());
341      closeButton.setOpaque(false);
342      gbc.insets.right = 10;
343      buttonsPanel.add(closeButton, gbc);
344      closeButton.addActionListener(new ActionListener()
345      {
346        public void actionPerformed(ActionEvent ev)
347        {
348          panel.closeClicked();
349        }
350      });
351      closeButton.setEnabled(panel.isEnableClose());
352    }
353
354
355
356    buttonsPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
357        ColorAndFontConstants.defaultBorderColor));
358    return buttonsPanel;
359  }
360
361  /**
362   * Updates the default button of the dialog, depending on the type of
363   * generic panel that it contains.
364   * @param panel the generic panel contained in this dialog.
365   */
366  private void updateDefaultButton(StatusGenericPanel panel)
367  {
368    ButtonType buttonType = panel.getButtonType();
369
370    if (buttonType == ButtonType.OK_CANCEL)
371    {
372      getRootPane().setDefaultButton(okButton);
373    }
374    else if (buttonType == ButtonType.OK)
375    {
376      getRootPane().setDefaultButton(okButton);
377    }
378    else if (buttonType == ButtonType.CLOSE)
379    {
380      getRootPane().setDefaultButton(closeButton);
381    }
382  }
383}