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