/* void scrollToElement (in nsIDOMElement child); */
NS_IMETHODIMP nsScrollBoxObject::ScrollToElement(nsIDOMElement *child)
{
    NS_ENSURE_ARG_POINTER(child);
    nsIScrollableView* scrollableView = GetScrollableView();
    if (!scrollableView)
       return NS_ERROR_FAILURE;

    nsCOMPtr<nsIPresShell> shell = GetPresShell(PR_FALSE);
    if (!shell) {
      return NS_ERROR_UNEXPECTED;
    }

    nsIFrame* scrolledBox = GetScrolledBox(this);
    if (!scrolledBox)
       return NS_ERROR_FAILURE;

    nsRect rect, crect;
    nsCOMPtr<nsIDOMDocument> doc;
    child->GetOwnerDocument(getter_AddRefs(doc));
    nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
    if(!nsDoc)
      return NS_ERROR_UNEXPECTED;

    nsCOMPtr<nsIBoxObject> childBoxObject;
    nsDoc->GetBoxObjectFor(child, getter_AddRefs(childBoxObject));
    if(!childBoxObject)
      return NS_ERROR_UNEXPECTED;

    PRInt32 x,y;
    childBoxObject->GetX(&x);
    childBoxObject->GetY(&y);
    // get the twips rectangle from the boxobject (which has pixels)    
    rect.x = nsPresContext::CSSPixelsToAppUnits(x);
    rect.y = nsPresContext::CSSPixelsToAppUnits(y);

    // TODO: make sure the child is inside the box

    // get our current info
    nsPoint cp;
    scrollableView->GetScrollPosition(cp.x,cp.y);

    nsIntRect prect;
    GetOffsetRect(prect);
    crect = nsIntRect::ToAppUnits(prect, nsPresContext::AppUnitsPerCSSPixel());
    nscoord newx=cp.x, newy=cp.y;

    // we only scroll in the direction of the scrollbox orientation
    // always scroll to left or top edge of child element
    if (scrolledBox->IsHorizontal()) {
        newx = rect.x - crect.x;
    } else {
        newy = rect.y - crect.y;
    }
    // scroll away
    return scrollableView->ScrollTo(newx, newy, 0);
}
Esempio n. 2
0
void
nsXULTooltipListener::CheckTreeBodyMove(nsIDOMMouseEvent* aMouseEvent)
{
  nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
  if (!sourceNode)
    return;

  // get the boxObject of the documentElement of the document the tree is in
  nsCOMPtr<nsIBoxObject> bx;
  nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(sourceNode->GetDocument()));
  if (doc) {
    nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
    nsCOMPtr<nsIDOMElement> docElement;
    doc->GetDocumentElement(getter_AddRefs(docElement));
    if (nsDoc && docElement) {
      nsDoc->GetBoxObjectFor(docElement, getter_AddRefs(bx));
    }
  }

  nsCOMPtr<nsITreeBoxObject> obx;
  GetSourceTreeBoxObject(getter_AddRefs(obx));
  if (bx && obx) {
    PRInt32 x, y;
    aMouseEvent->GetScreenX(&x);
    aMouseEvent->GetScreenY(&y);

    PRInt32 row;
    nsCOMPtr<nsITreeColumn> col;
    nsCAutoString obj;

    // subtract off the documentElement's boxObject
    PRInt32 boxX, boxY;
    bx->GetScreenX(&boxX);
    bx->GetScreenY(&boxY);
    x -= boxX;
    y -= boxY;

    obx->GetCellAt(x, y, &row, getter_AddRefs(col), obj);

    // determine if we are going to need a titletip
    // XXX check the disabletitletips attribute on the tree content
    mNeedTitletip = PR_FALSE;
    if (row >= 0 && obj.EqualsLiteral("text")) {
      obx->IsCellCropped(row, col, &mNeedTitletip);
    }

    nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
    if (currentTooltip && (row != mLastTreeRow || col != mLastTreeCol)) {
      HideTooltip();
    } 

    mLastTreeRow = row;
    mLastTreeCol = col;
  }
}
//
// LaunchPopup
//
// Given the element on which the event was triggered and the mouse locations in
// Client and widget coordinates, popup a new window showing the appropriate 
// content.
//
// aTargetContent is the target of the mouse event aEvent that triggered the
// popup. mElement is the element that the popup menu is attached to.
// aTargetContent may be equal to mElement or it may be a descendant.
//
// This looks for an attribute on |mElement| of the appropriate popup type 
// (popup, context) and uses that attribute's value as an ID for
// the popup content in the document.
//
nsresult
nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
{
  nsresult rv = NS_OK;

  nsAutoString type(NS_LITERAL_STRING("popup"));
  if (mIsContext)
    type.AssignLiteral("context");

  nsAutoString identifier;
  mElement->GetAttribute(type, identifier);

  if (identifier.IsEmpty()) {
    if (type.EqualsLiteral("popup"))
      mElement->GetAttribute(NS_LITERAL_STRING("menu"), identifier);
    else if (type.EqualsLiteral("context"))
      mElement->GetAttribute(NS_LITERAL_STRING("contextmenu"), identifier);
    if (identifier.IsEmpty())
      return rv;
  }

  // Try to find the popup content and the document.
  nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
  nsCOMPtr<nsIDocument> document = content->GetDocument();

  // Turn the document into a DOM document so we can use getElementById
  nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document);
  if (!domDocument) {
    NS_ERROR("Popup attached to an element that isn't in XUL!");
    return NS_ERROR_FAILURE;
  }

  // Handle the _child case for popups and context menus
  nsCOMPtr<nsIDOMElement> popupElement;

  if (identifier.EqualsLiteral("_child")) {
    nsCOMPtr<nsIContent> popup;

    GetImmediateChild(content, nsGkAtoms::menupopup, getter_AddRefs(popup));
    if (popup)
      popupElement = do_QueryInterface(popup);
    else {
      nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
      nsCOMPtr<nsIDOMNodeList> list;
      nsDoc->GetAnonymousNodes(mElement, getter_AddRefs(list));
      if (list) {
        PRUint32 ctr,listLength;
        nsCOMPtr<nsIDOMNode> node;
        list->GetLength(&listLength);
        for (ctr = 0; ctr < listLength; ctr++) {
          list->Item(ctr, getter_AddRefs(node));
          nsCOMPtr<nsIContent> childContent(do_QueryInterface(node));

          if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
                                               kNameSpaceID_XUL)) {
            popupElement = do_QueryInterface(childContent);
            break;
          }
        }
      }
    }
  }
  else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
                                              getter_AddRefs(popupElement)))) {
    // Use getElementById to obtain the popup content and gracefully fail if 
    // we didn't find any popup content in the document. 
    NS_ERROR("GetElementById had some kind of spasm.");
    return rv;
  }

  // return if no popup was found or the popup is the element itself.
  if ( !popupElement || popupElement == mElement)
    return NS_OK;

  // Submenus can't be used as context menus or popups, bug 288763.
  // Similar code also in nsXULTooltipListener::GetTooltipFor.
  nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
  nsIContent* parent = popup->GetParent();
  if (parent) {
    nsIFrame* frame = parent->GetPrimaryFrame();
    if (frame && frame->GetType() == nsGkAtoms::menuFrame)
      return NS_OK;
  }

  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  if (!pm)
    return NS_OK;

  // For left-clicks, if the popup has an position attribute, or both the
  // popupanchor and popupalign attributes are used, anchor the popup to the
  // element, otherwise just open it at the screen position where the mouse
  // was clicked. Context menus always open at the mouse position.
  mPopupContent = popup;
  if (!mIsContext &&
      (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
       (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) &&
        mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)))) {
    pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0,
                  PR_FALSE, PR_TRUE, PR_FALSE, aEvent);
  }
  else {
    PRInt32 xPos = 0, yPos = 0;
    nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
    mouseEvent->GetScreenX(&xPos);
    mouseEvent->GetScreenY(&yPos);

    pm->ShowPopupAtScreen(mPopupContent, xPos, yPos, mIsContext, aEvent);
  }

  return NS_OK;
}
/* void ensureElementIsVisible (in nsIDOMElement child); */
NS_IMETHODIMP nsScrollBoxObject::EnsureElementIsVisible(nsIDOMElement *child)
{
    NS_ENSURE_ARG_POINTER(child);

    // Start with getting info about the child, since that will flush
    // layout and possibly destroy scrollable views, presshells, etc.
    nsCOMPtr<nsIDOMDocument> doc;
    // XXXbz sXBL/XBL2 issue -- which document?
    child->GetOwnerDocument(getter_AddRefs(doc));
    nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
    if(!nsDoc)
        return NS_ERROR_UNEXPECTED;

    nsCOMPtr<nsIBoxObject> childBoxObject;
    nsDoc->GetBoxObjectFor(child, getter_AddRefs(childBoxObject));
    if(!childBoxObject)
      return NS_ERROR_UNEXPECTED;

    PRInt32 x, y, width, height;
    childBoxObject->GetX(&x);
    childBoxObject->GetY(&y);
    childBoxObject->GetWidth(&width);
    childBoxObject->GetHeight(&height);

    nsIScrollableView* scrollableView = GetScrollableView();
    if (!scrollableView)
       return NS_ERROR_FAILURE;

    nsIFrame* scrolledBox = GetScrolledBox(this);
    if (!scrolledBox)
       return NS_ERROR_FAILURE;

    nsRect rect, crect;
    // get the twips rectangle from the boxobject (which has pixels)    
    rect.x = nsPresContext::CSSPixelsToAppUnits(x);
    rect.y = nsPresContext::CSSPixelsToAppUnits(y);
    rect.width = nsPresContext::CSSPixelsToAppUnits(width);
    rect.height = nsPresContext::CSSPixelsToAppUnits(height);

    // TODO: make sure the child is inside the box

    // get our current info
    nsPoint cp;
    scrollableView->GetScrollPosition(cp.x,cp.y);
    nsIntRect prect;
    GetOffsetRect(prect);
    crect = nsIntRect::ToAppUnits(prect, nsPresContext::AppUnitsPerCSSPixel());

    nscoord newx=cp.x, newy=cp.y;

    // we only scroll in the direction of the scrollbox orientation
    if (scrolledBox->IsHorizontal()) {
        if ((rect.x - crect.x) + rect.width > cp.x + crect.width) {
            newx = cp.x + (((rect.x - crect.x) + rect.width)-(cp.x + crect.width));
        } else if (rect.x - crect.x < cp.x) {
            newx = rect.x - crect.x;
        }
    } else {
        if ((rect.y - crect.y) + rect.height > cp.y + crect.height) {
            newy = cp.y + (((rect.y - crect.y) + rect.height)-(cp.y + crect.height));
        } else if (rect.y - crect.y < cp.y) {
            newy = rect.y - crect.y;
        }
    }
    
    // scroll away
    return scrollableView->ScrollTo(newx, newy, 0);
}