History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/ToolTipManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/ToolTipManager.java+828−0
@@ -0,0 +1,828 @@
1+/*
2+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+
27+package javax.swing;
28+
29+import java.awt.event.*;
30+import java.awt.*;
31+
32+/**
33+ * Manages all the <code>ToolTips</code> in the system.
34+ * <p>
35+ * ToolTipManager contains numerous properties for configuring how long it
36+ * will take for the tooltips to become visible, and how long till they
37+ * hide. Consider a component that has a different tooltip based on where
38+ * the mouse is, such as JTree. When the mouse moves into the JTree and
39+ * over a region that has a valid tooltip, the tooltip will become
40+ * visibile after <code>initialDelay</code> milliseconds. After
41+ * <code>dismissDelay</code> milliseconds the tooltip will be hidden. If
42+ * the mouse is over a region that has a valid tooltip, and the tooltip
43+ * is currently visible, when the mouse moves to a region that doesn't have
44+ * a valid tooltip the tooltip will be hidden. If the mouse then moves back
45+ * into a region that has a valid tooltip within <code>reshowDelay</code>
46+ * milliseconds, the tooltip will immediately be shown, otherwise the
47+ * tooltip will be shown again after <code>initialDelay</code> milliseconds.
48+ *
49+ * @see JComponent#createToolTip
50+ * @author Dave Moore
51+ * @author Rich Schiavi
52+ */
53+public class ToolTipManager extends MouseAdapter implements MouseMotionListener {
54+ Timer enterTimer, exitTimer, insideTimer;
55+ String toolTipText;
56+ Point preferredLocation;
57+ JComponent insideComponent;
58+ MouseEvent mouseEvent;
59+ boolean showImmediately;
60+ private static final Object TOOL_TIP_MANAGER_KEY = new Object();
61+ transient Popup tipWindow;
62+ /** The Window tip is being displayed in. This will be non-null if
63+ * the Window tip is in differs from that of insideComponent's Window.
64+ */
65+ private Window window;
66+ JToolTip tip;
67+
68+ private Rectangle popupRect = null;
69+ private Rectangle popupFrameRect = null;
70+
71+ boolean enabled = true;
72+ private boolean tipShowing = false;
73+
74+ private FocusListener focusChangeListener = null;
75+ private MouseMotionListener moveBeforeEnterListener = null;
76+ private KeyListener accessibilityKeyListener = null;
77+
78+ private KeyStroke postTip;
79+ private KeyStroke hideTip;
80+
81+ // PENDING(ges)
82+ protected boolean lightWeightPopupEnabled = true;
83+ protected boolean heavyWeightPopupEnabled = false;
84+
85+ ToolTipManager() {
86+ enterTimer = new Timer(750, new insideTimerAction());
87+ enterTimer.setRepeats(false);
88+ exitTimer = new Timer(500, new outsideTimerAction());
89+ exitTimer.setRepeats(false);
90+ insideTimer = new Timer(4000, new stillInsideTimerAction());
91+ insideTimer.setRepeats(false);
92+
93+ moveBeforeEnterListener = new MoveBeforeEnterListener();
94+ accessibilityKeyListener = new AccessibilityKeyListener();
95+
96+ postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1, InputEvent.CTRL_MASK);
97+ hideTip = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
98+ }
99+
100+ /**
101+ * Enables or disables the tooltip.
102+ *
103+ * @param flag true to enable the tip, false otherwise
104+ */
105+ public void setEnabled(boolean flag) {
106+ enabled = flag;
107+ if (!flag) {
108+ hideTipWindow();
109+ }
110+ }
111+
112+ /**
113+ * Returns true if this object is enabled.
114+ *
115+ * @return true if this object is enabled, false otherwise
116+ */
117+ public boolean isEnabled() {
118+ return enabled;
119+ }
120+
121+ /**
122+ * When displaying the <code>JToolTip</code>, the
123+ * <code>ToolTipManager</code> chooses to use a lightweight
124+ * <code>JPanel</code> if it fits. This method allows you to
125+ * disable this feature. You have to do disable it if your
126+ * application mixes light weight and heavy weights components.
127+ *
128+ * @param aFlag true if a lightweight panel is desired, false otherwise
129+ *
130+ */
131+ public void setLightWeightPopupEnabled(boolean aFlag){
132+ lightWeightPopupEnabled = aFlag;
133+ }
134+
135+ /**
136+ * Returns true if lightweight (all-Java) <code>Tooltips</code>
137+ * are in use, or false if heavyweight (native peer)
138+ * <code>Tooltips</code> are being used.
139+ *
140+ * @return true if lightweight <code>ToolTips</code> are in use
141+ */
142+ public boolean isLightWeightPopupEnabled() {
143+ return lightWeightPopupEnabled;
144+ }
145+
146+
147+ /**
148+ * Specifies the initial delay value.
149+ *
150+ * @param milliseconds the number of milliseconds to delay
151+ * (after the cursor has paused) before displaying the
152+ * tooltip
153+ * @see #getInitialDelay
154+ */
155+ public void setInitialDelay(int milliseconds) {
156+ enterTimer.setInitialDelay(milliseconds);
157+ }
158+
159+ /**
160+ * Returns the initial delay value.
161+ *
162+ * @return an integer representing the initial delay value,
163+ * in milliseconds
164+ * @see #setInitialDelay
165+ */
166+ public int getInitialDelay() {
167+ return enterTimer.getInitialDelay();
168+ }
169+
170+ /**
171+ * Specifies the dismissal delay value.
172+ *
173+ * @param milliseconds the number of milliseconds to delay
174+ * before taking away the tooltip
175+ * @see #getDismissDelay
176+ */
177+ public void setDismissDelay(int milliseconds) {
178+ insideTimer.setInitialDelay(milliseconds);
179+ }
180+
181+ /**
182+ * Returns the dismissal delay value.
183+ *
184+ * @return an integer representing the dismissal delay value,
185+ * in milliseconds
186+ * @see #setDismissDelay
187+ */
188+ public int getDismissDelay() {
189+ return insideTimer.getInitialDelay();
190+ }
191+
192+ /**
193+ * Used to specify the amount of time before the user has to wait
194+ * <code>initialDelay</code> milliseconds before a tooltip will be
195+ * shown. That is, if the tooltip is hidden, and the user moves into
196+ * a region of the same Component that has a valid tooltip within
197+ * <code>milliseconds</code> milliseconds the tooltip will immediately
198+ * be shown. Otherwise, if the user moves into a region with a valid
199+ * tooltip after <code>milliseconds</code> milliseconds, the user
200+ * will have to wait an additional <code>initialDelay</code>
201+ * milliseconds before the tooltip is shown again.
202+ *
203+ * @param milliseconds time in milliseconds
204+ * @see #getReshowDelay
205+ */
206+ public void setReshowDelay(int milliseconds) {
207+ exitTimer.setInitialDelay(milliseconds);
208+ }
209+
210+ /**
211+ * Returns the reshow delay property.
212+ *
213+ * @return reshown delay property
214+ * @see #setReshowDelay
215+ */
216+ public int getReshowDelay() {
217+ return exitTimer.getInitialDelay();
218+ }
219+
220+ void showTipWindow() {
221+ if(insideComponent == null || !insideComponent.isShowing())
222+ return;
223+ String mode = UIManager.getString("ToolTipManager.enableToolTipMode");
224+ if ("activeApplication".equals(mode)) {
225+ KeyboardFocusManager kfm =
226+ KeyboardFocusManager.getCurrentKeyboardFocusManager();
227+ if (kfm.getFocusedWindow() == null) {
228+ return;
229+ }
230+ }
231+ if (enabled) {
232+ Dimension size;
233+ Point screenLocation = insideComponent.getLocationOnScreen();
234+ Point location = new Point();
235+ GraphicsConfiguration gc;
236+ gc = insideComponent.getGraphicsConfiguration();
237+ Rectangle sBounds = gc.getBounds();
238+ Insets screenInsets = Toolkit.getDefaultToolkit()
239+ .getScreenInsets(gc);
240+ // Take into account screen insets, decrease viewport
241+ sBounds.x += screenInsets.left;
242+ sBounds.y += screenInsets.top;
243+ sBounds.width -= (screenInsets.left + screenInsets.right);
244+ sBounds.height -= (screenInsets.top + screenInsets.bottom);
245+ boolean leftToRight
246+ = SwingUtilities.isLeftToRight(insideComponent);
247+
248+ // Just to be paranoid
249+ hideTipWindow();
250+
251+ tip = insideComponent.createToolTip();
252+ tip.setTipText(toolTipText);
253+ size = tip.getPreferredSize();
254+
255+ if(preferredLocation != null) {
256+ location.x = screenLocation.x + preferredLocation.x;
257+ location.y = screenLocation.y + preferredLocation.y;
258+ if (!leftToRight) {
259+ location.x -= size.width;
260+ }
261+ } else {
262+ location.x = screenLocation.x + mouseEvent.getX();
263+ location.y = screenLocation.y + mouseEvent.getY() + 20;
264+ if (!leftToRight) {
265+ if(location.x - size.width>=0) {
266+ location.x -= size.width;
267+ }
268+ }
269+
270+ }
271+
272+ // we do not adjust x/y when using awt.Window tips
273+ if (popupRect == null){
274+ popupRect = new Rectangle();
275+ }
276+ popupRect.setBounds(location.x,location.y,
277+ size.width,size.height);
278+
279+ // Fit as much of the tooltip on screen as possible
280+ if (location.x < sBounds.x) {
281+ location.x = sBounds.x;
282+ }
283+ else if (location.x - sBounds.x + size.width > sBounds.width) {
284+ location.x = sBounds.x + Math.max(0, sBounds.width - size.width)
285+;
286+ }
287+ if (location.y < sBounds.y) {
288+ location.y = sBounds.y;
289+ }
290+ else if (location.y - sBounds.y + size.height > sBounds.height) {
291+ location.y = sBounds.y + Math.max(0, sBounds.height - size.height);
292+ }
293+
294+ PopupFactory popupFactory = PopupFactory.getSharedInstance();
295+
296+ if (lightWeightPopupEnabled) {
297+ int y = getPopupFitHeight(popupRect, insideComponent);
298+ int x = getPopupFitWidth(popupRect,insideComponent);
299+ if (x>0 || y>0) {
300+ popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
301+ } else {
302+ popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
303+ }
304+ }
305+ else {
306+ popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
307+ }
308+ tipWindow = popupFactory.getPopup(insideComponent, tip,
309+ location.x,
310+ location.y);
311+ popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
312+
313+ tipWindow.show();
314+
315+ Window componentWindow = SwingUtilities.windowForComponent(
316+ insideComponent);
317+
318+ window = SwingUtilities.windowForComponent(tip);
319+ if (window != null && window != componentWindow) {
320+ window.addMouseListener(this);
321+ }
322+ else {
323+ window = null;
324+ }
325+
326+ insideTimer.start();
327+ tipShowing = true;
328+ }
329+ }
330+
331+ void hideTipWindow() {
332+ if (tipWindow != null) {
333+ if (window != null) {
334+ window.removeMouseListener(this);
335+ window = null;
336+ }
337+ tipWindow.hide();
338+ tipWindow = null;
339+ tipShowing = false;
340+ tip = null;
341+ insideTimer.stop();
342+ }
343+ }
344+
345+ /**
346+ * Returns a shared <code>ToolTipManager</code> instance.
347+ *
348+ * @return a shared <code>ToolTipManager</code> object
349+ */
350+ public static ToolTipManager sharedInstance() {
351+ Object value = SwingUtilities.appContextGet(TOOL_TIP_MANAGER_KEY);
352+ if (value instanceof ToolTipManager) {
353+ return (ToolTipManager) value;
354+ }
355+ ToolTipManager manager = new ToolTipManager();
356+ SwingUtilities.appContextPut(TOOL_TIP_MANAGER_KEY, manager);
357+ return manager;
358+ }
359+
360+ // add keylistener here to trigger tip for access
361+ /**
362+ * Registers a component for tooltip management.
363+ * <p>
364+ * This will register key bindings to show and hide the tooltip text
365+ * only if <code>component</code> has focus bindings. This is done
366+ * so that components that are not normally focus traversable, such
367+ * as <code>JLabel</code>, are not made focus traversable as a result
368+ * of invoking this method.
369+ *
370+ * @param component a <code>JComponent</code> object to add
371+ * @see JComponent#isFocusTraversable
372+ */
373+ public void registerComponent(JComponent component) {
374+ component.removeMouseListener(this);
375+ component.addMouseListener(this);
376+ component.removeMouseMotionListener(moveBeforeEnterListener);
377+ component.addMouseMotionListener(moveBeforeEnterListener);
378+ component.removeKeyListener(accessibilityKeyListener);
379+ component.addKeyListener(accessibilityKeyListener);
380+ }
381+
382+ /**
383+ * Removes a component from tooltip control.
384+ *
385+ * @param component a <code>JComponent</code> object to remove
386+ */
387+ public void unregisterComponent(JComponent component) {
388+ component.removeMouseListener(this);
389+ component.removeMouseMotionListener(moveBeforeEnterListener);
390+ component.removeKeyListener(accessibilityKeyListener);
391+ }
392+
393+ // implements java.awt.event.MouseListener
394+ /**
395+ * Called when the mouse enters the region of a component.
396+ * This determines whether the tool tip should be shown.
397+ *
398+ * @param event the event in question
399+ */
400+ public void mouseEntered(MouseEvent event) {
401+ initiateToolTip(event);
402+ }
403+
404+ private void initiateToolTip(MouseEvent event) {
405+ if (event.getSource() == window) {
406+ return;
407+ }
408+ JComponent component = (JComponent)event.getSource();
409+ component.removeMouseMotionListener(moveBeforeEnterListener);
410+
411+ exitTimer.stop();
412+
413+ Point location = event.getPoint();
414+ // ensure tooltip shows only in proper place
415+ if (location.x < 0 ||
416+ location.x >=component.getWidth() ||
417+ location.y < 0 ||
418+ location.y >= component.getHeight()) {
419+ return;
420+ }
421+
422+ if (insideComponent != null) {
423+ enterTimer.stop();
424+ }
425+ // A component in an unactive internal frame is sent two
426+ // mouseEntered events, make sure we don't end up adding
427+ // ourselves an extra time.
428+ component.removeMouseMotionListener(this);
429+ component.addMouseMotionListener(this);
430+
431+ boolean sameComponent = (insideComponent == component);
432+
433+ insideComponent = component;
434+ if (tipWindow != null){
435+ mouseEvent = event;
436+ if (showImmediately) {
437+ String newToolTipText = component.getToolTipText(event);
438+ Point newPreferredLocation = component.getToolTipLocation(
439+ event);
440+ boolean sameLoc = (preferredLocation != null) ?
441+ preferredLocation.equals(newPreferredLocation) :
442+ (newPreferredLocation == null);
443+
444+ if (!sameComponent || !toolTipText.equals(newToolTipText) ||
445+ !sameLoc) {
446+ toolTipText = newToolTipText;
447+ preferredLocation = newPreferredLocation;
448+ showTipWindow();
449+ }
450+ } else {
451+ enterTimer.start();
452+ }
453+ }
454+ }
455+
456+ // implements java.awt.event.MouseListener
457+ /**
458+ * Called when the mouse exits the region of a component.
459+ * Any tool tip showing should be hidden.
460+ *
461+ * @param event the event in question
462+ */
463+ public void mouseExited(MouseEvent event) {
464+ boolean shouldHide = true;
465+ if (insideComponent == null) {
466+ // Drag exit
467+ }
468+ if (window != null && event.getSource() == window && insideComponent != null) {
469+ // if we get an exit and have a heavy window
470+ // we need to check if it if overlapping the inside component
471+ Container insideComponentWindow = insideComponent.getTopLevelAncestor();
472+ // insideComponent may be removed after tooltip is made visible
473+ if (insideComponentWindow != null) {
474+ Point location = event.getPoint();
475+ SwingUtilities.convertPointToScreen(location, window);
476+
477+ location.x -= insideComponentWindow.getX();
478+ location.y -= insideComponentWindow.getY();
479+
480+ location = SwingUtilities.convertPoint(null, location, insideComponent);
481+ if (location.x >= 0 && location.x < insideComponent.getWidth() &&
482+ location.y >= 0 && location.y < insideComponent.getHeight()) {
483+ shouldHide = false;
484+ } else {
485+ shouldHide = true;
486+ }
487+ }
488+ } else if(event.getSource() == insideComponent && tipWindow != null) {
489+ Window win = SwingUtilities.getWindowAncestor(insideComponent);
490+ if (win != null) { // insideComponent may have been hidden (e.g. in a menu)
491+ Point location = SwingUtilities.convertPoint(insideComponent,
492+ event.getPoint(),
493+ win);
494+ Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();
495+ location.x += bounds.x;
496+ location.y += bounds.y;
497+
498+ Point loc = new Point(0, 0);
499+ SwingUtilities.convertPointToScreen(loc, tip);
500+ bounds.x = loc.x;
501+ bounds.y = loc.y;
502+ bounds.width = tip.getWidth();
503+ bounds.height = tip.getHeight();
504+
505+ if (location.x >= bounds.x && location.x < (bounds.x + bounds.width) &&
506+ location.y >= bounds.y && location.y < (bounds.y + bounds.height)) {
507+ shouldHide = false;
508+ } else {
509+ shouldHide = true;
510+ }
511+ }
512+ }
513+
514+ if (shouldHide) {
515+ enterTimer.stop();
516+ if (insideComponent != null) {
517+ insideComponent.removeMouseMotionListener(this);
518+ }
519+ insideComponent = null;
520+ toolTipText = null;
521+ mouseEvent = null;
522+ hideTipWindow();
523+ exitTimer.restart();
524+ }
525+ }
526+
527+ // implements java.awt.event.MouseListener
528+ /**
529+ * Called when the mouse is pressed.
530+ * Any tool tip showing should be hidden.
531+ *
532+ * @param event the event in question
533+ */
534+ public void mousePressed(MouseEvent event) {
535+ hideTipWindow();
536+ enterTimer.stop();
537+ showImmediately = false;
538+ insideComponent = null;
539+ mouseEvent = null;
540+ }
541+
542+ // implements java.awt.event.MouseMotionListener
543+ /**
544+ * Called when the mouse is pressed and dragged.
545+ * Does nothing.
546+ *
547+ * @param event the event in question
548+ */
549+ public void mouseDragged(MouseEvent event) {
550+ }
551+
552+ // implements java.awt.event.MouseMotionListener
553+ /**
554+ * Called when the mouse is moved.
555+ * Determines whether the tool tip should be displayed.
556+ *
557+ * @param event the event in question
558+ */
559+ public void mouseMoved(MouseEvent event) {
560+ if (tipShowing) {
561+ checkForTipChange(event);
562+ }
563+ else if (showImmediately) {
564+ JComponent component = (JComponent)event.getSource();
565+ toolTipText = component.getToolTipText(event);
566+ if (toolTipText != null) {
567+ preferredLocation = component.getToolTipLocation(event);
568+ mouseEvent = event;
569+ insideComponent = component;
570+ exitTimer.stop();
571+ showTipWindow();
572+ }
573+ }
574+ else {
575+ // Lazily lookup the values from within insideTimerAction
576+ insideComponent = (JComponent)event.getSource();
577+ mouseEvent = event;
578+ toolTipText = null;
579+ enterTimer.restart();
580+ }
581+ }
582+
583+ /**
584+ * Checks to see if the tooltip needs to be changed in response to
585+ * the MouseMoved event <code>event</code>.
586+ */
587+ private void checkForTipChange(MouseEvent event) {
588+ JComponent component = (JComponent)event.getSource();
589+ String newText = component.getToolTipText(event);
590+ Point newPreferredLocation = component.getToolTipLocation(event);
591+
592+ if (newText != null || newPreferredLocation != null) {
593+ mouseEvent = event;
594+ if (((newText != null && newText.equals(toolTipText)) || newText == null) &&
595+ ((newPreferredLocation != null && newPreferredLocation.equals(preferredLocation))
596+ || newPreferredLocation == null)) {
597+ if (tipWindow != null) {
598+ insideTimer.restart();
599+ } else {
600+ enterTimer.restart();
601+ }
602+ } else {
603+ toolTipText = newText;
604+ preferredLocation = newPreferredLocation;
605+ if (showImmediately) {
606+ hideTipWindow();
607+ showTipWindow();
608+ exitTimer.stop();
609+ } else {
610+ enterTimer.restart();
611+ }
612+ }
613+ } else {
614+ toolTipText = null;
615+ preferredLocation = null;
616+ mouseEvent = null;
617+ insideComponent = null;
618+ hideTipWindow();
619+ enterTimer.stop();
620+ exitTimer.restart();
621+ }
622+ }
623+
624+ protected class insideTimerAction implements ActionListener {
625+ public void actionPerformed(ActionEvent e) {
626+ if(insideComponent != null && insideComponent.isShowing()) {
627+ // Lazy lookup
628+ if (toolTipText == null && mouseEvent != null) {
629+ toolTipText = insideComponent.getToolTipText(mouseEvent);
630+ preferredLocation = insideComponent.getToolTipLocation(
631+ mouseEvent);
632+ }
633+ if(toolTipText != null) {
634+ showImmediately = true;
635+ showTipWindow();
636+ }
637+ else {
638+ insideComponent = null;
639+ toolTipText = null;
640+ preferredLocation = null;
641+ mouseEvent = null;
642+ hideTipWindow();
643+ }
644+ }
645+ }
646+ }
647+
648+ protected class outsideTimerAction implements ActionListener {
649+ public void actionPerformed(ActionEvent e) {
650+ showImmediately = false;
651+ }
652+ }
653+
654+ protected class stillInsideTimerAction implements ActionListener {
655+ public void actionPerformed(ActionEvent e) {
656+ hideTipWindow();
657+ enterTimer.stop();
658+ showImmediately = false;
659+ insideComponent = null;
660+ mouseEvent = null;
661+ }
662+ }
663+
664+ /* This listener is registered when the tooltip is first registered
665+ * on a component in order to catch the situation where the tooltip
666+ * was turned on while the mouse was already within the bounds of
667+ * the component. This way, the tooltip will be initiated on a
668+ * mouse-entered or mouse-moved, whichever occurs first. Once the
669+ * tooltip has been initiated, we can remove this listener and rely
670+ * solely on mouse-entered to initiate the tooltip.
671+ */
672+ private class MoveBeforeEnterListener extends MouseMotionAdapter {
673+ public void mouseMoved(MouseEvent e) {
674+ initiateToolTip(e);
675+ }
676+ }
677+
678+ static Frame frameForComponent(Component component) {
679+ while (!(component instanceof Frame)) {
680+ component = component.getParent();
681+ }
682+ return (Frame)component;
683+ }
684+
685+ private FocusListener createFocusChangeListener(){
686+ return new FocusAdapter(){
687+ public void focusLost(FocusEvent evt){
688+ hideTipWindow();
689+ insideComponent = null;
690+ JComponent c = (JComponent)evt.getSource();
691+ c.removeFocusListener(focusChangeListener);
692+ }
693+ };
694+ }
695+
696+ // Returns: 0 no adjust
697+ // -1 can't fit
698+ // >0 adjust value by amount returned
699+ private int getPopupFitWidth(Rectangle popupRectInScreen, Component invoker){
700+ if (invoker != null){
701+ Container parent;
702+ for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
703+ // fix internal frame size bug: 4139087 - 4159012
704+ if(parent instanceof JFrame || parent instanceof JDialog ||
705+ parent instanceof JWindow) { // no check for awt.Frame since we use Heavy tips
706+ return getWidthAdjust(parent.getBounds(),popupRectInScreen);
707+ } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
708+ if (popupFrameRect == null){
709+ popupFrameRect = new Rectangle();
710+ }
711+ Point p = parent.getLocationOnScreen();
712+ popupFrameRect.setBounds(p.x,p.y,
713+ parent.getBounds().width,
714+ parent.getBounds().height);
715+ return getWidthAdjust(popupFrameRect,popupRectInScreen);
716+ }
717+ }
718+ }
719+ return 0;
720+ }
721+
722+ // Returns: 0 no adjust
723+ // >0 adjust by value return
724+ private int getPopupFitHeight(Rectangle popupRectInScreen, Component invoker){
725+ if (invoker != null){
726+ Container parent;
727+ for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
728+ if(parent instanceof JFrame || parent instanceof JDialog ||
729+ parent instanceof JWindow) {
730+ return getHeightAdjust(parent.getBounds(),popupRectInScreen);
731+ } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
732+ if (popupFrameRect == null){
733+ popupFrameRect = new Rectangle();
734+ }
735+ Point p = parent.getLocationOnScreen();
736+ popupFrameRect.setBounds(p.x,p.y,
737+ parent.getBounds().width,
738+ parent.getBounds().height);
739+ return getHeightAdjust(popupFrameRect,popupRectInScreen);
740+ }
741+ }
742+ }
743+ return 0;
744+ }
745+
746+ private int getHeightAdjust(Rectangle a, Rectangle b){
747+ if (b.y >= a.y && (b.y + b.height) <= (a.y + a.height))
748+ return 0;
749+ else
750+ return (((b.y + b.height) - (a.y + a.height)) + 5);
751+ }
752+
753+ // Return the number of pixels over the edge we are extending.
754+ // If we are over the edge the ToolTipManager can adjust.
755+ // REMIND: what if the Tooltip is just too big to fit at all - we currently will just clip
756+ private int getWidthAdjust(Rectangle a, Rectangle b){
757+ // System.out.println("width b.x/b.width: " + b.x + "/" + b.width +
758+ // "a.x/a.width: " + a.x + "/" + a.width);
759+ if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width)){
760+ return 0;
761+ }
762+ else {
763+ return (((b.x + b.width) - (a.x +a.width)) + 5);
764+ }
765+ }
766+
767+
768+ //
769+ // Actions
770+ //
771+ private void show(JComponent source) {
772+ if (tipWindow != null) { // showing we unshow
773+ hideTipWindow();
774+ insideComponent = null;
775+ }
776+ else {
777+ hideTipWindow(); // be safe
778+ enterTimer.stop();
779+ exitTimer.stop();
780+ insideTimer.stop();
781+ insideComponent = source;
782+ if (insideComponent != null){
783+ toolTipText = insideComponent.getToolTipText();
784+ preferredLocation = new Point(10,insideComponent.getHeight()+
785+ 10); // manual set
786+ showTipWindow();
787+ // put a focuschange listener on to bring the tip down
788+ if (focusChangeListener == null){
789+ focusChangeListener = createFocusChangeListener();
790+ }
791+ insideComponent.addFocusListener(focusChangeListener);
792+ }
793+ }
794+ }
795+
796+ private void hide(JComponent source) {
797+ hideTipWindow();
798+ source.removeFocusListener(focusChangeListener);
799+ preferredLocation = null;
800+ insideComponent = null;
801+ }
802+
803+ /* This listener is registered when the tooltip is first registered
804+ * on a component in order to process accessibility keybindings.
805+ * This will apply globally across L&F
806+ *
807+ * Post Tip: Ctrl+F1
808+ * Unpost Tip: Esc and Ctrl+F1
809+ */
810+ private class AccessibilityKeyListener extends KeyAdapter {
811+ public void keyPressed(KeyEvent e) {
812+ if (!e.isConsumed()) {
813+ JComponent source = (JComponent) e.getComponent();
814+ KeyStroke keyStrokeForEvent = KeyStroke.getKeyStrokeForEvent(e);
815+ if (hideTip.equals(keyStrokeForEvent)) {
816+ if (tipWindow != null) {
817+ hide(source);
818+ e.consume();
819+ }
820+ } else if (postTip.equals(keyStrokeForEvent)) {
821+ // Shown tooltip will be hidden
822+ ToolTipManager.this.show(source);
823+ e.consume();
824+ }
825+ }
826+ }
827+ }
828+}