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