LCOV - code coverage report
Current view: directory - layout/xul/base/src - nsXULTooltipListener.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 326 0 0.0 %
Date: 2012-06-02 Functions: 23 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsXULTooltipListener.h"
      39                 : 
      40                 : #include "nsIDOMMouseEvent.h"
      41                 : #include "nsIDOMEventTarget.h"
      42                 : #include "nsIDOMDocument.h"
      43                 : #include "nsIDOMXULDocument.h"
      44                 : #include "nsIDOMXULElement.h"
      45                 : #include "nsIDocument.h"
      46                 : #include "nsGkAtoms.h"
      47                 : #include "nsIFrame.h"
      48                 : #include "nsIPopupBoxObject.h"
      49                 : #include "nsMenuPopupFrame.h"
      50                 : #include "nsIServiceManager.h"
      51                 : #include "nsIDragService.h"
      52                 : #include "nsIDragSession.h"
      53                 : #ifdef MOZ_XUL
      54                 : #include "nsITreeView.h"
      55                 : #endif
      56                 : #include "nsGUIEvent.h"
      57                 : #include "nsIPrivateDOMEvent.h"
      58                 : #include "nsIScriptContext.h"
      59                 : #include "nsPIDOMWindow.h"
      60                 : #ifdef MOZ_XUL
      61                 : #include "nsXULPopupManager.h"
      62                 : #endif
      63                 : #include "nsIRootBox.h"
      64                 : #include "nsEventDispatcher.h"
      65                 : #include "mozilla/Preferences.h"
      66                 : #include "mozilla/LookAndFeel.h"
      67                 : #include "mozilla/dom/Element.h"
      68                 : 
      69                 : 
      70                 : using namespace mozilla;
      71                 : 
      72                 : nsXULTooltipListener* nsXULTooltipListener::mInstance = nsnull;
      73                 : 
      74                 : //////////////////////////////////////////////////////////////////////////
      75                 : //// nsISupports
      76                 : 
      77               0 : nsXULTooltipListener::nsXULTooltipListener()
      78                 :   : mMouseScreenX(0)
      79                 :   , mMouseScreenY(0)
      80                 :   , mTooltipShownOnce(false)
      81                 : #ifdef MOZ_XUL
      82                 :   , mIsSourceTree(false)
      83                 :   , mNeedTitletip(false)
      84               0 :   , mLastTreeRow(-1)
      85                 : #endif
      86                 : {
      87               0 :   if (sTooltipListenerCount++ == 0) {
      88                 :     // register the callback so we get notified of updates
      89                 :     Preferences::RegisterCallback(ToolbarTipsPrefChanged,
      90               0 :                                   "browser.chrome.toolbar_tips");
      91                 : 
      92                 :     // Call the pref callback to initialize our state.
      93               0 :     ToolbarTipsPrefChanged("browser.chrome.toolbar_tips", nsnull);
      94                 :   }
      95               0 : }
      96                 : 
      97               0 : nsXULTooltipListener::~nsXULTooltipListener()
      98                 : {
      99               0 :   if (nsXULTooltipListener::mInstance == this) {
     100               0 :     ClearTooltipCache();
     101                 :   }
     102               0 :   HideTooltip();
     103                 : 
     104               0 :   if (--sTooltipListenerCount == 0) {
     105                 :     // Unregister our pref observer
     106                 :     Preferences::UnregisterCallback(ToolbarTipsPrefChanged,
     107               0 :                                     "browser.chrome.toolbar_tips");
     108                 :   }
     109               0 : }
     110                 : 
     111               0 : NS_IMPL_ISUPPORTS1(nsXULTooltipListener, nsIDOMEventListener)
     112                 : 
     113                 : void
     114               0 : nsXULTooltipListener::MouseOut(nsIDOMEvent* aEvent)
     115                 : {
     116                 :   // reset flag so that tooltip will display on the next MouseMove
     117               0 :   mTooltipShownOnce = false;
     118                 : 
     119                 :   // if the timer is running and no tooltip is shown, we
     120                 :   // have to cancel the timer here so that it doesn't 
     121                 :   // show the tooltip if we move the mouse out of the window
     122               0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     123               0 :   if (mTooltipTimer && !currentTooltip) {
     124               0 :     mTooltipTimer->Cancel();
     125               0 :     mTooltipTimer = nsnull;
     126                 :     return;
     127                 :   }
     128                 : 
     129                 : #ifdef DEBUG_crap
     130                 :   if (mNeedTitletip)
     131                 :     return;
     132                 : #endif
     133                 : 
     134                 : #ifdef MOZ_XUL
     135                 :   // check to see if the mouse left the targetNode, and if so,
     136                 :   // hide the tooltip
     137               0 :   if (currentTooltip) {
     138                 :     // which node did the mouse leave?
     139               0 :     nsCOMPtr<nsIDOMEventTarget> eventTarget;
     140               0 :     aEvent->GetTarget(getter_AddRefs(eventTarget));
     141               0 :     nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(eventTarget));
     142                 : 
     143               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     144               0 :     if (pm) {
     145                 :       nsCOMPtr<nsIDOMNode> tooltipNode =
     146               0 :         pm->GetLastTriggerTooltipNode(currentTooltip->GetCurrentDoc());
     147               0 :       if (tooltipNode == targetNode) {
     148                 :         // if the target node is the current tooltip target node, the mouse
     149                 :         // left the node the tooltip appeared on, so close the tooltip.
     150               0 :         HideTooltip();
     151                 :         // reset special tree tracking
     152               0 :         if (mIsSourceTree) {
     153               0 :           mLastTreeRow = -1;
     154               0 :           mLastTreeCol = nsnull;
     155                 :         }
     156                 :       }
     157                 :     }
     158                 :   }
     159                 : #endif
     160                 : }
     161                 : 
     162                 : void
     163               0 : nsXULTooltipListener::MouseMove(nsIDOMEvent* aEvent)
     164                 : {
     165               0 :   if (!sShowTooltips)
     166               0 :     return;
     167                 : 
     168                 :   // stash the coordinates of the event so that we can still get back to it from within the 
     169                 :   // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
     170                 :   // even when the mouse doesn't change position! To get around this, we make sure the
     171                 :   // mouse has really moved before proceeding.
     172               0 :   nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aEvent));
     173               0 :   if (!mouseEvent)
     174                 :     return;
     175                 :   PRInt32 newMouseX, newMouseY;
     176               0 :   mouseEvent->GetScreenX(&newMouseX);
     177               0 :   mouseEvent->GetScreenY(&newMouseY);
     178                 : 
     179                 :   // filter out false win32 MouseMove event
     180               0 :   if (mMouseScreenX == newMouseX && mMouseScreenY == newMouseY)
     181                 :     return;
     182                 : 
     183                 :   // filter out minor movements due to crappy optical mice and shaky hands
     184                 :   // to prevent tooltips from hiding prematurely.
     185               0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     186                 : 
     187               0 :   if ((currentTooltip) &&
     188               0 :       (abs(mMouseScreenX - newMouseX) <= kTooltipMouseMoveTolerance) &&
     189               0 :       (abs(mMouseScreenY - newMouseY) <= kTooltipMouseMoveTolerance))
     190                 :     return;
     191               0 :   mMouseScreenX = newMouseX;
     192               0 :   mMouseScreenY = newMouseY;
     193                 : 
     194               0 :   nsCOMPtr<nsIDOMEventTarget> currentTarget;
     195               0 :   aEvent->GetCurrentTarget(getter_AddRefs(currentTarget));
     196                 : 
     197               0 :   nsCOMPtr<nsIContent> sourceContent = do_QueryInterface(currentTarget);
     198               0 :   mSourceNode = do_GetWeakReference(sourceContent);
     199                 : #ifdef MOZ_XUL
     200               0 :   mIsSourceTree = sourceContent->Tag() == nsGkAtoms::treechildren;
     201               0 :   if (mIsSourceTree)
     202               0 :     CheckTreeBodyMove(mouseEvent);
     203                 : #endif
     204                 : 
     205                 :   // as the mouse moves, we want to make sure we reset the timer to show it, 
     206                 :   // so that the delay is from when the mouse stops moving, not when it enters
     207                 :   // the node.
     208               0 :   KillTooltipTimer();
     209                 : 
     210                 :   // If the mouse moves while the tooltip is up, hide it. If nothing is
     211                 :   // showing and the tooltip hasn't been displayed since the mouse entered
     212                 :   // the node, then start the timer to show the tooltip.
     213               0 :   if (!currentTooltip && !mTooltipShownOnce) {
     214               0 :     nsCOMPtr<nsIDOMEventTarget> eventTarget;
     215               0 :     aEvent->GetTarget(getter_AddRefs(eventTarget));
     216                 : 
     217                 :     // don't show tooltips attached to elements outside of a menu popup
     218                 :     // when hovering over an element inside it. The popupsinherittooltip
     219                 :     // attribute may be used to disable this behaviour, which is useful for
     220                 :     // large menu hierarchies such as bookmarks.
     221               0 :     if (!sourceContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::popupsinherittooltip,
     222               0 :                                     nsGkAtoms::_true, eCaseMatters)) {
     223               0 :       nsCOMPtr<nsIContent> targetContent = do_QueryInterface(eventTarget);
     224               0 :       while (targetContent && targetContent != sourceContent) {
     225               0 :         nsIAtom* tag = targetContent->Tag();
     226               0 :         if (targetContent->GetNameSpaceID() == kNameSpaceID_XUL &&
     227                 :             (tag == nsGkAtoms::menupopup ||
     228                 :              tag == nsGkAtoms::panel ||
     229                 :              tag == nsGkAtoms::tooltip)) {
     230               0 :           mSourceNode = nsnull;
     231                 :           return;
     232                 :         }
     233                 : 
     234               0 :         targetContent = targetContent->GetParent();
     235                 :       }
     236                 :     }
     237                 : 
     238               0 :     mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
     239               0 :     if (mTooltipTimer) {
     240               0 :       mTargetNode = do_GetWeakReference(eventTarget);
     241               0 :       if (mTargetNode) {
     242                 :         nsresult rv =
     243               0 :           mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
     244               0 :             LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
     245               0 :             nsITimer::TYPE_ONE_SHOT);
     246               0 :         if (NS_FAILED(rv)) {
     247               0 :           mTargetNode = nsnull;
     248               0 :           mSourceNode = nsnull;
     249                 :         }
     250                 :       }
     251                 :     }
     252                 :     return;
     253                 :   }
     254                 : 
     255                 : #ifdef MOZ_XUL
     256               0 :   if (mIsSourceTree)
     257                 :     return;
     258                 : #endif
     259                 : 
     260               0 :   HideTooltip();
     261                 :   // set a flag so that the tooltip is only displayed once until the mouse
     262                 :   // leaves the node
     263               0 :   mTooltipShownOnce = true;
     264                 : }
     265                 : 
     266                 : NS_IMETHODIMP
     267               0 : nsXULTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
     268                 : {
     269               0 :   nsAutoString type;
     270               0 :   aEvent->GetType(type);
     271               0 :   if (type.EqualsLiteral("DOMMouseScroll") ||
     272               0 :       type.EqualsLiteral("keydown") ||
     273               0 :       type.EqualsLiteral("mousedown") ||
     274               0 :       type.EqualsLiteral("mouseup") ||
     275               0 :       type.EqualsLiteral("dragstart")) {
     276               0 :     HideTooltip();
     277               0 :     return NS_OK;
     278                 :   }
     279                 : 
     280               0 :   if (type.EqualsLiteral("popuphiding")) {
     281               0 :     DestroyTooltip();
     282               0 :     return NS_OK;
     283                 :   }
     284                 : 
     285                 :   // Note that mousemove, mouseover and mouseout might be
     286                 :   // fired even during dragging due to widget's bug.
     287                 :   nsCOMPtr<nsIDragService> dragService =
     288               0 :     do_GetService("@mozilla.org/widget/dragservice;1");
     289               0 :   NS_ENSURE_TRUE(dragService, NS_OK);
     290               0 :   nsCOMPtr<nsIDragSession> dragSession;
     291               0 :   dragService->GetCurrentSession(getter_AddRefs(dragSession));
     292               0 :   if (dragSession) {
     293               0 :     return NS_OK;
     294                 :   }
     295                 : 
     296                 :   // Not dragging.
     297                 : 
     298               0 :   if (type.EqualsLiteral("mousemove")) {
     299               0 :     MouseMove(aEvent);
     300               0 :     return NS_OK;
     301                 :   }
     302                 : 
     303               0 :   if (type.EqualsLiteral("mouseout")) {
     304               0 :     MouseOut(aEvent);
     305               0 :     return NS_OK;
     306                 :   }
     307                 : 
     308               0 :   return NS_OK;
     309                 : }
     310                 : 
     311                 : //////////////////////////////////////////////////////////////////////////
     312                 : //// nsXULTooltipListener
     313                 : 
     314                 : // static
     315                 : int
     316               0 : nsXULTooltipListener::ToolbarTipsPrefChanged(const char *aPref,
     317                 :                                              void *aClosure)
     318                 : {
     319                 :   sShowTooltips =
     320               0 :     Preferences::GetBool("browser.chrome.toolbar_tips", sShowTooltips);
     321                 : 
     322               0 :   return 0;
     323                 : }
     324                 : 
     325                 : //////////////////////////////////////////////////////////////////////////
     326                 : //// nsXULTooltipListener
     327                 : 
     328                 : bool nsXULTooltipListener::sShowTooltips = false;
     329                 : PRUint32 nsXULTooltipListener::sTooltipListenerCount = 0;
     330                 : 
     331                 : nsresult
     332               0 : nsXULTooltipListener::AddTooltipSupport(nsIContent* aNode)
     333                 : {
     334               0 :   if (!aNode)
     335               0 :     return NS_ERROR_NULL_POINTER;
     336                 : 
     337               0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mouseout"), this,
     338               0 :                                 false, false);
     339               0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mousemove"), this,
     340               0 :                                 false, false);
     341               0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("dragstart"), this,
     342               0 :                                 true, false);
     343                 : 
     344               0 :   return NS_OK;
     345                 : }
     346                 : 
     347                 : nsresult
     348               0 : nsXULTooltipListener::RemoveTooltipSupport(nsIContent* aNode)
     349                 : {
     350               0 :   if (!aNode)
     351               0 :     return NS_ERROR_NULL_POINTER;
     352                 : 
     353               0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mouseout"), this, false);
     354               0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mousemove"), this, false);
     355               0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("dragstart"), this, true);
     356                 : 
     357               0 :   return NS_OK;
     358                 : }
     359                 : 
     360                 : #ifdef MOZ_XUL
     361                 : void
     362               0 : nsXULTooltipListener::CheckTreeBodyMove(nsIDOMMouseEvent* aMouseEvent)
     363                 : {
     364               0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     365               0 :   if (!sourceNode)
     366                 :     return;
     367                 : 
     368                 :   // get the boxObject of the documentElement of the document the tree is in
     369               0 :   nsCOMPtr<nsIBoxObject> bx;
     370               0 :   nsIDocument* doc = sourceNode->GetDocument();
     371               0 :   if (doc) {
     372               0 :     nsCOMPtr<nsIDOMElement> docElement = do_QueryInterface(doc->GetRootElement());
     373               0 :     if (docElement) {
     374               0 :       doc->GetBoxObjectFor(docElement, getter_AddRefs(bx));
     375                 :     }
     376                 :   }
     377                 : 
     378               0 :   nsCOMPtr<nsITreeBoxObject> obx;
     379               0 :   GetSourceTreeBoxObject(getter_AddRefs(obx));
     380               0 :   if (bx && obx) {
     381                 :     PRInt32 x, y;
     382               0 :     aMouseEvent->GetScreenX(&x);
     383               0 :     aMouseEvent->GetScreenY(&y);
     384                 : 
     385                 :     PRInt32 row;
     386               0 :     nsCOMPtr<nsITreeColumn> col;
     387               0 :     nsCAutoString obj;
     388                 : 
     389                 :     // subtract off the documentElement's boxObject
     390                 :     PRInt32 boxX, boxY;
     391               0 :     bx->GetScreenX(&boxX);
     392               0 :     bx->GetScreenY(&boxY);
     393               0 :     x -= boxX;
     394               0 :     y -= boxY;
     395                 : 
     396               0 :     obx->GetCellAt(x, y, &row, getter_AddRefs(col), obj);
     397                 : 
     398                 :     // determine if we are going to need a titletip
     399                 :     // XXX check the disabletitletips attribute on the tree content
     400               0 :     mNeedTitletip = false;
     401               0 :     if (row >= 0 && obj.EqualsLiteral("text")) {
     402               0 :       obx->IsCellCropped(row, col, &mNeedTitletip);
     403                 :     }
     404                 : 
     405               0 :     nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     406               0 :     if (currentTooltip && (row != mLastTreeRow || col != mLastTreeCol)) {
     407               0 :       HideTooltip();
     408                 :     } 
     409                 : 
     410               0 :     mLastTreeRow = row;
     411               0 :     mLastTreeCol = col;
     412                 :   }
     413                 : }
     414                 : #endif
     415                 : 
     416                 : nsresult
     417               0 : nsXULTooltipListener::ShowTooltip()
     418                 : {
     419               0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     420                 : 
     421                 :   // get the tooltip content designated for the target node
     422               0 :   nsCOMPtr<nsIContent> tooltipNode;
     423               0 :   GetTooltipFor(sourceNode, getter_AddRefs(tooltipNode));
     424               0 :   if (!tooltipNode || sourceNode == tooltipNode)
     425               0 :     return NS_ERROR_FAILURE; // the target node doesn't need a tooltip
     426                 : 
     427                 :   // set the node in the document that triggered the tooltip and show it
     428               0 :   nsCOMPtr<nsIDOMXULDocument> xulDoc(do_QueryInterface(tooltipNode->GetDocument()));
     429               0 :   if (xulDoc) {
     430                 :     // Make sure the target node is still attached to some document. 
     431                 :     // It might have been deleted.
     432               0 :     if (sourceNode->GetDocument()) {
     433                 : #ifdef MOZ_XUL
     434               0 :       if (!mIsSourceTree) {
     435               0 :         mLastTreeRow = -1;
     436               0 :         mLastTreeCol = nsnull;
     437                 :       }
     438                 : #endif
     439                 : 
     440               0 :       mCurrentTooltip = do_GetWeakReference(tooltipNode);
     441               0 :       LaunchTooltip();
     442               0 :       mTargetNode = nsnull;
     443                 : 
     444               0 :       nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     445               0 :       if (!currentTooltip)
     446               0 :         return NS_OK;
     447                 : 
     448                 :       // listen for popuphidden on the tooltip node, so that we can
     449                 :       // be sure DestroyPopup is called even if someone else closes the tooltip
     450               0 :       currentTooltip->AddSystemEventListener(NS_LITERAL_STRING("popuphiding"), 
     451               0 :                                              this, false, false);
     452                 : 
     453                 :       // listen for mousedown, mouseup, keydown, and DOMMouseScroll events at document level
     454               0 :       nsIDocument* doc = sourceNode->GetDocument();
     455               0 :       if (doc) {
     456                 :         // Probably, we should listen to untrusted events for hiding tooltips
     457                 :         // on content since tooltips might disturb something of web
     458                 :         // applications.  If we don't specify the aWantsUntrusted of
     459                 :         // AddSystemEventListener(), the event target sets it to TRUE if the
     460                 :         // target is in content.
     461               0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("DOMMouseScroll"),
     462               0 :                                     this, true);
     463               0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("mousedown"),
     464               0 :                                     this, true);
     465               0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("mouseup"),
     466               0 :                                     this, true);
     467               0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("keydown"),
     468               0 :                                     this, true);
     469                 :       }
     470               0 :       mSourceNode = nsnull;
     471                 :     }
     472                 :   }
     473                 : 
     474               0 :   return NS_OK;
     475                 : }
     476                 : 
     477                 : #ifdef MOZ_XUL
     478                 : // XXX: "This stuff inside DEBUG_crap could be used to make tree tooltips work
     479                 : //       in the future."
     480                 : #ifdef DEBUG_crap
     481                 : static void
     482                 : GetTreeCellCoords(nsITreeBoxObject* aTreeBox, nsIContent* aSourceNode, 
     483                 :                   PRInt32 aRow, nsITreeColumn* aCol, PRInt32* aX, PRInt32* aY)
     484                 : {
     485                 :   PRInt32 junk;
     486                 :   aTreeBox->GetCoordsForCellItem(aRow, aCol, EmptyCString(), aX, aY, &junk, &junk);
     487                 :   nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aSourceNode));
     488                 :   nsCOMPtr<nsIBoxObject> bx;
     489                 :   xulEl->GetBoxObject(getter_AddRefs(bx));
     490                 :   PRInt32 myX, myY;
     491                 :   bx->GetX(&myX);
     492                 :   bx->GetY(&myY);
     493                 :   *aX += myX;
     494                 :   *aY += myY;
     495                 : }
     496                 : #endif
     497                 : 
     498                 : static void
     499               0 : SetTitletipLabel(nsITreeBoxObject* aTreeBox, nsIContent* aTooltip,
     500                 :                  PRInt32 aRow, nsITreeColumn* aCol)
     501                 : {
     502               0 :   nsCOMPtr<nsITreeView> view;
     503               0 :   aTreeBox->GetView(getter_AddRefs(view));
     504               0 :   if (view) {
     505               0 :     nsAutoString label;
     506                 : #ifdef DEBUG
     507                 :     nsresult rv = 
     508                 : #endif
     509               0 :       view->GetCellText(aRow, aCol, label);
     510               0 :     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't get the cell text!");
     511               0 :     aTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, true);
     512                 :   }
     513               0 : }
     514                 : #endif
     515                 : 
     516                 : void
     517               0 : nsXULTooltipListener::LaunchTooltip()
     518                 : {
     519               0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     520               0 :   if (!currentTooltip)
     521                 :     return;
     522                 : 
     523                 : #ifdef MOZ_XUL
     524               0 :   if (mIsSourceTree && mNeedTitletip) {
     525               0 :     nsCOMPtr<nsITreeBoxObject> obx;
     526               0 :     GetSourceTreeBoxObject(getter_AddRefs(obx));
     527                 : 
     528               0 :     SetTitletipLabel(obx, currentTooltip, mLastTreeRow, mLastTreeCol);
     529               0 :     if (!(currentTooltip = do_QueryReferent(mCurrentTooltip))) {
     530                 :       // Because of mutation events, currentTooltip can be null.
     531                 :       return;
     532                 :     }
     533               0 :     currentTooltip->SetAttr(nsnull, nsGkAtoms::titletip, NS_LITERAL_STRING("true"), true);
     534                 :   } else {
     535               0 :     currentTooltip->UnsetAttr(nsnull, nsGkAtoms::titletip, true);
     536                 :   }
     537               0 :   if (!(currentTooltip = do_QueryReferent(mCurrentTooltip))) {
     538                 :     // Because of mutation events, currentTooltip can be null.
     539                 :     return;
     540                 :   }
     541                 : 
     542               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     543               0 :   if (pm) {
     544               0 :     nsCOMPtr<nsIContent> target = do_QueryReferent(mTargetNode);
     545               0 :     pm->ShowTooltipAtScreen(currentTooltip, target, mMouseScreenX, mMouseScreenY);
     546                 : 
     547                 :     // Clear the current tooltip if the popup was not opened successfully.
     548               0 :     if (!pm->IsPopupOpen(currentTooltip))
     549               0 :       mCurrentTooltip = nsnull;
     550                 :   }
     551                 : #endif
     552                 : 
     553                 : }
     554                 : 
     555                 : nsresult
     556               0 : nsXULTooltipListener::HideTooltip()
     557                 : {
     558                 : #ifdef MOZ_XUL
     559               0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     560               0 :   if (currentTooltip) {
     561               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     562               0 :     if (pm)
     563               0 :       pm->HidePopup(currentTooltip, false, false, false);
     564                 :   }
     565                 : #endif
     566                 : 
     567               0 :   DestroyTooltip();
     568               0 :   return NS_OK;
     569                 : }
     570                 : 
     571                 : static void
     572               0 : GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult) 
     573                 : {
     574               0 :   *aResult = nsnull;
     575               0 :   PRUint32 childCount = aContent->GetChildCount();
     576               0 :   for (PRUint32 i = 0; i < childCount; i++) {
     577               0 :     nsIContent *child = aContent->GetChildAt(i);
     578                 : 
     579               0 :     if (child->Tag() == aTag) {
     580               0 :       *aResult = child;
     581               0 :       NS_ADDREF(*aResult);
     582               0 :       return;
     583                 :     }
     584                 :   }
     585                 : 
     586               0 :   return;
     587                 : }
     588                 : 
     589                 : nsresult
     590               0 : nsXULTooltipListener::FindTooltip(nsIContent* aTarget, nsIContent** aTooltip)
     591                 : {
     592               0 :   if (!aTarget)
     593               0 :     return NS_ERROR_NULL_POINTER;
     594                 : 
     595                 :   // before we go on, make sure that target node still has a window
     596               0 :   nsIDocument *document = aTarget->GetDocument();
     597               0 :   if (!document) {
     598               0 :     NS_WARNING("Unable to retrieve the tooltip node document.");
     599               0 :     return NS_ERROR_FAILURE;
     600                 :   }
     601               0 :   nsPIDOMWindow *window = document->GetWindow();
     602               0 :   if (!window) {
     603               0 :     return NS_OK;
     604                 :   }
     605                 : 
     606                 :   bool closed;
     607               0 :   window->GetClosed(&closed);
     608                 : 
     609               0 :   if (closed) {
     610               0 :     return NS_OK;
     611                 :   }
     612                 : 
     613               0 :   nsAutoString tooltipText;
     614               0 :   aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, tooltipText);
     615               0 :   if (!tooltipText.IsEmpty()) {
     616                 :     // specifying tooltiptext means we will always use the default tooltip
     617               0 :     nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetShell());
     618               0 :     NS_ENSURE_STATE(rootBox);
     619               0 :     *aTooltip = rootBox->GetDefaultTooltip();
     620               0 :     if (*aTooltip) {
     621               0 :       NS_ADDREF(*aTooltip);
     622               0 :       (*aTooltip)->SetAttr(kNameSpaceID_None, nsGkAtoms::label, tooltipText, true);
     623                 :     }
     624               0 :     return NS_OK;
     625                 :   }
     626                 : 
     627               0 :   nsAutoString tooltipId;
     628               0 :   aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltip, tooltipId);
     629                 : 
     630                 :   // if tooltip == _child, look for first <tooltip> child
     631               0 :   if (tooltipId.EqualsLiteral("_child")) {
     632               0 :     GetImmediateChild(aTarget, nsGkAtoms::tooltip, aTooltip);
     633               0 :     return NS_OK;
     634                 :   }
     635                 : 
     636               0 :   if (!tooltipId.IsEmpty()) {
     637                 :     // tooltip must be an id, use getElementById to find it
     638               0 :     nsCOMPtr<nsIContent> tooltipEl = document->GetElementById(tooltipId);
     639                 : 
     640               0 :     if (tooltipEl) {
     641                 : #ifdef MOZ_XUL
     642               0 :       mNeedTitletip = false;
     643                 : #endif
     644               0 :       tooltipEl.forget(aTooltip);
     645               0 :       return NS_OK;
     646                 :     }
     647                 :   }
     648                 : 
     649                 : #ifdef MOZ_XUL
     650                 :   // titletips should just use the default tooltip
     651               0 :   if (mIsSourceTree && mNeedTitletip) {
     652               0 :     nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetShell());
     653               0 :     NS_ENSURE_STATE(rootBox);
     654               0 :     NS_IF_ADDREF(*aTooltip = rootBox->GetDefaultTooltip());
     655                 :   }
     656                 : #endif
     657                 : 
     658               0 :   return NS_OK;
     659                 : }
     660                 : 
     661                 : 
     662                 : nsresult
     663               0 : nsXULTooltipListener::GetTooltipFor(nsIContent* aTarget, nsIContent** aTooltip)
     664                 : {
     665               0 :   *aTooltip = nsnull;
     666               0 :   nsCOMPtr<nsIContent> tooltip;
     667               0 :   nsresult rv = FindTooltip(aTarget, getter_AddRefs(tooltip));
     668               0 :   if (NS_FAILED(rv) || !tooltip) {
     669               0 :     return rv;
     670                 :   }
     671                 : 
     672                 :   // Submenus can't be used as tooltips, see bug 288763.
     673               0 :   nsIContent* parent = tooltip->GetParent();
     674               0 :   if (parent) {
     675               0 :     nsIFrame* frame = parent->GetPrimaryFrame();
     676               0 :     if (frame && frame->GetType() == nsGkAtoms::menuFrame) {
     677               0 :       NS_WARNING("Menu cannot be used as a tooltip");
     678               0 :       return NS_ERROR_FAILURE;
     679                 :     }
     680                 :   }
     681                 : 
     682               0 :   tooltip.swap(*aTooltip);
     683               0 :   return rv;
     684                 : }
     685                 : 
     686                 : nsresult
     687               0 : nsXULTooltipListener::DestroyTooltip()
     688                 : {
     689               0 :   nsCOMPtr<nsIDOMEventListener> kungFuDeathGrip(this);
     690               0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     691               0 :   if (currentTooltip) {
     692                 :     // clear out the tooltip node on the document
     693               0 :     nsCOMPtr<nsIDocument> doc = currentTooltip->GetDocument();
     694               0 :     if (doc) {
     695                 :       // remove the mousedown and keydown listener from document
     696               0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("DOMMouseScroll"), this,
     697               0 :                                      true);
     698               0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), this,
     699               0 :                                      true);
     700               0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     701               0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), this, true);
     702                 :     }
     703                 : 
     704                 :     // remove the popuphidden listener from tooltip
     705               0 :     nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(currentTooltip));
     706                 : 
     707                 :     // release tooltip before removing listener to prevent our destructor from
     708                 :     // being called recursively (bug 120863)
     709               0 :     mCurrentTooltip = nsnull;
     710                 : 
     711               0 :     evtTarget->RemoveEventListener(NS_LITERAL_STRING("popuphiding"), this, false);
     712                 :   }
     713                 :   
     714                 :   // kill any ongoing timers
     715               0 :   KillTooltipTimer();
     716               0 :   mSourceNode = nsnull;
     717                 : #ifdef MOZ_XUL
     718               0 :   mLastTreeCol = nsnull;
     719                 : #endif
     720                 : 
     721               0 :   return NS_OK;
     722                 : }
     723                 : 
     724                 : void
     725               0 : nsXULTooltipListener::KillTooltipTimer()
     726                 : {
     727               0 :   if (mTooltipTimer) {
     728               0 :     mTooltipTimer->Cancel();
     729               0 :     mTooltipTimer = nsnull;
     730               0 :     mTargetNode = nsnull;
     731                 :   }
     732               0 : }
     733                 : 
     734                 : void
     735               0 : nsXULTooltipListener::sTooltipCallback(nsITimer *aTimer, void *aListener)
     736                 : {
     737               0 :   nsRefPtr<nsXULTooltipListener> instance = mInstance;
     738               0 :   if (instance)
     739               0 :     instance->ShowTooltip();
     740               0 : }
     741                 : 
     742                 : #ifdef MOZ_XUL
     743                 : nsresult
     744               0 : nsXULTooltipListener::GetSourceTreeBoxObject(nsITreeBoxObject** aBoxObject)
     745                 : {
     746               0 :   *aBoxObject = nsnull;
     747                 : 
     748               0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     749               0 :   if (mIsSourceTree && sourceNode) {
     750               0 :     nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(sourceNode->GetParent()));
     751               0 :     if (xulEl) {
     752               0 :       nsCOMPtr<nsIBoxObject> bx;
     753               0 :       xulEl->GetBoxObject(getter_AddRefs(bx));
     754               0 :       nsCOMPtr<nsITreeBoxObject> obx(do_QueryInterface(bx));
     755               0 :       if (obx) {
     756               0 :         *aBoxObject = obx;
     757               0 :         NS_ADDREF(*aBoxObject);
     758               0 :         return NS_OK;
     759                 :       }
     760                 :     }
     761                 :   }
     762               0 :   return NS_ERROR_FAILURE;
     763                 : }
     764                 : #endif

Generated by: LCOV version 1.7