gecko-dev/layout/xul/tree/TreeBoxObject.cpp
Sylvestre Ledru 265e672179 Bug 1511181 - Reformat everything to the Google coding style r=ehsan a=clang-format
# ignore-this-changeset

--HG--
extra : amend_source : 4d301d3b0b8711c4692392aa76088ba7fd7d1022
2018-11-30 11:46:48 +01:00

510 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/TreeBoxObject.h"
#include "nsCOMPtr.h"
#include "nsXULElement.h"
#include "nsTreeContentView.h"
#include "nsITreeSelection.h"
#include "ChildIterator.h"
#include "nsError.h"
#include "nsTreeBodyFrame.h"
#include "mozilla/dom/TreeBoxObjectBinding.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ToJSValue.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(TreeBoxObject, BoxObject, mView)
NS_IMPL_ADDREF_INHERITED(TreeBoxObject, BoxObject)
NS_IMPL_RELEASE_INHERITED(TreeBoxObject, BoxObject)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TreeBoxObject)
NS_INTERFACE_MAP_ENTRY(nsITreeBoxObject)
NS_INTERFACE_MAP_END_INHERITING(BoxObject)
void TreeBoxObject::Clear() {
ClearCachedValues();
// Drop the view's ref to us.
if (mView) {
nsCOMPtr<nsITreeSelection> sel;
mView->GetSelection(getter_AddRefs(sel));
if (sel) sel->SetTree(nullptr);
mView->SetTree(nullptr); // Break the circular ref between the view and us.
}
mView = nullptr;
BoxObject::Clear();
}
TreeBoxObject::TreeBoxObject() : mTreeBody(nullptr) {}
TreeBoxObject::~TreeBoxObject() {}
static nsIContent* FindBodyElement(nsIContent* aParent) {
mozilla::dom::FlattenedChildIterator iter(aParent);
for (nsIContent* content = iter.GetNextChild(); content;
content = iter.GetNextChild()) {
mozilla::dom::NodeInfo* ni = content->NodeInfo();
if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
return content;
} else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
// There are nesting tree elements. Only the innermost should
// find the treechilren.
return nullptr;
} else if (content->IsElement() &&
!ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
nsIContent* result = FindBodyElement(content);
if (result) return result;
}
}
return nullptr;
}
nsTreeBodyFrame* TreeBoxObject::GetTreeBodyFrame(bool aFlushLayout) {
// Make sure our frames are up to date, and layout as needed. We
// have to do this before checking for our cached mTreeBody, since
// it might go away on style flush, and in any case if aFlushLayout
// is true we need to make sure to flush no matter what.
// XXXbz except that flushing style when we were not asked to flush
// layout here breaks things. See bug 585123.
nsIFrame* frame = nullptr;
if (aFlushLayout) {
frame = GetFrame(aFlushLayout);
if (!frame) return nullptr;
}
if (mTreeBody) {
// Have one cached already.
return mTreeBody;
}
if (!aFlushLayout) {
frame = GetFrame(aFlushLayout);
if (!frame) return nullptr;
}
// Iterate over our content model children looking for the body.
nsCOMPtr<nsIContent> content = FindBodyElement(frame->GetContent());
if (!content) return nullptr;
frame = content->GetPrimaryFrame();
if (!frame) return nullptr;
// Make sure that the treebodyframe has a pointer to |this|.
nsTreeBodyFrame* treeBody = do_QueryFrame(frame);
NS_ENSURE_TRUE(treeBody && treeBody->GetTreeBoxObject() == this, nullptr);
mTreeBody = treeBody;
return mTreeBody;
}
NS_IMETHODIMP
TreeBoxObject::GetView(nsITreeView** aView) {
if (!mTreeBody) {
if (!GetTreeBodyFrame()) {
// Don't return an uninitialised view
*aView = nullptr;
return NS_OK;
}
if (mView)
// Our new frame needs to initialise itself
return mTreeBody->GetView(aView);
}
if (!mView) {
RefPtr<nsXULElement> xulele = nsXULElement::FromNodeOrNull(mContent);
if (xulele) {
// No tree builder, create a tree content view.
nsresult rv = NS_NewTreeContentView(getter_AddRefs(mView));
NS_ENSURE_SUCCESS(rv, rv);
// Initialise the frame and view
mTreeBody->SetView(mView);
}
}
NS_IF_ADDREF(*aView = mView);
return NS_OK;
}
already_AddRefed<nsITreeView> TreeBoxObject::GetView(CallerType /* unused */) {
nsCOMPtr<nsITreeView> view;
GetView(getter_AddRefs(view));
return view.forget();
}
NS_IMETHODIMP
TreeBoxObject::SetView(nsITreeView* aView) {
ErrorResult rv;
SetView(aView, CallerType::System, rv);
return rv.StealNSResult();
}
void TreeBoxObject::SetView(nsITreeView* aView, CallerType aCallerType,
ErrorResult& aRv) {
if (aCallerType != CallerType::System) {
// Don't trust views coming from random places.
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
mView = aView;
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) body->SetView(aView);
}
bool TreeBoxObject::Focused() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->GetFocused();
return false;
}
NS_IMETHODIMP TreeBoxObject::GetFocused(bool* aFocused) {
*aFocused = Focused();
return NS_OK;
}
NS_IMETHODIMP TreeBoxObject::SetFocused(bool aFocused) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->SetFocused(aFocused);
return NS_OK;
}
NS_IMETHODIMP TreeBoxObject::GetTreeBody(Element** aElement) {
*aElement = nullptr;
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->GetTreeBody(aElement);
return NS_OK;
}
already_AddRefed<Element> TreeBoxObject::GetTreeBody() {
RefPtr<Element> el;
GetTreeBody(getter_AddRefs(el));
return el.forget();
}
already_AddRefed<nsTreeColumns> TreeBoxObject::GetColumns() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->Columns();
return nullptr;
}
NS_IMETHODIMP TreeBoxObject::GetColumns(nsTreeColumns** aColumns) {
*aColumns = GetColumns().take();
return NS_OK;
}
int32_t TreeBoxObject::RowHeight() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->RowHeight();
return 0;
}
int32_t TreeBoxObject::RowWidth() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->RowWidth();
return 0;
}
NS_IMETHODIMP TreeBoxObject::GetRowHeight(int32_t* aRowHeight) {
*aRowHeight = RowHeight();
return NS_OK;
}
NS_IMETHODIMP TreeBoxObject::GetRowWidth(int32_t* aRowWidth) {
*aRowWidth = RowWidth();
return NS_OK;
}
int32_t TreeBoxObject::GetFirstVisibleRow() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->FirstVisibleRow();
return 0;
}
NS_IMETHODIMP TreeBoxObject::GetFirstVisibleRow(int32_t* aFirstVisibleRow) {
*aFirstVisibleRow = GetFirstVisibleRow();
return NS_OK;
}
int32_t TreeBoxObject::GetLastVisibleRow() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->LastVisibleRow();
return 0;
}
NS_IMETHODIMP TreeBoxObject::GetLastVisibleRow(int32_t* aLastVisibleRow) {
*aLastVisibleRow = GetLastVisibleRow();
return NS_OK;
}
int32_t TreeBoxObject::HorizontalPosition() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->GetHorizontalPosition();
return 0;
}
int32_t TreeBoxObject::GetPageLength() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->PageLength();
return 0;
}
NS_IMETHODIMP
TreeBoxObject::EnsureRowIsVisible(int32_t aRow) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->EnsureRowIsVisible(aRow);
return NS_OK;
}
void TreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol,
ErrorResult& aRv) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) {
nsresult rv = body->EnsureCellIsVisible(aRow, aCol);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
}
void TreeBoxObject::ScrollToRow(int32_t aRow) {
nsTreeBodyFrame* body = GetTreeBodyFrame(true);
if (!body) {
return;
}
body->ScrollToRow(aRow);
}
void TreeBoxObject::ScrollByLines(int32_t aNumLines) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (!body) {
return;
}
body->ScrollByLines(aNumLines);
}
void TreeBoxObject::ScrollByPages(int32_t aNumPages) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) body->ScrollByPages(aNumPages);
}
NS_IMETHODIMP TreeBoxObject::Invalidate() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->Invalidate();
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::InvalidateColumn(nsTreeColumn* aCol) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->InvalidateColumn(aCol);
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::InvalidateRow(int32_t aIndex) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->InvalidateRow(aIndex);
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::InvalidateCell(int32_t aRow, nsTreeColumn* aCol) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->InvalidateCell(aRow, aCol);
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::InvalidateRange(int32_t aStart, int32_t aEnd) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->InvalidateRange(aStart, aEnd);
return NS_OK;
}
int32_t TreeBoxObject::GetRowAt(int32_t x, int32_t y) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (!body) {
return 0;
}
return body->GetRowAt(x, y);
}
NS_IMETHODIMP
TreeBoxObject::GetCellAt(int32_t aX, int32_t aY, int32_t* aRow,
nsTreeColumn** aCol, nsAString& aChildElt) {
*aRow = 0;
*aCol = nullptr;
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) {
nsAutoCString element;
nsresult retval = body->GetCellAt(aX, aY, aRow, aCol, element);
CopyUTF8toUTF16(element, aChildElt);
return retval;
}
return NS_OK;
}
void TreeBoxObject::GetCellAt(int32_t x, int32_t y, TreeCellInfo& aRetVal,
ErrorResult& aRv) {
GetCellAt(x, y, &aRetVal.mRow, getter_AddRefs(aRetVal.mCol),
aRetVal.mChildElt);
}
void TreeBoxObject::GetCellAt(JSContext* cx, int32_t x, int32_t y,
JS::Handle<JSObject*> rowOut,
JS::Handle<JSObject*> colOut,
JS::Handle<JSObject*> childEltOut,
ErrorResult& aRv) {
int32_t row;
RefPtr<nsTreeColumn> col;
nsAutoString childElt;
GetCellAt(x, y, &row, getter_AddRefs(col), childElt);
JS::Rooted<JS::Value> v(cx);
if (!ToJSValue(cx, row, &v) || !JS_SetProperty(cx, rowOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
if (!dom::WrapObject(cx, col, &v) ||
!JS_SetProperty(cx, colOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
if (!ToJSValue(cx, childElt, &v) ||
!JS_SetProperty(cx, childEltOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
}
NS_IMETHODIMP
TreeBoxObject::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol,
const nsAString& aElement, int32_t* aX,
int32_t* aY, int32_t* aWidth,
int32_t* aHeight) {
*aX = *aY = *aWidth = *aHeight = 0;
nsTreeBodyFrame* body = GetTreeBodyFrame();
NS_ConvertUTF16toUTF8 element(aElement);
if (body)
return body->GetCoordsForCellItem(aRow, aCol, element, aX, aY, aWidth,
aHeight);
return NS_OK;
}
already_AddRefed<DOMRect> TreeBoxObject::GetCoordsForCellItem(
int32_t row, nsTreeColumn& col, const nsAString& element,
ErrorResult& aRv) {
int32_t x, y, w, h;
GetCoordsForCellItem(row, &col, element, &x, &y, &w, &h);
RefPtr<DOMRect> rect = new DOMRect(mContent, x, y, w, h);
return rect.forget();
}
void TreeBoxObject::GetCoordsForCellItem(
JSContext* cx, int32_t row, nsTreeColumn& col, const nsAString& element,
JS::Handle<JSObject*> xOut, JS::Handle<JSObject*> yOut,
JS::Handle<JSObject*> widthOut, JS::Handle<JSObject*> heightOut,
ErrorResult& aRv) {
int32_t x, y, w, h;
GetCoordsForCellItem(row, &col, element, &x, &y, &w, &h);
JS::Rooted<JS::Value> v(cx, JS::Int32Value(x));
if (!JS_SetProperty(cx, xOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
v.setInt32(y);
if (!JS_SetProperty(cx, yOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
v.setInt32(w);
if (!JS_SetProperty(cx, widthOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
v.setInt32(h);
if (!JS_SetProperty(cx, heightOut, "value", v)) {
aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
return;
}
}
NS_IMETHODIMP
TreeBoxObject::IsCellCropped(int32_t aRow, nsTreeColumn* aCol,
bool* aIsCropped) {
*aIsCropped = false;
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->IsCellCropped(aRow, aCol, aIsCropped);
return NS_OK;
}
bool TreeBoxObject::IsCellCropped(int32_t row, nsTreeColumn* col,
ErrorResult& aRv) {
bool ret;
aRv = IsCellCropped(row, col, &ret);
return ret;
}
NS_IMETHODIMP
TreeBoxObject::RowCountChanged(int32_t aIndex, int32_t aDelta) {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->RowCountChanged(aIndex, aDelta);
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::BeginUpdateBatch() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->BeginUpdateBatch();
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::EndUpdateBatch() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->EndUpdateBatch();
return NS_OK;
}
NS_IMETHODIMP
TreeBoxObject::ClearStyleAndImageCaches() {
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) return body->ClearStyleAndImageCaches();
return NS_OK;
}
void TreeBoxObject::RemoveImageCacheEntry(int32_t aRowIndex, nsTreeColumn& aCol,
ErrorResult& aRv) {
if (NS_WARN_IF(aRowIndex < 0)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
nsTreeBodyFrame* body = GetTreeBodyFrame();
if (body) {
body->RemoveImageCacheEntry(aRowIndex, &aCol);
}
}
void TreeBoxObject::ClearCachedValues() { mTreeBody = nullptr; }
JSObject* TreeBoxObject::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return TreeBoxObject_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla