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 2009 Sun Microsystems, Inc.
015 * Portions Copyright 2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.event;
019
020import java.awt.Component;
021import java.awt.Dimension;
022import java.awt.Point;
023import java.awt.Rectangle;
024import java.awt.event.MouseAdapter;
025import java.awt.event.MouseEvent;
026
027import javax.swing.JComponent;
028import javax.swing.JTable;
029import javax.swing.JToolTip;
030import javax.swing.Popup;
031import javax.swing.PopupFactory;
032import javax.swing.table.TableCellRenderer;
033
034/**
035 * This class listens to events and displays a tooltip when the user clicks on
036 * the object that registered this listener.
037 *
038 */
039public class ClickTooltipDisplayer extends MouseAdapter
040{
041  private boolean isTooltipVisible;
042  private Popup tipWindow;
043
044  /** {@inheritDoc} */
045  public void mouseExited(MouseEvent event)
046  {
047    hideToolTip(event);
048  }
049
050  /** {@inheritDoc} */
051  public void mousePressed(MouseEvent event)
052  {
053    if (isTooltipVisible)
054    {
055      hideToolTip(event);
056    }
057    else
058    {
059      displayToolTip(event);
060    }
061  }
062
063  /**
064   * Displays a tooltip depending on the MouseEvent received.
065   * @param event the mouse event.
066   */
067  private void displayToolTip(MouseEvent event)
068  {
069    JComponent component = (JComponent)event.getSource();
070    String toolTipText;
071    if (component instanceof JTable)
072    {
073      JTable table = (JTable)component;
074      int row = table.rowAtPoint(event.getPoint());
075      int column = table.columnAtPoint(event.getPoint());
076      if (row != -1 && column != -1)
077      {
078        TableCellRenderer renderer = table.getCellRenderer(row, column);
079        Component comp = renderer.getTableCellRendererComponent(table,
080            table.getValueAt(row, column), true, true, row, column);
081        if (comp instanceof JComponent)
082        {
083          // The coordinates must be translated.
084          Rectangle rect = table.getCellRect(row, column, true);
085          int x = event.getPoint().x - rect.x;
086          int y = event.getPoint().y - rect.y;
087          MouseEvent tEv = new MouseEvent(table, event.getID(),
088              event.getWhen(), event.getModifiers(), x, y,
089              event.getClickCount(), event.isPopupTrigger(), event.getButton());
090          toolTipText = ((JComponent)comp).getToolTipText(tEv);
091        }
092        else
093        {
094          toolTipText = null;
095        }
096      }
097      else
098      {
099        toolTipText = null;
100      }
101    }
102    else
103    {
104      toolTipText = component.getToolTipText();
105    }
106    if (toolTipText != null)
107    {
108      Point preferredLocation = component.getToolTipLocation(event);
109      Rectangle sBounds = component.getGraphicsConfiguration().
110      getBounds();
111
112      JToolTip tip = component.createToolTip();
113      tip.setTipText(toolTipText);
114      Dimension size = tip.getPreferredSize();
115      Point location = new Point();
116
117      Point screenLocation = component.getLocationOnScreen();
118      if(preferredLocation != null)
119      {
120        location.x = screenLocation.x + preferredLocation.x;
121        location.y = screenLocation.y + preferredLocation.y;
122      }
123      else
124      {
125        location.x = screenLocation.x + event.getX();
126        location.y = screenLocation.y + event.getY() + 20;
127      }
128
129      if (location.x < sBounds.x) {
130        location.x = sBounds.x;
131      }
132      else if (location.x - sBounds.x + size.width > sBounds.width) {
133        location.x = sBounds.x + Math.max(0, sBounds.width - size.width);
134      }
135      if (location.y < sBounds.y) {
136        location.y = sBounds.y;
137      }
138      else if (location.y - sBounds.y + size.height > sBounds.height) {
139        location.y = sBounds.y + Math.max(0, sBounds.height - size.height);
140      }
141
142      PopupFactory popupFactory = PopupFactory.getSharedInstance();
143      tipWindow = popupFactory.getPopup(component, tip, location.x, location.y);
144      tipWindow.show();
145      isTooltipVisible = true;
146    }
147  }
148
149  /**
150   * Hides the tooltip if we are displaying it.
151   * @param event the mouse event.
152   */
153  private void hideToolTip(MouseEvent event)
154  {
155    if (tipWindow != null)
156    {
157      tipWindow.hide();
158      tipWindow = null;
159      isTooltipVisible = false;
160    }
161  }
162}