001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Sergey Burlak
019: * @version $Revision$
020: */package javax.swing;
021:
022: import java.awt.MouseInfo;
023: import java.awt.Point;
024: import java.awt.event.ActionEvent;
025: import java.awt.event.ActionListener;
026: import java.awt.event.MouseAdapter;
027: import java.awt.event.MouseEvent;
028: import java.awt.event.MouseMotionListener;
029: import java.util.LinkedList;
030:
031: import org.apache.harmony.x.swing.Utilities;
032:
033: import org.apache.harmony.x.swing.internal.nls.Messages;
034:
035: public class ToolTipManager extends MouseAdapter implements
036: MouseMotionListener {
037: protected class insideTimerAction implements ActionListener {
038: public void actionPerformed(final ActionEvent e) {
039: insideTimer.stop();
040: component = enteredComponent;
041: tipText = newTipText;
042: showPopup();
043: }
044: }
045:
046: protected class outsideTimerAction implements ActionListener {
047: public void actionPerformed(final ActionEvent e) {
048: outsideTimer.stop();
049: }
050: }
051:
052: protected class stillInsideTimerAction implements ActionListener {
053: public void actionPerformed(final ActionEvent e) {
054: hidePopup();
055: }
056: }
057:
058: protected boolean lightWeightPopupEnabled = true;
059: protected boolean heavyWeightPopupEnabled;
060:
061: //There is no API to retrieve actual cursor size. An approximate
062: //'default' cursor height is taken.
063: private static final int MOUSE_CURSOR_HEIGHT = 20;
064: private static ToolTipManager manager;
065:
066: private int reshowDelay = 500;
067: private int dismissDelay = 4000;
068: private int initialDelay = 750;
069:
070: private Timer insideTimer;
071: private Timer outsideTimer;
072: private Timer stillInsideTimer;
073:
074: private LinkedList componentsList;
075:
076: private boolean enabled = true;
077: private JComponent component;
078: private JComponent enteredComponent;
079: private Popup popup;
080: private String tipText;
081: private String newTipText;
082:
083: private ToolTipManager() {
084: insideTimer = new Timer(initialDelay, new insideTimerAction());
085: outsideTimer = new Timer(reshowDelay, new outsideTimerAction());
086: stillInsideTimer = new Timer(dismissDelay,
087: new stillInsideTimerAction());
088:
089: componentsList = new LinkedList();
090: }
091:
092: public void setEnabled(final boolean flag) {
093: enabled = flag;
094: }
095:
096: public boolean isEnabled() {
097: return enabled;
098: }
099:
100: public void setLightWeightPopupEnabled(final boolean flag) {
101: lightWeightPopupEnabled = flag;
102: }
103:
104: public boolean isLightWeightPopupEnabled() {
105: return lightWeightPopupEnabled;
106: }
107:
108: public void setInitialDelay(final int milliseconds) {
109: if (milliseconds < 0) {
110: throw new IllegalArgumentException(Messages.getString(
111: "swing.65", milliseconds)); //$NON-NLS-1$
112: }
113: initialDelay = milliseconds;
114: }
115:
116: public int getInitialDelay() {
117: return initialDelay;
118: }
119:
120: public void setDismissDelay(final int milliseconds) {
121: if (milliseconds < 0) {
122: throw new IllegalArgumentException(Messages.getString(
123: "swing.66", milliseconds)); //$NON-NLS-1$
124: }
125: dismissDelay = milliseconds;
126: }
127:
128: public int getDismissDelay() {
129: return dismissDelay;
130: }
131:
132: public void setReshowDelay(final int milliseconds) {
133: if (milliseconds < 0) {
134: throw new IllegalArgumentException(Messages.getString(
135: "swing.67", milliseconds)); //$NON-NLS-1$
136: }
137: reshowDelay = milliseconds;
138: }
139:
140: public int getReshowDelay() {
141: return reshowDelay;
142: }
143:
144: public static ToolTipManager sharedInstance() {
145: if (manager == null) {
146: manager = new ToolTipManager();
147: }
148:
149: return manager;
150: }
151:
152: public void registerComponent(final JComponent c) {
153: if (!componentsList.contains(c)) {
154: c.addMouseListener(this );
155: c.addMouseMotionListener(this );
156: componentsList.add(c);
157: }
158: }
159:
160: public void unregisterComponent(final JComponent c) {
161: componentsList.remove(c);
162: c.removeMouseListener(this );
163: c.removeMouseMotionListener(this );
164: }
165:
166: public void mouseEntered(final MouseEvent e) {
167: if (!isEnabled() || SwingUtilities.isLeftMouseButton(e)) {
168: return;
169: }
170: enteredComponent = (JComponent) e.getComponent();
171: newTipText = enteredComponent.getToolTipText(e);
172: if (outsideTimer.isRunning()) {
173: tipText = newTipText;
174: outsideTimer.stop();
175: component = enteredComponent;
176: showPopup();
177: } else {
178: insideTimer.restart();
179: }
180: }
181:
182: public void mouseExited(final MouseEvent e) {
183: boolean isPopupShown = stillInsideTimer.isRunning();
184: hidePopup();
185: if (isPopupShown) {
186: outsideTimer.restart();
187: }
188: insideTimer.stop();
189: }
190:
191: public void mousePressed(final MouseEvent e) {
192: hidePopup();
193: insideTimer.stop();
194: }
195:
196: public void mouseDragged(final MouseEvent e) {
197: }
198:
199: public void mouseMoved(final MouseEvent e) {
200: newTipText = ((JComponent) e.getComponent()).getToolTipText(e);
201:
202: if (component != e.getComponent()) {
203: return;
204: }
205: if (!toolTipTextChanged(newTipText)) {
206: return;
207: }
208:
209: if (stillInsideTimer.isRunning()) {
210: tipText = newTipText;
211: showPopup();
212: } else {
213: mouseEntered(e);
214: }
215: }
216:
217: private boolean toolTipTextChanged(final String newToolTipText) {
218: return (!Utilities.isEmptyString(newToolTipText) || !Utilities
219: .isEmptyString(tipText))
220: && (tipText == null || !tipText.equals(newToolTipText));
221: }
222:
223: private void hidePopup() {
224: if (popup != null) {
225: popup.hide();
226: popup = null;
227: insideTimer.stop();
228: stillInsideTimer.stop();
229: outsideTimer.stop();
230: }
231: }
232:
233: private void showPopup() {
234: if (!isEnabled()) {
235: return;
236: }
237:
238: if (Utilities.isEmptyString(tipText) || !component.isShowing()) {
239: hidePopup();
240: return;
241: }
242: JToolTip t = component.createToolTip();
243: t.setTipText(tipText);
244:
245: if (popup != null) {
246: popup.hide();
247: }
248: PopupFactory factory = PopupFactory.getSharedInstance();
249: Point toolTipPoint = MouseInfo.getPointerInfo().getLocation();
250: factory.setLWPopupsEnabled(isLightWeightPopupEnabled());
251: popup = factory.getPopup(component, t, toolTipPoint.x,
252: toolTipPoint.y + MOUSE_CURSOR_HEIGHT);
253: factory.setLWPopupsEnabled(false);
254: popup.show();
255: stillInsideTimer.restart();
256: }
257: }
|