mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-17 04:37:46 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
695
layout/xul/tree/TreeBoxObject.cpp
Normal file
695
layout/xul/tree/TreeBoxObject.cpp
Normal file
|
|
@ -0,0 +1,695 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsIDOMXULElement.h"
|
||||
#include "nsIScriptableRegion.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsTreeContentView.h"
|
||||
#include "nsITreeSelection.h"
|
||||
#include "ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsTreeBodyFrame.h"
|
||||
#include "mozilla/dom/TreeBoxObjectBinding.h"
|
||||
#include "nsITreeColumns.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_INHERITED(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) {
|
||||
nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(mContent);
|
||||
if (xulele) {
|
||||
// See if there is a XUL tree builder associated with the element
|
||||
nsCOMPtr<nsIXULTemplateBuilder> builder;
|
||||
xulele->GetBuilder(getter_AddRefs(builder));
|
||||
mView = do_QueryInterface(builder);
|
||||
|
||||
if (!mView) {
|
||||
// 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() {
|
||||
nsCOMPtr<nsITreeView> view;
|
||||
GetView(getter_AddRefs(view));
|
||||
return view.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
CanTrustView(nsISupports* aValue)
|
||||
{
|
||||
// Untrusted content is only allowed to specify known-good views
|
||||
if (nsContentUtils::IsCallerChrome())
|
||||
return true;
|
||||
nsCOMPtr<nsINativeTreeView> nativeTreeView = do_QueryInterface(aValue);
|
||||
if (!nativeTreeView || NS_FAILED(nativeTreeView->EnsureNative())) {
|
||||
// XXX ERRMSG need a good error here for developers
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::SetView(nsITreeView * aView)
|
||||
{
|
||||
if (!CanTrustView(aView))
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
|
||||
mView = aView;
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
body->SetView(aView);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void TreeBoxObject::SetView(nsITreeView* aView, ErrorResult& aRv)
|
||||
{
|
||||
aRv = 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(nsIDOMElement** aElement)
|
||||
{
|
||||
*aElement = nullptr;
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->GetTreeBody(aElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
TreeBoxObject::GetTreeBody()
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> el;
|
||||
GetTreeBody(getter_AddRefs(el));
|
||||
nsCOMPtr<Element> ret(do_QueryInterface(el));
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsTreeColumns>
|
||||
TreeBoxObject::GetColumns()
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->Columns();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::GetColumns(nsITreeColumns** 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::GetHorizontalPosition(int32_t *aHorizontalPosition)
|
||||
{
|
||||
*aHorizontalPosition = HorizontalPosition();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t TreeBoxObject::GetPageLength()
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->PageLength();
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::GetPageLength(int32_t *aPageLength)
|
||||
{
|
||||
*aPageLength = GetPageLength();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::GetSelectionRegion(nsIScriptableRegion **aRegion)
|
||||
{
|
||||
*aRegion = nullptr;
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->GetSelectionRegion(aRegion);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIScriptableRegion>
|
||||
TreeBoxObject::SelectionRegion()
|
||||
{
|
||||
nsCOMPtr<nsIScriptableRegion> region;
|
||||
GetSelectionRegion(getter_AddRefs(region));
|
||||
return region.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::EnsureRowIsVisible(int32_t aRow)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->EnsureRowIsVisible(aRow);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsITreeColumn* aCol)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->EnsureCellIsVisible(aRow, aCol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollToRow(int32_t aRow)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame(true);
|
||||
if (body)
|
||||
return body->ScrollToRow(aRow);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollByLines(int32_t aNumLines)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->ScrollByLines(aNumLines);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollByPages(int32_t aNumPages)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->ScrollByPages(aNumPages);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollToCell(int32_t aRow, nsITreeColumn* aCol)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->ScrollToCell(aRow, aCol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollToColumn(nsITreeColumn* aCol)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->ScrollToColumn(aCol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::ScrollToHorizontalPosition(int32_t aHorizontalPosition)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->ScrollToHorizontalPosition(aHorizontalPosition);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TreeBoxObject::Invalidate()
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::InvalidateColumn(nsITreeColumn* 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, nsITreeColumn* 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::InvalidateColumnRange(int32_t aStart, int32_t aEnd, nsITreeColumn* aCol)
|
||||
{
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->InvalidateColumnRange(aStart, aEnd, aCol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::GetRowAt(int32_t x, int32_t y, int32_t *aRow)
|
||||
{
|
||||
*aRow = 0;
|
||||
nsTreeBodyFrame* body = GetTreeBodyFrame();
|
||||
if (body)
|
||||
return body->GetRowAt(x, y, aRow);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
TreeBoxObject::GetRowAt(int32_t x, int32_t y)
|
||||
{
|
||||
int32_t row;
|
||||
GetRowAt(x, y, &row);
|
||||
return row;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TreeBoxObject::GetCellAt(int32_t aX, int32_t aY, int32_t *aRow,
|
||||
nsITreeColumn** 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)
|
||||
{
|
||||
nsCOMPtr<nsITreeColumn> col;
|
||||
GetCellAt(x, y, &aRetVal.mRow, getter_AddRefs(col), aRetVal.mChildElt);
|
||||
aRetVal.mCol = col.forget().downcast<nsTreeColumn>();
|
||||
}
|
||||
|
||||
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;
|
||||
nsITreeColumn* col;
|
||||
nsAutoString childElt;
|
||||
GetCellAt(x, y, &row, &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, nsITreeColumn* 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, nsITreeColumn* 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, nsITreeColumn* 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::ClearCachedValues()
|
||||
{
|
||||
mTreeBody = nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TreeBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TreeBoxObjectBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsresult
|
||||
NS_NewTreeBoxObject(nsIBoxObject** aResult)
|
||||
{
|
||||
NS_ADDREF(*aResult = new TreeBoxObject());
|
||||
return NS_OK;
|
||||
}
|
||||
128
layout/xul/tree/TreeBoxObject.h
Normal file
128
layout/xul/tree/TreeBoxObject.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_TreeBoxObject_h
|
||||
#define mozilla_dom_TreeBoxObject_h
|
||||
|
||||
#include "mozilla/dom/BoxObject.h"
|
||||
#include "nsITreeView.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
|
||||
class nsTreeBodyFrame;
|
||||
class nsTreeColumn;
|
||||
class nsTreeColumns;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct TreeCellInfo;
|
||||
class DOMRect;
|
||||
|
||||
class TreeBoxObject final : public BoxObject,
|
||||
public nsITreeBoxObject
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TreeBoxObject, BoxObject)
|
||||
NS_DECL_NSITREEBOXOBJECT
|
||||
|
||||
TreeBoxObject();
|
||||
|
||||
nsTreeBodyFrame* GetTreeBodyFrame(bool aFlushLayout = false);
|
||||
nsTreeBodyFrame* GetCachedTreeBodyFrame() { return mTreeBody; }
|
||||
|
||||
//NS_PIBOXOBJECT interfaces
|
||||
virtual void Clear() override;
|
||||
virtual void ClearCachedValues() override;
|
||||
|
||||
// WebIDL
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<nsTreeColumns> GetColumns();
|
||||
|
||||
already_AddRefed<nsITreeView> GetView();
|
||||
|
||||
void SetView(nsITreeView* arg, ErrorResult& aRv);
|
||||
|
||||
bool Focused();
|
||||
|
||||
already_AddRefed<Element> GetTreeBody();
|
||||
|
||||
int32_t RowHeight();
|
||||
|
||||
int32_t RowWidth();
|
||||
|
||||
int32_t HorizontalPosition();
|
||||
|
||||
already_AddRefed<nsIScriptableRegion> SelectionRegion();
|
||||
|
||||
int32_t GetFirstVisibleRow();
|
||||
|
||||
int32_t GetLastVisibleRow();
|
||||
|
||||
int32_t GetPageLength();
|
||||
|
||||
int32_t GetRowAt(int32_t x, int32_t y);
|
||||
|
||||
void GetCellAt(int32_t x, int32_t y, TreeCellInfo& aRetVal, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DOMRect> GetCoordsForCellItem(int32_t row,
|
||||
nsTreeColumn& col,
|
||||
const nsAString& element,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool IsCellCropped(int32_t row, nsITreeColumn* col, ErrorResult& aRv);
|
||||
|
||||
// Deprecated APIs from old IDL
|
||||
void GetCellAt(JSContext* cx,
|
||||
int32_t x, int32_t y,
|
||||
JS::Handle<JSObject*> rowOut,
|
||||
JS::Handle<JSObject*> colOut,
|
||||
JS::Handle<JSObject*> childEltOut,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void 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);
|
||||
|
||||
// Same signature (except for nsresult return type) as the XPIDL impls
|
||||
// void Invalidate();
|
||||
// void BeginUpdateBatch();
|
||||
// void EndUpdateBatch();
|
||||
// void ClearStyleAndImageCaches();
|
||||
// void SetFocused(bool arg);
|
||||
// void EnsureRowIsVisible(int32_t index);
|
||||
// void EnsureCellIsVisible(int32_t row, nsITreeColumn* col);
|
||||
// void ScrollToRow(int32_t index);
|
||||
// void ScrollByLines(int32_t numLines);
|
||||
// void ScrollByPages(int32_t numPages);
|
||||
// void ScrollToCell(int32_t row, nsITreeColumn* col);
|
||||
// void ScrollToColumn(nsITreeColumn* col);
|
||||
// void ScrollToHorizontalPosition(int32_t horizontalPosition);
|
||||
// void InvalidateColumn(nsITreeColumn* col);
|
||||
// void InvalidateRow(int32_t index);
|
||||
// void InvalidateCell(int32_t row, nsITreeColumn* col);
|
||||
// void InvalidateRange(int32_t startIndex, int32_t endIndex);
|
||||
// void InvalidateColumnRange(int32_t startIndex, int32_t endIndex, nsITreeColumn* col);
|
||||
// void RowCountChanged(int32_t index, int32_t count);
|
||||
|
||||
protected:
|
||||
nsTreeBodyFrame* mTreeBody;
|
||||
nsCOMPtr<nsITreeView> mView;
|
||||
|
||||
private:
|
||||
~TreeBoxObject();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
21
layout/xul/tree/crashtests/307298-1.xul
Normal file
21
layout/xul/tree/crashtests/307298-1.xul
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="var tree = document.getElementById('tree'), treeitem = document.getElementById('treeitem'); tree.parentNode.insertBefore(treeitem, tree);">
|
||||
|
||||
<tree flex="1" id="tree">
|
||||
<treecols>
|
||||
<treecol id="name" label="Name" primary="true" flex="1"/>
|
||||
</treecols>
|
||||
|
||||
<treechildren>
|
||||
<treeitem id="treeitem">
|
||||
<treerow>
|
||||
<treecell label="Click the button below to crash"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
</window>
|
||||
30
layout/xul/tree/crashtests/309732-1.xul
Normal file
30
layout/xul/tree/crashtests/309732-1.xul
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="reftest-wait" onload="setTimeout(boom, 30)">
|
||||
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.appendChild(document.getElementById("TC"));
|
||||
document.documentElement.appendChild(document.getElementById("TI"));
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
<tree flex="1">
|
||||
<treecols>
|
||||
<treecol label="Name"/>
|
||||
</treecols>
|
||||
<treechildren id="TC">
|
||||
<treeitem id="TI">
|
||||
<treerow>
|
||||
<treecell label="First treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
</window>
|
||||
31
layout/xul/tree/crashtests/309732-2.xul
Normal file
31
layout/xul/tree/crashtests/309732-2.xul
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="reftest-wait" onload="setTimeout(boom, 30)">
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.appendChild(document.getElementById('TC'));
|
||||
document.getElementById('TI').hidden = false;
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<tree flex="1">
|
||||
<treecols>
|
||||
<treecol label="Name" flex="1"/>
|
||||
</treecols>
|
||||
<treechildren id="TC">
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="First treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
<treeitem id="TI" hidden="true"/>
|
||||
</window>
|
||||
43
layout/xul/tree/crashtests/366583-1.xul
Normal file
43
layout/xul/tree/crashtests/366583-1.xul
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="boom1();"
|
||||
class="reftest-wait">
|
||||
|
||||
<script>
|
||||
|
||||
var tree;
|
||||
|
||||
function boom1()
|
||||
{
|
||||
tree = document.getElementById("tree");
|
||||
tree.style.position = "fixed";
|
||||
setTimeout(boom2, 30);
|
||||
}
|
||||
|
||||
function boom2()
|
||||
{
|
||||
tree.style.overflow = "visible";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
<tree rows="6" id="tree" style="display: list-item; overflow: auto; visibility: collapse;">
|
||||
<treecols>
|
||||
<treecol id="firstname" label="First Name" primary="true" flex="3"/>
|
||||
<treecol id="lastname" label="Last Name" flex="7"/>
|
||||
</treecols>
|
||||
|
||||
<treechildren>
|
||||
<treeitem container="true" open="true">
|
||||
<treerow>
|
||||
<treecell label="Foo"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
|
||||
</window>
|
||||
24
layout/xul/tree/crashtests/380217-1.xul
Normal file
24
layout/xul/tree/crashtests/380217-1.xul
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<window xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="document.documentElement.style.content = '\'a\'';">
|
||||
|
||||
<html:style>
|
||||
* { position: fixed; }
|
||||
</html:style>
|
||||
|
||||
<tree rows="6">
|
||||
<treecols>
|
||||
<treecol id="firstname" label="First Name" primary="true"/>
|
||||
</treecols>
|
||||
<treechildren>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
</window>
|
||||
15
layout/xul/tree/crashtests/382444-1-inner.html
Normal file
15
layout/xul/tree/crashtests/382444-1-inner.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Testcase bug - Crash [@ nsINodeInfo::Equals] with underflow event, tree stuff and removing window</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="data:application/vnd.mozilla.xul+xml;charset=utf-8,%3Cwindow%20xmlns%3D%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%3E%0A%3Ctree%20style%3D%22overflow%3A%20auto%3B%20display%3A%20-moz-inline-box%3B%22%3E%0A%3Ctreeitem%20style%3D%22overflow%3A%20scroll%3B%20display%3A%20table-cell%3B%22%3E%0A%3Ctreechildren%20style%3D%22%20display%3A%20table-row%3B%22%3E%0A%3Ctreeitem%20id%3D%22a%22%20style%3D%22display%3A%20table-cell%3B%22%3E%0A%3C/treeitem%3E%0A%3C/treechildren%3E%0A%3C/treeitem%3E%0A%0A%3C/tree%3E%0A%0A%3Cscript%20xmlns%3D%22http%3A//www.w3.org/1999/xhtml%22%3E%0Afunction%20doe%28%29%20%7B%0Adocument.getElementById%28%27a%27%29.parentNode.removeChild%28document.getElementById%28%27a%27%29%29%3B%0A%7D%0AsetTimeout%28doe%2C%20100%29%3B%0Adocument.addEventListener%28%27underflow%27%2C%20function%28e%29%20%7Bwindow.frameElement.parentNode.removeChild%28window.frameElement%29%20%7D%2C%20true%29%3B%0Awindow.addEventListener%28%27underflow%27%2C%20function%28e%29%20%7Bwindow.frameElement.parentNode.removeChild%28window.frameElement%29%20%7D%2C%20true%29%3B%0A%3C/script%3E%0A%3C/window%3E" id="content"></iframe>
|
||||
|
||||
<script>
|
||||
function doe() {
|
||||
window.location.reload();
|
||||
}
|
||||
setTimeout(doe, 500);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
9
layout/xul/tree/crashtests/382444-1.html
Normal file
9
layout/xul/tree/crashtests/382444-1.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
setTimeout('document.documentElement.className = ""', 500);
|
||||
</script>
|
||||
<body>
|
||||
<iframe src="382444-1-inner.html"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
41
layout/xul/tree/crashtests/391178-1.xhtml
Normal file
41
layout/xul/tree/crashtests/391178-1.xhtml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
var ccc;
|
||||
|
||||
function boom()
|
||||
{
|
||||
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
var hbox = document.createElementNS(XUL_NS, 'hbox');
|
||||
var tree = document.createElementNS(XUL_NS, 'tree');
|
||||
var treecol = document.createElementNS(XUL_NS, 'treecol');
|
||||
|
||||
ccc = document.getElementById("ccc");
|
||||
|
||||
ccc.style.position = "fixed";
|
||||
|
||||
hbox.appendChild(treecol);
|
||||
tree.appendChild(hbox);
|
||||
ccc.appendChild(tree);
|
||||
|
||||
setTimeout(boom2, 200);
|
||||
}
|
||||
|
||||
function boom2()
|
||||
{
|
||||
ccc.style.position = "";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
|
||||
<div id="ccc">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
20
layout/xul/tree/crashtests/391178-2.xul
Normal file
20
layout/xul/tree/crashtests/391178-2.xul
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
|
||||
<tree id="a" style="position: fixed;">
|
||||
<box style=" display: -moz-box; position: fixed;">
|
||||
<treecol style=" display: -moz-box;"/>
|
||||
</box>
|
||||
<box style="position: fixed;">
|
||||
<treechildren style="display: -moz-box; position: absolute;"/>
|
||||
</box>
|
||||
</tree>
|
||||
|
||||
<script xmlns="http://www.w3.org/1999/xhtml">
|
||||
function removestyles(){
|
||||
document.getElementById('a').removeAttribute('style');
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
setTimeout(removestyles, 100);
|
||||
</script>
|
||||
</window>
|
||||
3
layout/xul/tree/crashtests/393665-1.xul
Normal file
3
layout/xul/tree/crashtests/393665-1.xul
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<treechildren style="display: block" />
|
||||
</window>
|
||||
44
layout/xul/tree/crashtests/399227-1.xul
Normal file
44
layout/xul/tree/crashtests/399227-1.xul
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="reftest-wait" onload="setTimeout(boom, 30)">
|
||||
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var tree = document.getElementById("thetree");
|
||||
var selection = tree.view.selection;
|
||||
|
||||
selection.select(0);
|
||||
tree.parentNode.removeChild(tree);
|
||||
|
||||
// This is expected to throw an error (it used to crash).
|
||||
try {
|
||||
selection.rangedSelect(1, 1, false);
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
<tree flex="1" id="thetree">
|
||||
<treecols>
|
||||
<treecol label="Name"/>
|
||||
</treecols>
|
||||
<treechildren id="TC">
|
||||
<treeitem id="TI1">
|
||||
<treerow>
|
||||
<treecell label="First treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem id="TI2">
|
||||
<treerow>
|
||||
<treecell label="Second treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
</window>
|
||||
50
layout/xul/tree/crashtests/399227-2.xul
Normal file
50
layout/xul/tree/crashtests/399227-2.xul
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="reftest-wait" onload="setTimeout(boom, 30);">
|
||||
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var tree = document.getElementById("thetree");
|
||||
var selection = tree.view.selection;
|
||||
var treecolumn0 = tree.columns[0];
|
||||
var treecolumn1 = tree.columns[1];
|
||||
|
||||
selection.select(0);
|
||||
selection.currentColumn = treecolumn0;
|
||||
tree.parentNode.removeChild(tree);
|
||||
|
||||
// This is expected to throw an error (it used to crash).
|
||||
try {
|
||||
selection.currentColumn = treecolumn1;
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
<tree flex="1" id="thetree" seltype="cell">
|
||||
<treecols>
|
||||
<treecol label="Name"/>
|
||||
<treecol label="Test"/>
|
||||
</treecols>
|
||||
<treechildren id="TC">
|
||||
<treeitem id="TI1">
|
||||
<treerow>
|
||||
<treecell label="First treecell"/>
|
||||
<treecell label="Second treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem id="TI2">
|
||||
<treerow>
|
||||
<treecell label="Third treecell"/>
|
||||
<treecell label="Fourth treecell"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
</window>
|
||||
10
layout/xul/tree/crashtests/399692-1.xhtml
Normal file
10
layout/xul/tree/crashtests/399692-1.xhtml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<xul:treechildren style="display: inline;" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
9
layout/xul/tree/crashtests/399715-1.xhtml
Normal file
9
layout/xul/tree/crashtests/399715-1.xhtml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<body style="float: right;" onload="document.body.style.cssFloat = '';">
|
||||
|
||||
<xul:tree><xul:hbox><xul:treecol /></xul:hbox></xul:tree>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
25
layout/xul/tree/crashtests/409807-1.xul
Normal file
25
layout/xul/tree/crashtests/409807-1.xul
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="boom();">
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var tree = document.getElementById("tree");
|
||||
var tc = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "treechildren");
|
||||
|
||||
document.addEventListener("DOMAttrModified", m, false);
|
||||
|
||||
tree.appendChild(tc);
|
||||
|
||||
function m()
|
||||
{
|
||||
document.removeEventListener("DOMAttrModified", m, false);
|
||||
tree.removeChild(tc);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<tree id="tree" />
|
||||
|
||||
</window>
|
||||
20
layout/xul/tree/crashtests/414170-1.xul
Normal file
20
layout/xul/tree/crashtests/414170-1.xul
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="boom();">
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var option = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
|
||||
document.getElementById("tc").appendChild(option);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<tree><treechildren id="tc"><hbox/></treechildren></tree>
|
||||
|
||||
</window>
|
||||
8
layout/xul/tree/crashtests/430394-1.xul
Normal file
8
layout/xul/tree/crashtests/430394-1.xul
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<tree id="a" style="content: 't';" rows="-2">
|
||||
<menuitem id="b" onoverflow="event.currentTarget.parentNode.removeAttribute('style')">
|
||||
<treechildren style="display: block;" onoverflow="event.target.parentNode.removeChild(event.target)" />
|
||||
<treechildren style="display: block;" ordinal="0.5"/>
|
||||
</menuitem>
|
||||
</tree>
|
||||
</window>
|
||||
23
layout/xul/tree/crashtests/454186-1.xul
Normal file
23
layout/xul/tree/crashtests/454186-1.xul
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<tree flex="1">
|
||||
<treecols>
|
||||
<treecol label="test" flex="1" type="progressmeter" />
|
||||
</treecols>
|
||||
<treechildren>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell value="50" mode="normal" />
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell mode="undetermined" />
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
</window>
|
||||
19
layout/xul/tree/crashtests/479931-1.xhtml
Normal file
19
layout/xul/tree/crashtests/479931-1.xhtml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var o = document.createElementNS("http://www.w3.org/1999/xhtml", "option");
|
||||
var q = document.getElementById("q");
|
||||
q.appendChild(o);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
|
||||
<xul:tree><xul:treechildren id="q"><div/></xul:treechildren></xul:tree>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
12
layout/xul/tree/crashtests/509602-1-overlay.xul
Normal file
12
layout/xul/tree/crashtests/509602-1-overlay.xul
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<box id="b">
|
||||
<box onDOMAttrModified="event.target.parentNode.removeChild(event.target)" id="d"/>
|
||||
<tree/>
|
||||
</box>
|
||||
|
||||
<tree>
|
||||
<box id="b" observes="d"/>
|
||||
<treechildren observes="b"/>
|
||||
</tree>
|
||||
</overlay>
|
||||
3
layout/xul/tree/crashtests/509602-1.xul
Normal file
3
layout/xul/tree/crashtests/509602-1.xul
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<?xul-overlay href="509602-1-overlay.xul"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
|
||||
72
layout/xul/tree/crashtests/585815-iframe.xul
Normal file
72
layout/xul/tree/crashtests/585815-iframe.xul
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="setInterval(run, 25)">
|
||||
|
||||
<tree flex="1" rows="2">
|
||||
<treecols>
|
||||
<treecol id="sender" label="Sender" flex="1"/>
|
||||
<treecol id="subject" label="Subject" flex="2"/>
|
||||
</treecols>
|
||||
<treechildren>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="joe@somewhere.com"/>
|
||||
<treecell label="Top secret plans"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="mel@whereever.com"/>
|
||||
<treecell label="Let's do lunch"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
<script type="text/javascript"><![CDATA[
|
||||
function run() {
|
||||
var tree = document.getElementsByTagName("tree")[0];
|
||||
var sel = tree.view.selection;
|
||||
sel.rangedSelect(0, 0, true);
|
||||
sel.rangedSelect(1000, 1001, true);
|
||||
sel.adjustSelection(1, 0x7fffffff);
|
||||
}
|
||||
]]></script>
|
||||
|
||||
</window>
|
||||
18
layout/xul/tree/crashtests/585815.html
Normal file
18
layout/xul/tree/crashtests/585815.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase for bug 585815</title>
|
||||
<script>
|
||||
function done()
|
||||
{
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setTimeout(done,1000)">
|
||||
|
||||
<iframe src="585815-iframe.xul"></iframe>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
30
layout/xul/tree/crashtests/601427.html
Normal file
30
layout/xul/tree/crashtests/601427.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<script>
|
||||
|
||||
var onPaintFunctions =
|
||||
[
|
||||
function() { document.documentElement.style.MozAppearance = "treeheadersortarrow"; },
|
||||
function() { document.documentElement.style.position = "fixed"; },
|
||||
function() { document.documentElement.removeAttribute("class"); }
|
||||
];
|
||||
|
||||
var i = 0;
|
||||
|
||||
function advance()
|
||||
{
|
||||
var f = onPaintFunctions[i++];
|
||||
if (f)
|
||||
f();
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
window.addEventListener("MozAfterPaint", advance, true);
|
||||
advance();
|
||||
}
|
||||
|
||||
window.addEventListener("load", start, false);
|
||||
|
||||
</script>
|
||||
</html>
|
||||
54
layout/xul/tree/crashtests/730441-1.xul
Normal file
54
layout/xul/tree/crashtests/730441-1.xul
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0xb6457185 in nsIContent::SetAttr (this=0x0, aNameSpaceID=0, aName=0xb0cb064c, aValue=..., aNotify=1) at ../../dist/include/nsIContent.h:285
|
||||
285 return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
|
||||
(gdb) p this
|
||||
$6 = (nsIContent * const) 0x0
|
||||
(gdb) bt 3
|
||||
#0 0xb6457185 in nsIContent::SetAttr (this=0x0, aNameSpaceID=0, aName=0xb0cb064c, aValue=..., aNotify=1) at ../../dist/include/nsIContent.h:285
|
||||
#1 0xb6b72072 in nsTreeColumns::RestoreNaturalOrder (this=0xaaf83cc0) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:605
|
||||
#2 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
|
||||
(More stack frames follow...)
|
||||
(gdb) frame 1
|
||||
#1 0xb6b72072 in nsTreeColumns::RestoreNaturalOrder (this=0xaaf83cc0) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:605
|
||||
605 child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, PR_TRUE);
|
||||
(gdb) list
|
||||
600 PRUint32 numChildren = colsContent->GetChildCount();
|
||||
601 for (PRUint32 i = 0; i < numChildren; ++i) {
|
||||
602 nsIContent *child = colsContent->GetChildAt(i);
|
||||
603 nsAutoString ordinal;
|
||||
604 ordinal.AppendInt(i);
|
||||
605 child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, PR_TRUE);
|
||||
606 }
|
||||
(gdb) p child
|
||||
$7 = (nsIContent *) 0x0
|
||||
|
||||
First loop iteration: |child->SetAttr()| dispatches "DOMAttrModified" event.
|
||||
Event listener removes next column. Second loop iteration: |colsContent->GetChildAt(i)|
|
||||
returns null. Then we have |null->SetAttr()|.
|
||||
-->
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="run();">
|
||||
<tree id="tree">
|
||||
<treecols>
|
||||
<treecol id="col1"/>
|
||||
<treecol id="col2"/>
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
</tree>
|
||||
<script type="text/javascript"><![CDATA[
|
||||
function listener() {
|
||||
var col2 = document.getElementById("col2");
|
||||
col2.parentNode.removeChild(col2);
|
||||
}
|
||||
|
||||
function run() {
|
||||
var col1 = document.getElementById("col1");
|
||||
col1.addEventListener("DOMAttrModified", listener, true);
|
||||
var tree = document.getElementById("tree");
|
||||
tree.columns.restoreNaturalOrder();
|
||||
}
|
||||
]]></script>
|
||||
</window>
|
||||
|
||||
52
layout/xul/tree/crashtests/730441-2.xul
Normal file
52
layout/xul/tree/crashtests/730441-2.xul
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0xb6b720a6 in nsTreeColumns::RestoreNaturalOrder (this=0xa947a580) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:610
|
||||
610 mTree->Invalidate();
|
||||
(gdb) bt 3
|
||||
#0 0xb6b720a6 in nsTreeColumns::RestoreNaturalOrder (this=0xa947a580) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:610
|
||||
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
|
||||
#2 0xb6171901 in XPCWrappedNative::CallMethod (ccx=..., mode=XPCWrappedNative::CALL_METHOD)
|
||||
at js/src/xpconnect/src/xpcwrappednative.cpp:2722
|
||||
(More stack frames follow...)
|
||||
(gdb) list
|
||||
605 child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, PR_TRUE);
|
||||
606 }
|
||||
607
|
||||
608 nsTreeColumns::InvalidateColumns();
|
||||
609
|
||||
610 mTree->Invalidate();
|
||||
611
|
||||
612 return NS_OK;
|
||||
613 }
|
||||
614
|
||||
(gdb) p mTree
|
||||
$9 = (nsITreeBoxObject *) 0x0
|
||||
|
||||
|child->SetAttr()| dispatches "DOMAttrModified" event. Event listener removes
|
||||
whole tree, |mTree| is being set to null. Then we have |null->Invalidate()|.
|
||||
-->
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="run();">
|
||||
<tree id="tree">
|
||||
<treecols>
|
||||
<treecol id="col"/>
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
</tree>
|
||||
<script type="text/javascript"><![CDATA[
|
||||
var tree = null;
|
||||
|
||||
function listener() {
|
||||
tree.parentNode.removeChild(tree);
|
||||
}
|
||||
|
||||
function run() {
|
||||
col = document.getElementById("col");
|
||||
col.addEventListener("DOMAttrModified", listener, true);
|
||||
tree = document.getElementById("tree");
|
||||
tree.columns.restoreNaturalOrder();
|
||||
}
|
||||
]]></script>
|
||||
</window>
|
||||
|
||||
38
layout/xul/tree/crashtests/730441-3.xul
Normal file
38
layout/xul/tree/crashtests/730441-3.xul
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
###!!! ASSERTION: You can't dereference a NULL nsCOMPtr with operator->().: 'mRawPtr != 0', file ../../../../dist/include/nsCOMPtr.h, line 796
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0xb6b7463a in nsTreeContentView::SetTree (this=0xb0ba2510, aTree=0xaaecece0) at layout/xul/base/src/tree/src/nsTreeContentView.cpp:571
|
||||
571 boxObject->GetElement(getter_AddRefs(element));
|
||||
(gdb) bt 3
|
||||
#0 0xb6b7463a in nsTreeContentView::SetTree (this=0xb0ba2510, aTree=0xaaecece0) at layout/xul/base/src/tree/src/nsTreeContentView.cpp:571
|
||||
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
|
||||
#2 0xb6171901 in XPCWrappedNative::CallMethod (ccx=..., mode=XPCWrappedNative::CALL_METHOD)
|
||||
at js/src/xpconnect/src/xpcwrappednative.cpp:2722
|
||||
(More stack frames follow...)
|
||||
(gdb) list 566
|
||||
561 nsTreeContentView::SetTree(nsITreeBoxObject* aTree)
|
||||
562 {
|
||||
563 ClearRows();
|
||||
564
|
||||
565 mBoxObject = aTree;
|
||||
566
|
||||
567 if (aTree && !mRoot) {
|
||||
568 // Get our root element
|
||||
569 nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mBoxObject);
|
||||
570 nsCOMPtr<nsIDOMElement> element;
|
||||
571 boxObject->GetElement(getter_AddRefs(element));
|
||||
(gdb) p boxObject
|
||||
$16 = {mRawPtr = 0x0}
|
||||
|
||||
|aTree| does not implement |nsIBoxObject|, so |do_QueryInterface(mBoxObject)|
|
||||
returns null. Then we have |null->GetElement()|.
|
||||
-->
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="document.getElementById('tree').view.setTree({});">
|
||||
<tree id="tree">
|
||||
<treechildren/>
|
||||
</tree>
|
||||
</window>
|
||||
|
||||
24
layout/xul/tree/crashtests/crashtests.list
Normal file
24
layout/xul/tree/crashtests/crashtests.list
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
load 307298-1.xul
|
||||
load 309732-1.xul
|
||||
load 309732-2.xul
|
||||
load 366583-1.xul
|
||||
load 380217-1.xul
|
||||
load 382444-1.html
|
||||
load 391178-1.xhtml
|
||||
load 391178-2.xul
|
||||
load 393665-1.xul
|
||||
load 399227-1.xul
|
||||
load 399227-2.xul
|
||||
load 399692-1.xhtml
|
||||
load 399715-1.xhtml
|
||||
load 409807-1.xul
|
||||
load 414170-1.xul
|
||||
load 430394-1.xul
|
||||
load 454186-1.xul
|
||||
load 479931-1.xhtml
|
||||
load 509602-1.xul
|
||||
load 585815.html
|
||||
load 601427.html
|
||||
load 730441-1.xul
|
||||
load 730441-2.xul
|
||||
load 730441-3.xul
|
||||
53
layout/xul/tree/moz.build
Normal file
53
layout/xul/tree/moz.build
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Core', 'XP Toolkit/Widgets: XUL')
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsITreeBoxObject.idl',
|
||||
'nsITreeColumns.idl',
|
||||
'nsITreeContentView.idl',
|
||||
'nsITreeSelection.idl',
|
||||
'nsITreeView.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'layout_xul_tree'
|
||||
|
||||
EXPORTS += [
|
||||
'nsTreeColFrame.h',
|
||||
'nsTreeColumns.h',
|
||||
'nsTreeUtils.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'TreeBoxObject.h'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsTreeBodyFrame.cpp',
|
||||
'nsTreeColFrame.cpp',
|
||||
'nsTreeColumns.cpp',
|
||||
'nsTreeContentView.cpp',
|
||||
'nsTreeImageListener.cpp',
|
||||
'nsTreeSelection.cpp',
|
||||
'nsTreeStyleCache.cpp',
|
||||
'nsTreeUtils.cpp',
|
||||
'TreeBoxObject.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
'../../base',
|
||||
'../../forms',
|
||||
'../../generic',
|
||||
'../../style',
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
189
layout/xul/tree/nsITreeBoxObject.idl
Normal file
189
layout/xul/tree/nsITreeBoxObject.idl
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
interface nsITreeView;
|
||||
interface nsITreeSelection;
|
||||
interface nsITreeColumn;
|
||||
interface nsITreeColumns;
|
||||
interface nsIScriptableRegion;
|
||||
|
||||
[scriptable, uuid(f3da0c5e-51f5-45f0-b2cd-6be3ab6847ae)]
|
||||
interface nsITreeBoxObject : nsISupports
|
||||
{
|
||||
/**
|
||||
* Obtain the columns.
|
||||
*/
|
||||
readonly attribute nsITreeColumns columns;
|
||||
|
||||
/**
|
||||
* The view that backs the tree and that supplies it with its data.
|
||||
* It is dynamically settable, either using a view attribute on the
|
||||
* tree tag or by setting this attribute to a new value.
|
||||
*/
|
||||
attribute nsITreeView view;
|
||||
|
||||
/**
|
||||
* Whether or not we are currently focused.
|
||||
*/
|
||||
attribute boolean focused;
|
||||
|
||||
/**
|
||||
* Obtain the treebody content node
|
||||
*/
|
||||
readonly attribute nsIDOMElement treeBody;
|
||||
|
||||
/**
|
||||
* Obtain the height of a row.
|
||||
*/
|
||||
readonly attribute long rowHeight;
|
||||
|
||||
/**
|
||||
* Obtain the width of a row.
|
||||
*/
|
||||
readonly attribute long rowWidth;
|
||||
|
||||
/**
|
||||
* Get the pixel position of the horizontal scrollbar.
|
||||
*/
|
||||
readonly attribute long horizontalPosition;
|
||||
|
||||
/**
|
||||
* Return the region for the visible parts of the selection, in device pixels.
|
||||
*/
|
||||
readonly attribute nsIScriptableRegion selectionRegion;
|
||||
|
||||
/**
|
||||
* Get the index of the first visible row.
|
||||
*/
|
||||
long getFirstVisibleRow();
|
||||
|
||||
/**
|
||||
* Get the index of the last visible row.
|
||||
*/
|
||||
long getLastVisibleRow();
|
||||
|
||||
/**
|
||||
* Gets the number of possible visible rows.
|
||||
*/
|
||||
long getPageLength();
|
||||
|
||||
/**
|
||||
* Ensures that a row at a given index is visible.
|
||||
*/
|
||||
void ensureRowIsVisible(in long index);
|
||||
|
||||
/**
|
||||
* Ensures that a given cell in the tree is visible.
|
||||
*/
|
||||
void ensureCellIsVisible(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Scrolls such that the row at index is at the top of the visible view.
|
||||
*/
|
||||
void scrollToRow(in long index);
|
||||
|
||||
/**
|
||||
* Scroll the tree up or down by numLines lines. Positive
|
||||
* values move down in the tree. Prevents scrolling off the
|
||||
* end of the tree.
|
||||
*/
|
||||
void scrollByLines(in long numLines);
|
||||
|
||||
/**
|
||||
* Scroll the tree up or down by numPages pages. A page
|
||||
* is considered to be the amount displayed by the tree.
|
||||
* Positive values move down in the tree. Prevents scrolling
|
||||
* off the end of the tree.
|
||||
*/
|
||||
void scrollByPages(in long numPages);
|
||||
|
||||
/**
|
||||
* Scrolls such that a given cell is visible (if possible)
|
||||
* at the top left corner of the visible view.
|
||||
*/
|
||||
void scrollToCell(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Scrolls horizontally so that the specified column is
|
||||
* at the left of the view (if possible).
|
||||
*/
|
||||
void scrollToColumn(in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Scroll to a specific horizontal pixel position.
|
||||
*/
|
||||
void scrollToHorizontalPosition(in long horizontalPosition);
|
||||
|
||||
/**
|
||||
* Invalidation methods for fine-grained painting control.
|
||||
*/
|
||||
void invalidate();
|
||||
void invalidateColumn(in nsITreeColumn col);
|
||||
void invalidateRow(in long index);
|
||||
void invalidateCell(in long row, in nsITreeColumn col);
|
||||
void invalidateRange(in long startIndex, in long endIndex);
|
||||
void invalidateColumnRange(in long startIndex, in long endIndex,
|
||||
in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* A hit test that can tell you what row the mouse is over.
|
||||
* returns -1 for invalid mouse coordinates.
|
||||
*
|
||||
* The coordinate system is the client coordinate system for the
|
||||
* document this boxObject lives in, and the units are CSS pixels.
|
||||
*/
|
||||
long getRowAt(in long x, in long y);
|
||||
|
||||
/**
|
||||
* A hit test that can tell you what cell the mouse is over. Row is the row index
|
||||
* hit, returns -1 for invalid mouse coordinates. ColID is the column hit.
|
||||
* ChildElt is the pseudoelement hit: this can have values of
|
||||
* "cell", "twisty", "image", and "text".
|
||||
*
|
||||
* The coordinate system is the client coordinate system for the
|
||||
* document this boxObject lives in, and the units are CSS pixels.
|
||||
*/
|
||||
void getCellAt(in long x, in long y, out long row, out nsITreeColumn col, out AString childElt);
|
||||
|
||||
/**
|
||||
* Find the coordinates of an element within a specific cell.
|
||||
*/
|
||||
void getCoordsForCellItem(in long row, in nsITreeColumn col, in AString element,
|
||||
out long x, out long y, out long width, out long height);
|
||||
|
||||
/**
|
||||
* Determine if the text of a cell is being cropped or not.
|
||||
*/
|
||||
boolean isCellCropped(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* The view is responsible for calling these notification methods when
|
||||
* rows are added or removed. Index is the position at which the new
|
||||
* rows were added or at which rows were removed. For
|
||||
* non-contiguous additions/removals, this method should be called multiple times.
|
||||
*/
|
||||
void rowCountChanged(in long index, in long count);
|
||||
|
||||
/**
|
||||
* Notify the tree that the view is about to perform a batch
|
||||
* update, that is, add, remove or invalidate several rows at once.
|
||||
* This must be followed by calling endUpdateBatch(), otherwise the tree
|
||||
* will get out of sync.
|
||||
*/
|
||||
void beginUpdateBatch();
|
||||
|
||||
/**
|
||||
* Notify the tree that the view has completed a batch update.
|
||||
*/
|
||||
void endUpdateBatch();
|
||||
|
||||
/**
|
||||
* Called on a theme switch to flush out the tree's style and image caches.
|
||||
*/
|
||||
void clearStyleAndImageCaches();
|
||||
};
|
||||
96
layout/xul/tree/nsITreeColumns.idl
Normal file
96
layout/xul/tree/nsITreeColumns.idl
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsITreeColumns;
|
||||
interface nsIDOMElement;
|
||||
interface nsIAtom;
|
||||
|
||||
[scriptable, uuid(ae835ecf-6b32-4660-9b43-8a270df56e02)]
|
||||
interface nsITreeColumn : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMElement element;
|
||||
|
||||
readonly attribute nsITreeColumns columns;
|
||||
|
||||
readonly attribute long x;
|
||||
readonly attribute long width;
|
||||
|
||||
readonly attribute AString id;
|
||||
[noscript] void getIdConst([shared] out wstring idConst);
|
||||
[noscript] readonly attribute nsIAtom atom;
|
||||
|
||||
readonly attribute long index;
|
||||
|
||||
readonly attribute boolean primary;
|
||||
readonly attribute boolean cycler;
|
||||
readonly attribute boolean editable;
|
||||
readonly attribute boolean selectable;
|
||||
|
||||
const short TYPE_TEXT = 1;
|
||||
const short TYPE_CHECKBOX = 2;
|
||||
const short TYPE_PROGRESSMETER = 3;
|
||||
const short TYPE_PASSWORD = 4;
|
||||
readonly attribute short type;
|
||||
|
||||
nsITreeColumn getNext();
|
||||
nsITreeColumn getPrevious();
|
||||
|
||||
void invalidate();
|
||||
};
|
||||
|
||||
interface nsITreeBoxObject;
|
||||
|
||||
[scriptable, uuid(f8a8d6b4-6788-438d-9009-7142798767ab)]
|
||||
interface nsITreeColumns : nsISupports
|
||||
{
|
||||
/**
|
||||
* The tree widget for these columns.
|
||||
*/
|
||||
readonly attribute nsITreeBoxObject tree;
|
||||
|
||||
/**
|
||||
* The number of columns.
|
||||
*/
|
||||
readonly attribute long count;
|
||||
|
||||
/**
|
||||
* An alias for count (for the benefit of scripts which treat this as an
|
||||
* array).
|
||||
*/
|
||||
readonly attribute long length;
|
||||
|
||||
/**
|
||||
* Get the first/last column.
|
||||
*/
|
||||
nsITreeColumn getFirstColumn();
|
||||
nsITreeColumn getLastColumn();
|
||||
|
||||
/**
|
||||
* Attribute based column getters.
|
||||
*/
|
||||
nsITreeColumn getPrimaryColumn();
|
||||
nsITreeColumn getSortedColumn();
|
||||
nsITreeColumn getKeyColumn();
|
||||
|
||||
/**
|
||||
* Get the column for the given element.
|
||||
*/
|
||||
nsITreeColumn getColumnFor(in nsIDOMElement element);
|
||||
|
||||
/**
|
||||
* Parametric column getters.
|
||||
*/
|
||||
nsITreeColumn getNamedColumn(in AString id);
|
||||
nsITreeColumn getColumnAt(in long index);
|
||||
|
||||
/**
|
||||
* This method is called whenever a treecol is added or removed and
|
||||
* the column cache needs to be rebuilt.
|
||||
*/
|
||||
void invalidateColumns();
|
||||
|
||||
void restoreNaturalOrder();
|
||||
};
|
||||
22
layout/xul/tree/nsITreeContentView.idl
Normal file
22
layout/xul/tree/nsITreeContentView.idl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
|
||||
[scriptable, uuid(5ef62896-0c0a-41f1-bb3c-44a60f5dfdab)]
|
||||
interface nsITreeContentView : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve the content item associated with the specified index.
|
||||
*/
|
||||
nsIDOMElement getItemAtIndex(in long index);
|
||||
|
||||
/**
|
||||
* Retrieve the index associated with the specified content item.
|
||||
*/
|
||||
long getIndexOfItem(in nsIDOMElement item);
|
||||
};
|
||||
130
layout/xul/tree/nsITreeSelection.idl
Normal file
130
layout/xul/tree/nsITreeSelection.idl
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
interface nsITreeBoxObject;
|
||||
interface nsITreeColumn;
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(ab6fe746-300b-4ab4-abb9-1c0e3977874c)]
|
||||
interface nsITreeSelection : nsISupports
|
||||
{
|
||||
/**
|
||||
* The tree widget for this selection.
|
||||
*/
|
||||
attribute nsITreeBoxObject tree;
|
||||
|
||||
/**
|
||||
* This attribute is a boolean indicating single selection.
|
||||
*/
|
||||
readonly attribute boolean single;
|
||||
|
||||
/**
|
||||
* The number of rows currently selected in this tree.
|
||||
*/
|
||||
readonly attribute long count;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the row at the specified index is
|
||||
* part of the selection.
|
||||
*/
|
||||
boolean isSelected(in long index);
|
||||
|
||||
/**
|
||||
* Deselect all rows and select the row at the specified index.
|
||||
*/
|
||||
void select(in long index);
|
||||
|
||||
/**
|
||||
* Perform a timed select.
|
||||
*/
|
||||
void timedSelect(in long index, in long delay);
|
||||
|
||||
/**
|
||||
* Toggle the selection state of the row at the specified index.
|
||||
*/
|
||||
void toggleSelect(in long index);
|
||||
|
||||
/**
|
||||
* Select the range specified by the indices. If augment is true,
|
||||
* then we add the range to the selection without clearing out anything
|
||||
* else. If augment is false, everything is cleared except for the specified range.
|
||||
*/
|
||||
void rangedSelect(in long startIndex, in long endIndex, in boolean augment);
|
||||
|
||||
/**
|
||||
* Clears the range.
|
||||
*/
|
||||
void clearRange(in long startIndex, in long endIndex);
|
||||
|
||||
/**
|
||||
* Clears the selection.
|
||||
*/
|
||||
void clearSelection();
|
||||
|
||||
/**
|
||||
* Inverts the selection.
|
||||
*/
|
||||
void invertSelection();
|
||||
|
||||
/**
|
||||
* Selects all rows.
|
||||
*/
|
||||
void selectAll();
|
||||
|
||||
/**
|
||||
* Iterate the selection using these methods.
|
||||
*/
|
||||
long getRangeCount();
|
||||
void getRangeAt(in long i, out long min, out long max);
|
||||
|
||||
/**
|
||||
* Can be used to invalidate the selection.
|
||||
*/
|
||||
void invalidateSelection();
|
||||
|
||||
/**
|
||||
* Called when the row count changes to adjust selection indices.
|
||||
*/
|
||||
void adjustSelection(in long index, in long count);
|
||||
|
||||
/**
|
||||
* This attribute is a boolean indicating whether or not the
|
||||
* "select" event should fire when the selection is changed using
|
||||
* one of our methods. A view can use this to temporarily suppress
|
||||
* the selection while manipulating all of the indices, e.g., on
|
||||
* a sort.
|
||||
* Note: setting this attribute to false will fire a select event.
|
||||
*/
|
||||
attribute boolean selectEventsSuppressed;
|
||||
|
||||
/**
|
||||
* The current item (the one that gets a focus rect in addition to being
|
||||
* selected).
|
||||
*/
|
||||
attribute long currentIndex;
|
||||
|
||||
/**
|
||||
* The current column.
|
||||
*/
|
||||
attribute nsITreeColumn currentColumn;
|
||||
|
||||
/**
|
||||
* The selection "pivot". This is the first item the user selected as
|
||||
* part of a ranged select.
|
||||
*/
|
||||
readonly attribute long shiftSelectPivot;
|
||||
};
|
||||
|
||||
/**
|
||||
* The following interface is not scriptable and MUST NEVER BE MADE scriptable.
|
||||
* Native treeselections implement it, and we use this to check whether a
|
||||
* treeselection is native (and therefore suitable for use by untrusted content).
|
||||
*/
|
||||
[uuid(1bd59678-5cb3-4316-b246-31a91b19aabe)]
|
||||
interface nsINativeTreeSelection : nsITreeSelection
|
||||
{
|
||||
[noscript] void ensureNative();
|
||||
};
|
||||
215
layout/xul/tree/nsITreeView.idl
Normal file
215
layout/xul/tree/nsITreeView.idl
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsITreeBoxObject;
|
||||
interface nsITreeSelection;
|
||||
interface nsITreeColumn;
|
||||
interface nsIDOMDataTransfer;
|
||||
|
||||
[scriptable, uuid(091116f0-0bdc-4b32-b9c8-c8d5a37cb088)]
|
||||
interface nsITreeView : nsISupports
|
||||
{
|
||||
/**
|
||||
* The total number of rows in the tree (including the offscreen rows).
|
||||
*/
|
||||
readonly attribute long rowCount;
|
||||
|
||||
/**
|
||||
* The selection for this view.
|
||||
*/
|
||||
attribute nsITreeSelection selection;
|
||||
|
||||
/**
|
||||
* A whitespace delimited list of properties. For each property X the view
|
||||
* gives back will cause the pseudoclasses ::-moz-tree-cell(x),
|
||||
* ::-moz-tree-row(x), ::-moz-tree-twisty(x), ::-moz-tree-image(x),
|
||||
* ::-moz-tree-cell-text(x). to be matched on the pseudoelement
|
||||
* ::moz-tree-row.
|
||||
*/
|
||||
AString getRowProperties(in long index);
|
||||
|
||||
/**
|
||||
* A whitespace delimited list of properties for a given cell. Each
|
||||
* property, x, that the view gives back will cause the pseudoclasses
|
||||
* ::-moz-tree-cell(x), ::-moz-tree-row(x), ::-moz-tree-twisty(x),
|
||||
* ::-moz-tree-image(x), ::-moz-tree-cell-text(x). to be matched on the
|
||||
* cell.
|
||||
*/
|
||||
AString getCellProperties(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Called to get properties to paint a column background. For shading the sort
|
||||
* column, etc.
|
||||
*/
|
||||
AString getColumnProperties(in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Methods that can be used to test whether or not a twisty should be drawn,
|
||||
* and if so, whether an open or closed twisty should be used.
|
||||
*/
|
||||
boolean isContainer(in long index);
|
||||
boolean isContainerOpen(in long index);
|
||||
boolean isContainerEmpty(in long index);
|
||||
|
||||
/**
|
||||
* isSeparator is used to determine if the row at index is a separator.
|
||||
* A value of true will result in the tree drawing a horizontal separator.
|
||||
* The tree uses the ::moz-tree-separator pseudoclass to draw the separator.
|
||||
*/
|
||||
boolean isSeparator(in long index);
|
||||
|
||||
/**
|
||||
* Specifies if there is currently a sort on any column. Used mostly by dragdrop
|
||||
* to affect drop feedback.
|
||||
*/
|
||||
boolean isSorted();
|
||||
|
||||
const short DROP_BEFORE = -1;
|
||||
const short DROP_ON = 0;
|
||||
const short DROP_AFTER = 1;
|
||||
/**
|
||||
* Methods used by the drag feedback code to determine if a drag is allowable at
|
||||
* the current location. To get the behavior where drops are only allowed on
|
||||
* items, such as the mailNews folder pane, always return false when
|
||||
* the orientation is not DROP_ON.
|
||||
*/
|
||||
boolean canDrop(in long index, in long orientation, in nsIDOMDataTransfer dataTransfer);
|
||||
|
||||
/**
|
||||
* Called when the user drops something on this view. The |orientation| param
|
||||
* specifies before/on/after the given |row|.
|
||||
*/
|
||||
void drop(in long row, in long orientation, in nsIDOMDataTransfer dataTransfer);
|
||||
|
||||
/**
|
||||
* Methods used by the tree to draw thread lines in the tree.
|
||||
* getParentIndex is used to obtain the index of a parent row.
|
||||
* If there is no parent row, getParentIndex returns -1.
|
||||
*/
|
||||
long getParentIndex(in long rowIndex);
|
||||
|
||||
/**
|
||||
* hasNextSibling is used to determine if the row at rowIndex has a nextSibling
|
||||
* that occurs *after* the index specified by afterIndex. Code that is forced
|
||||
* to march down the view looking at levels can optimize the march by starting
|
||||
* at afterIndex+1.
|
||||
*/
|
||||
boolean hasNextSibling(in long rowIndex, in long afterIndex);
|
||||
|
||||
/**
|
||||
* The level is an integer value that represents
|
||||
* the level of indentation. It is multiplied by the width specified in the
|
||||
* :moz-tree-indentation pseudoelement to compute the exact indendation.
|
||||
*/
|
||||
long getLevel(in long index);
|
||||
|
||||
/**
|
||||
* The image path for a given cell. For defining an icon for a cell.
|
||||
* If the empty string is returned, the :moz-tree-image pseudoelement
|
||||
* will be used.
|
||||
*/
|
||||
AString getImageSrc(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* The progress mode for a given cell. This method is only called for
|
||||
* columns of type |progressmeter|.
|
||||
*/
|
||||
const short PROGRESS_NORMAL = 1;
|
||||
const short PROGRESS_UNDETERMINED = 2;
|
||||
const short PROGRESS_NONE = 3;
|
||||
long getProgressMode(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* The value for a given cell. This method is only called for columns
|
||||
* of type other than |text|.
|
||||
*/
|
||||
AString getCellValue(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* The text for a given cell. If a column consists only of an image, then
|
||||
* the empty string is returned.
|
||||
*/
|
||||
AString getCellText(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Called during initialization to link the view to the front end box object.
|
||||
*/
|
||||
void setTree(in nsITreeBoxObject tree);
|
||||
|
||||
/**
|
||||
* Called on the view when an item is opened or closed.
|
||||
*/
|
||||
void toggleOpenState(in long index);
|
||||
|
||||
/**
|
||||
* Called on the view when a header is clicked.
|
||||
*/
|
||||
void cycleHeader(in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* Should be called from a XUL onselect handler whenever the selection changes.
|
||||
*/
|
||||
void selectionChanged();
|
||||
|
||||
/**
|
||||
* Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked.
|
||||
*/
|
||||
void cycleCell(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* isEditable is called to ask the view if the cell contents are editable.
|
||||
* A value of true will result in the tree popping up a text field when
|
||||
* the user tries to inline edit the cell.
|
||||
*/
|
||||
boolean isEditable(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* isSelectable is called to ask the view if the cell is selectable.
|
||||
* This method is only called if the selection style is |cell| or |text|.
|
||||
* XXXvarga shouldn't this be called isCellSelectable?
|
||||
*/
|
||||
boolean isSelectable(in long row, in nsITreeColumn col);
|
||||
|
||||
/**
|
||||
* setCellValue is called when the value of the cell has been set by the user.
|
||||
* This method is only called for columns of type other than |text|.
|
||||
*/
|
||||
void setCellValue(in long row, in nsITreeColumn col, in AString value);
|
||||
|
||||
/**
|
||||
* setCellText is called when the contents of the cell have been edited by the user.
|
||||
*/
|
||||
void setCellText(in long row, in nsITreeColumn col, in AString value);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on the selection. The tree
|
||||
* will automatically invoke this method when certain keys are pressed. For example,
|
||||
* when the DEL key is pressed, performAction will be called with the "delete" string.
|
||||
*/
|
||||
void performAction(in wstring action);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific row.
|
||||
*/
|
||||
void performActionOnRow(in wstring action, in long row);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific cell.
|
||||
*/
|
||||
void performActionOnCell(in wstring action, in long row, in nsITreeColumn col);
|
||||
};
|
||||
|
||||
/**
|
||||
* The following interface is not scriptable and MUST NEVER BE MADE scriptable.
|
||||
* Native treeviews implement it, and we use this to check whether a treeview
|
||||
* is native (and therefore suitable for use by untrusted content).
|
||||
*/
|
||||
[uuid(46c90265-6553-41ae-8d39-7022e7d09145)]
|
||||
interface nsINativeTreeView : nsITreeView
|
||||
{
|
||||
[noscript] void ensureNative();
|
||||
};
|
||||
4945
layout/xul/tree/nsTreeBodyFrame.cpp
Normal file
4945
layout/xul/tree/nsTreeBodyFrame.cpp
Normal file
File diff suppressed because it is too large
Load diff
651
layout/xul/tree/nsTreeBodyFrame.h
Normal file
651
layout/xul/tree/nsTreeBodyFrame.h
Normal file
|
|
@ -0,0 +1,651 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsTreeBodyFrame_h
|
||||
#define nsTreeBodyFrame_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsLeafBoxFrame.h"
|
||||
#include "nsITreeView.h"
|
||||
#include "nsICSSPseudoComparator.h"
|
||||
#include "nsIScrollbarMediator.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIReflowCallback.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTreeStyleCache.h"
|
||||
#include "nsTreeColumns.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "nsScrollbarFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
|
||||
class nsFontMetrics;
|
||||
class nsOverflowChecker;
|
||||
class nsTreeImageListener;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layout {
|
||||
class ScrollbarActivity;
|
||||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
|
||||
// An entry in the tree's image cache
|
||||
struct nsTreeImageCacheEntry
|
||||
{
|
||||
nsTreeImageCacheEntry() {}
|
||||
nsTreeImageCacheEntry(imgIRequest *aRequest, imgINotificationObserver *aListener)
|
||||
: request(aRequest), listener(aListener) {}
|
||||
|
||||
nsCOMPtr<imgIRequest> request;
|
||||
nsCOMPtr<imgINotificationObserver> listener;
|
||||
};
|
||||
|
||||
// The actual frame that paints the cells and rows.
|
||||
class nsTreeBodyFrame final
|
||||
: public nsLeafBoxFrame
|
||||
, public nsICSSPseudoComparator
|
||||
, public nsIScrollbarMediator
|
||||
, public nsIReflowCallback
|
||||
{
|
||||
typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
|
||||
typedef mozilla::image::DrawResult DrawResult;
|
||||
|
||||
public:
|
||||
explicit nsTreeBodyFrame(nsStyleContext* aContext);
|
||||
~nsTreeBodyFrame();
|
||||
|
||||
NS_DECL_QUERYFRAME_TARGET(nsTreeBodyFrame)
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
// Callback handler methods for refresh driver based animations.
|
||||
// Calls to these functions are forwarded from nsTreeImageListener. These
|
||||
// mirror how nsImageFrame works.
|
||||
nsresult OnImageIsAnimated(imgIRequest* aRequest);
|
||||
|
||||
// non-virtual signatures like nsITreeBodyFrame
|
||||
already_AddRefed<nsTreeColumns> Columns() const
|
||||
{
|
||||
RefPtr<nsTreeColumns> cols = mColumns;
|
||||
return cols.forget();
|
||||
}
|
||||
already_AddRefed<nsITreeView> GetExistingView() const
|
||||
{
|
||||
nsCOMPtr<nsITreeView> view = mView;
|
||||
return view.forget();
|
||||
}
|
||||
nsresult GetView(nsITreeView **aView);
|
||||
nsresult SetView(nsITreeView *aView);
|
||||
bool GetFocused() const { return mFocused; }
|
||||
nsresult SetFocused(bool aFocused);
|
||||
nsresult GetTreeBody(nsIDOMElement **aElement);
|
||||
int32_t RowHeight() const;
|
||||
int32_t RowWidth();
|
||||
int32_t GetHorizontalPosition() const;
|
||||
nsresult GetSelectionRegion(nsIScriptableRegion **aRegion);
|
||||
int32_t FirstVisibleRow() const { return mTopRowIndex; }
|
||||
int32_t LastVisibleRow() const { return mTopRowIndex + mPageLength; }
|
||||
int32_t PageLength() const { return mPageLength; }
|
||||
nsresult EnsureRowIsVisible(int32_t aRow);
|
||||
nsresult EnsureCellIsVisible(int32_t aRow, nsITreeColumn *aCol);
|
||||
nsresult ScrollToRow(int32_t aRow);
|
||||
nsresult ScrollByLines(int32_t aNumLines);
|
||||
nsresult ScrollByPages(int32_t aNumPages);
|
||||
nsresult ScrollToCell(int32_t aRow, nsITreeColumn *aCol);
|
||||
nsresult ScrollToColumn(nsITreeColumn *aCol);
|
||||
nsresult ScrollToHorizontalPosition(int32_t aValue);
|
||||
nsresult Invalidate();
|
||||
nsresult InvalidateColumn(nsITreeColumn *aCol);
|
||||
nsresult InvalidateRow(int32_t aRow);
|
||||
nsresult InvalidateCell(int32_t aRow, nsITreeColumn *aCol);
|
||||
nsresult InvalidateRange(int32_t aStart, int32_t aEnd);
|
||||
nsresult InvalidateColumnRange(int32_t aStart, int32_t aEnd,
|
||||
nsITreeColumn *aCol);
|
||||
nsresult GetRowAt(int32_t aX, int32_t aY, int32_t *aValue);
|
||||
nsresult GetCellAt(int32_t aX, int32_t aY, int32_t *aRow,
|
||||
nsITreeColumn **aCol, nsACString &aChildElt);
|
||||
nsresult GetCoordsForCellItem(int32_t aRow, nsITreeColumn *aCol,
|
||||
const nsACString &aElt,
|
||||
int32_t *aX, int32_t *aY,
|
||||
int32_t *aWidth, int32_t *aHeight);
|
||||
nsresult IsCellCropped(int32_t aRow, nsITreeColumn *aCol, bool *aResult);
|
||||
nsresult RowCountChanged(int32_t aIndex, int32_t aCount);
|
||||
nsresult BeginUpdateBatch();
|
||||
nsresult EndUpdateBatch();
|
||||
nsresult ClearStyleAndImageCaches();
|
||||
|
||||
void CancelImageRequests();
|
||||
|
||||
void ManageReflowCallback(const nsRect& aRect, nscoord aHorzWidth);
|
||||
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
|
||||
bool aRemoveOverflowArea = false) override;
|
||||
|
||||
// nsIReflowCallback
|
||||
virtual bool ReflowFinished() override;
|
||||
virtual void ReflowCallbackCanceled() override;
|
||||
|
||||
// nsICSSPseudoComparator
|
||||
virtual bool PseudoMatches(nsCSSSelector* aSelector) override;
|
||||
|
||||
// nsIScrollbarMediator
|
||||
virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
||||
nsIScrollbarMediator::ScrollSnapMode aSnap
|
||||
= nsIScrollbarMediator::DISABLE_SNAP) override;
|
||||
virtual void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
||||
nsIScrollbarMediator::ScrollSnapMode aSnap
|
||||
= nsIScrollbarMediator::DISABLE_SNAP) override;
|
||||
virtual void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
||||
nsIScrollbarMediator::ScrollSnapMode aSnap
|
||||
= nsIScrollbarMediator::DISABLE_SNAP) override;
|
||||
virtual void RepeatButtonScroll(nsScrollbarFrame* aScrollbar) override;
|
||||
virtual void ThumbMoved(nsScrollbarFrame* aScrollbar,
|
||||
nscoord aOldPos,
|
||||
nscoord aNewPos) override;
|
||||
virtual void ScrollbarReleased(nsScrollbarFrame* aScrollbar) override {}
|
||||
virtual void VisibilityChanged(bool aVisible) override { Invalidate(); }
|
||||
virtual nsIFrame* GetScrollbarBox(bool aVertical) override {
|
||||
ScrollParts parts = GetScrollParts();
|
||||
return aVertical ? parts.mVScrollbar : parts.mHScrollbar;
|
||||
}
|
||||
virtual void ScrollbarActivityStarted() const override;
|
||||
virtual void ScrollbarActivityStopped() const override;
|
||||
virtual bool IsScrollbarOnRight() const override {
|
||||
return (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR);
|
||||
}
|
||||
virtual bool ShouldSuppressScrollbarRepaints() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Overridden from nsIFrame to cache our pres context.
|
||||
virtual void Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow) override;
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
virtual nsresult GetCursor(const nsPoint& aPoint,
|
||||
nsIFrame::Cursor& aCursor) override;
|
||||
|
||||
virtual nsresult HandleEvent(nsPresContext* aPresContext,
|
||||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) override;
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
|
||||
|
||||
friend nsIFrame* NS_NewTreeBodyFrame(nsIPresShell* aPresShell);
|
||||
friend class nsTreeColumn;
|
||||
|
||||
struct ScrollParts {
|
||||
nsScrollbarFrame* mVScrollbar;
|
||||
nsCOMPtr<nsIContent> mVScrollbarContent;
|
||||
nsScrollbarFrame* mHScrollbar;
|
||||
nsCOMPtr<nsIContent> mHScrollbarContent;
|
||||
nsIFrame* mColumnsFrame;
|
||||
nsIScrollableFrame* mColumnsScrollFrame;
|
||||
};
|
||||
|
||||
DrawResult PaintTreeBody(nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect, nsPoint aPt);
|
||||
|
||||
nsITreeBoxObject* GetTreeBoxObject() const { return mTreeBoxObject; }
|
||||
|
||||
// Get the base element, <tree> or <select>
|
||||
nsIContent* GetBaseElement();
|
||||
|
||||
bool GetVerticalOverflow() const { return mVerticalOverflow; }
|
||||
bool GetHorizontalOverflow() const {return mHorizontalOverflow; }
|
||||
|
||||
protected:
|
||||
friend class nsOverflowChecker;
|
||||
|
||||
// This method paints a specific column background of the tree.
|
||||
DrawResult PaintColumn(nsTreeColumn* aColumn,
|
||||
const nsRect& aColumnRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// This method paints a single row in the tree.
|
||||
DrawResult PaintRow(int32_t aRowIndex,
|
||||
const nsRect& aRowRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt);
|
||||
|
||||
// This method paints a single separator in the tree.
|
||||
DrawResult PaintSeparator(int32_t aRowIndex,
|
||||
const nsRect& aSeparatorRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// This method paints a specific cell in a given row of the tree.
|
||||
DrawResult PaintCell(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aCellRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nscoord& aCurrX,
|
||||
nsPoint aPt);
|
||||
|
||||
// This method paints the twisty inside a cell in the primary column of an tree.
|
||||
DrawResult PaintTwisty(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aTwistyRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nscoord& aRemainingWidth,
|
||||
nscoord& aCurrX);
|
||||
|
||||
// This method paints the image inside the cell of an tree.
|
||||
DrawResult PaintImage(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aImageRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nscoord& aRemainingWidth,
|
||||
nscoord& aCurrX);
|
||||
|
||||
// This method paints the text string inside a particular cell of the tree.
|
||||
DrawResult PaintText(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aTextRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nscoord& aCurrX);
|
||||
|
||||
// This method paints the checkbox inside a particular cell of the tree.
|
||||
DrawResult PaintCheckbox(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aCheckboxRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// This method paints the progress meter inside a particular cell of the tree.
|
||||
DrawResult PaintProgressMeter(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
const nsRect& aProgressMeterRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// This method paints a drop feedback of the tree.
|
||||
DrawResult PaintDropFeedback(const nsRect& aDropFeedbackRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt);
|
||||
|
||||
// This method is called with a specific style context and rect to
|
||||
// paint the background rect as if it were a full-blown frame.
|
||||
DrawResult PaintBackgroundLayer(nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
|
||||
// An internal hit test. aX and aY are expected to be in twips in the
|
||||
// coordinate system of this frame.
|
||||
int32_t GetRowAt(nscoord aX, nscoord aY);
|
||||
|
||||
// Check for bidi characters in the text, and if there are any, ensure
|
||||
// that the prescontext is in bidi mode.
|
||||
void CheckTextForBidi(nsAutoString& aText);
|
||||
|
||||
void AdjustForCellText(nsAutoString& aText,
|
||||
int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
nsFontMetrics& aFontMetrics,
|
||||
nsRect& aTextRect);
|
||||
|
||||
// A helper used when hit testing.
|
||||
nsIAtom* GetItemWithinCellAt(nscoord aX, const nsRect& aCellRect,
|
||||
int32_t aRowIndex, nsTreeColumn* aColumn);
|
||||
|
||||
// An internal hit test. aX and aY are expected to be in twips in the
|
||||
// coordinate system of this frame.
|
||||
void GetCellAt(nscoord aX, nscoord aY, int32_t* aRow, nsTreeColumn** aCol,
|
||||
nsIAtom** aChildElt);
|
||||
|
||||
// Retrieve the area for the twisty for a cell.
|
||||
nsITheme* GetTwistyRect(int32_t aRowIndex,
|
||||
nsTreeColumn* aColumn,
|
||||
nsRect& aImageRect,
|
||||
nsRect& aTwistyRect,
|
||||
nsPresContext* aPresContext,
|
||||
nsStyleContext* aTwistyContext);
|
||||
|
||||
// Fetch an image from the image cache.
|
||||
nsresult GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContext,
|
||||
nsStyleContext* aStyleContext, bool& aAllowImageRegions, imgIContainer** aResult);
|
||||
|
||||
// Returns the size of a given image. This size *includes* border and
|
||||
// padding. It does not include margins.
|
||||
nsRect GetImageSize(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContext, nsStyleContext* aStyleContext);
|
||||
|
||||
// Returns the destination size of the image, not including borders and padding.
|
||||
nsSize GetImageDestSize(nsStyleContext* aStyleContext, bool useImageRegion, imgIContainer* image);
|
||||
|
||||
// Returns the source rectangle of the image to be displayed.
|
||||
nsRect GetImageSourceRect(nsStyleContext* aStyleContext, bool useImageRegion, imgIContainer* image);
|
||||
|
||||
// Returns the height of rows in the tree.
|
||||
int32_t GetRowHeight();
|
||||
|
||||
// Returns our indentation width.
|
||||
int32_t GetIndentation();
|
||||
|
||||
// Calculates our width/height once border and padding have been removed.
|
||||
void CalcInnerBox();
|
||||
|
||||
// Calculate the total width of our scrollable portion
|
||||
nscoord CalcHorzWidth(const ScrollParts& aParts);
|
||||
|
||||
// Looks up a style context in the style cache. On a cache miss we resolve
|
||||
// the pseudo-styles passed in and place them into the cache.
|
||||
nsStyleContext* GetPseudoStyleContext(nsIAtom* aPseudoElement);
|
||||
|
||||
// Retrieves the scrollbars and scrollview relevant to this treebody. We
|
||||
// traverse the frame tree under our base element, in frame order, looking
|
||||
// for the first relevant vertical scrollbar, horizontal scrollbar, and
|
||||
// scrollable frame (with associated content and scrollable view). These
|
||||
// are all volatile and should not be retained.
|
||||
ScrollParts GetScrollParts();
|
||||
|
||||
// Update the curpos of the scrollbar.
|
||||
void UpdateScrollbars(const ScrollParts& aParts);
|
||||
|
||||
// Update the maxpos of the scrollbar.
|
||||
void InvalidateScrollbars(const ScrollParts& aParts, nsWeakFrame& aWeakColumnsFrame);
|
||||
|
||||
// Check overflow and generate events.
|
||||
void CheckOverflow(const ScrollParts& aParts);
|
||||
|
||||
// Calls UpdateScrollbars, Invalidate aNeedsFullInvalidation if true,
|
||||
// InvalidateScrollbars and finally CheckOverflow.
|
||||
// returns true if the frame is still alive after the method call.
|
||||
bool FullScrollbarsUpdate(bool aNeedsFullInvalidation);
|
||||
|
||||
// Use to auto-fill some of the common properties without the view having to do it.
|
||||
// Examples include container, open, selected, and focus.
|
||||
void PrefillPropertyArray(int32_t aRowIndex, nsTreeColumn* aCol);
|
||||
|
||||
// Our internal scroll method, used by all the public scroll methods.
|
||||
nsresult ScrollInternal(const ScrollParts& aParts, int32_t aRow);
|
||||
nsresult ScrollToRowInternal(const ScrollParts& aParts, int32_t aRow);
|
||||
nsresult ScrollToColumnInternal(const ScrollParts& aParts, nsITreeColumn* aCol);
|
||||
nsresult ScrollHorzInternal(const ScrollParts& aParts, int32_t aPosition);
|
||||
nsresult EnsureRowIsVisibleInternal(const ScrollParts& aParts, int32_t aRow);
|
||||
|
||||
// Convert client pixels into appunits in our coordinate space.
|
||||
nsPoint AdjustClientCoordsToBoxCoordSpace(int32_t aX, int32_t aY);
|
||||
|
||||
// Cache the box object
|
||||
void EnsureBoxObject();
|
||||
|
||||
void EnsureView();
|
||||
|
||||
nsresult GetCellWidth(int32_t aRow, nsTreeColumn* aCol,
|
||||
nsRenderingContext* aRenderingContext,
|
||||
nscoord& aDesiredSize, nscoord& aCurrentSize);
|
||||
nscoord CalcMaxRowWidth();
|
||||
|
||||
// Translate the given rect horizontally from tree coordinates into the
|
||||
// coordinate system of our nsTreeBodyFrame. If clip is true, then clip the
|
||||
// rect to its intersection with mInnerBox in the horizontal direction.
|
||||
// Return whether the result has a nonempty intersection with mInnerBox
|
||||
// after projecting both onto the horizontal coordinate axis.
|
||||
bool OffsetForHorzScroll(nsRect& rect, bool clip);
|
||||
|
||||
bool CanAutoScroll(int32_t aRowIndex);
|
||||
|
||||
// Calc the row and above/below/on status given where the mouse currently is hovering.
|
||||
// Also calc if we're in the region in which we want to auto-scroll the tree.
|
||||
// A positive value of |aScrollLines| means scroll down, a negative value
|
||||
// means scroll up, a zero value means that we aren't in drag scroll region.
|
||||
void ComputeDropPosition(mozilla::WidgetGUIEvent* aEvent,
|
||||
int32_t* aRow,
|
||||
int16_t* aOrient,
|
||||
int16_t* aScrollLines);
|
||||
|
||||
// Mark ourselves dirty if we're a select widget
|
||||
void MarkDirtyIfSelect();
|
||||
|
||||
void InvalidateDropFeedback(int32_t aRow, int16_t aOrientation) {
|
||||
InvalidateRow(aRow);
|
||||
if (aOrientation != nsITreeView::DROP_ON)
|
||||
InvalidateRow(aRow + aOrientation);
|
||||
}
|
||||
|
||||
public:
|
||||
static
|
||||
already_AddRefed<nsTreeColumn> GetColumnImpl(nsITreeColumn* aUnknownCol) {
|
||||
if (!aUnknownCol)
|
||||
return nullptr;
|
||||
|
||||
nsCOMPtr<nsTreeColumn> col = do_QueryInterface(aUnknownCol);
|
||||
return col.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an nsITreeImageListener from being tracked by this frame. Only tree
|
||||
* image listeners that are created by this frame are tracked.
|
||||
*
|
||||
* @param aListener A pointer to an nsTreeImageListener to no longer
|
||||
* track.
|
||||
*/
|
||||
void RemoveTreeImageListener(nsTreeImageListener* aListener);
|
||||
|
||||
protected:
|
||||
|
||||
// Create a new timer. This method is used to delay various actions like
|
||||
// opening/closing folders or tree scrolling.
|
||||
// aID is type of the action, aFunc is the function to be called when
|
||||
// the timer fires and aType is type of timer - one shot or repeating.
|
||||
nsresult CreateTimer(const mozilla::LookAndFeel::IntID aID,
|
||||
nsTimerCallbackFunc aFunc, int32_t aType,
|
||||
nsITimer** aTimer);
|
||||
|
||||
static void OpenCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
static void CloseCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
static void LazyScrollCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
static void ScrollCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
class ScrollEvent : public mozilla::Runnable {
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
explicit ScrollEvent(nsTreeBodyFrame *aInner) : mInner(aInner) {}
|
||||
void Revoke() { mInner = nullptr; }
|
||||
private:
|
||||
nsTreeBodyFrame* mInner;
|
||||
};
|
||||
|
||||
void PostScrollEvent();
|
||||
void FireScrollEvent();
|
||||
|
||||
/**
|
||||
* Clear the pointer to this frame for all nsTreeImageListeners that were
|
||||
* created by this frame.
|
||||
*/
|
||||
void DetachImageListeners();
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
/**
|
||||
* Fires 'treeRowCountChanged' event asynchronously. The event supports
|
||||
* nsIDOMCustomEvent interface that is used to expose the following
|
||||
* information structures.
|
||||
*
|
||||
* @param aIndex the row index rows are added/removed from
|
||||
* @param aCount the number of added/removed rows (the sign points to
|
||||
* an operation, plus - addition, minus - removing)
|
||||
*/
|
||||
void FireRowCountChangedEvent(int32_t aIndex, int32_t aCount);
|
||||
|
||||
/**
|
||||
* Fires 'treeInvalidated' event asynchronously. The event supports
|
||||
* nsIDOMCustomEvent interface that is used to expose the information
|
||||
* structures described by method arguments.
|
||||
*
|
||||
* @param aStartRow the start index of invalidated rows, -1 means that
|
||||
* columns have been invalidated only
|
||||
* @param aEndRow the end index of invalidated rows, -1 means that columns
|
||||
* have been invalidated only
|
||||
* @param aStartCol the start invalidated column, nullptr means that only rows
|
||||
* have been invalidated
|
||||
* @param aEndCol the end invalidated column, nullptr means that rows have
|
||||
* been invalidated only
|
||||
*/
|
||||
void FireInvalidateEvent(int32_t aStartRow, int32_t aEndRow,
|
||||
nsITreeColumn *aStartCol, nsITreeColumn *aEndCol);
|
||||
#endif
|
||||
|
||||
protected: // Data Members
|
||||
|
||||
class Slots {
|
||||
public:
|
||||
Slots() {
|
||||
}
|
||||
|
||||
~Slots() {
|
||||
if (mTimer)
|
||||
mTimer->Cancel();
|
||||
}
|
||||
|
||||
friend class nsTreeBodyFrame;
|
||||
|
||||
protected:
|
||||
// If the drop is actually allowed here or not.
|
||||
bool mDropAllowed;
|
||||
|
||||
// True while dragging over the tree.
|
||||
bool mIsDragging;
|
||||
|
||||
// The row the mouse is hovering over during a drop.
|
||||
int32_t mDropRow;
|
||||
|
||||
// Where we want to draw feedback (above/on this row/below) if allowed.
|
||||
int16_t mDropOrient;
|
||||
|
||||
// Number of lines to be scrolled.
|
||||
int16_t mScrollLines;
|
||||
|
||||
// The drag action that was received for this slot
|
||||
uint32_t mDragAction;
|
||||
|
||||
// Timer for opening/closing spring loaded folders or scrolling the tree.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
// An array used to keep track of all spring loaded folders.
|
||||
nsTArray<int32_t> mArray;
|
||||
};
|
||||
|
||||
Slots* mSlots;
|
||||
|
||||
nsRevocableEventPtr<ScrollEvent> mScrollEvent;
|
||||
|
||||
RefPtr<ScrollbarActivity> mScrollbarActivity;
|
||||
|
||||
// The cached box object parent.
|
||||
nsCOMPtr<nsITreeBoxObject> mTreeBoxObject;
|
||||
|
||||
// Cached column information.
|
||||
RefPtr<nsTreeColumns> mColumns;
|
||||
|
||||
// The current view for this tree widget. We get all of our row and cell data
|
||||
// from the view.
|
||||
nsCOMPtr<nsITreeView> mView;
|
||||
|
||||
// A cache of all the style contexts we have seen for rows and cells of the tree. This is a mapping from
|
||||
// a list of atoms to a corresponding style context. This cache stores every combination that
|
||||
// occurs in the tree, so for n distinct properties, this cache could have 2 to the n entries
|
||||
// (the power set of all row properties).
|
||||
nsTreeStyleCache mStyleCache;
|
||||
|
||||
// A hashtable that maps from URLs to image request/listener pairs. The URL
|
||||
// is provided by the view or by the style context. The style context
|
||||
// represents a resolved :-moz-tree-cell-image (or twisty) pseudo-element.
|
||||
// It maps directly to an imgIRequest.
|
||||
nsDataHashtable<nsStringHashKey, nsTreeImageCacheEntry> mImageCache;
|
||||
|
||||
// A scratch array used when looking up cached style contexts.
|
||||
AtomArray mScratchArray;
|
||||
|
||||
// The index of the first visible row and the # of rows visible onscreen.
|
||||
// The tree only examines onscreen rows, starting from
|
||||
// this index and going up to index+pageLength.
|
||||
int32_t mTopRowIndex;
|
||||
int32_t mPageLength;
|
||||
|
||||
// The horizontal scroll position
|
||||
nscoord mHorzPosition;
|
||||
|
||||
// The original desired horizontal width before changing it and posting a
|
||||
// reflow callback. In some cases, the desired horizontal width can first be
|
||||
// different from the current desired horizontal width, only to return to
|
||||
// the same value later during the same reflow. In this case, we can cancel
|
||||
// the posted reflow callback and prevent an unnecessary reflow.
|
||||
nscoord mOriginalHorzWidth;
|
||||
// Our desired horizontal width (the width for which we actually have tree
|
||||
// columns).
|
||||
nscoord mHorzWidth;
|
||||
// The amount by which to adjust the width of the last cell.
|
||||
// This depends on whether or not the columnpicker and scrollbars are present.
|
||||
nscoord mAdjustWidth;
|
||||
|
||||
// Cached heights and indent info.
|
||||
nsRect mInnerBox; // 4-byte aligned
|
||||
int32_t mRowHeight;
|
||||
int32_t mIndentation;
|
||||
nscoord mStringWidth;
|
||||
|
||||
int32_t mUpdateBatchNest;
|
||||
|
||||
// Cached row count.
|
||||
int32_t mRowCount;
|
||||
|
||||
// The row the mouse is hovering over.
|
||||
int32_t mMouseOverRow;
|
||||
|
||||
// Whether or not we're currently focused.
|
||||
bool mFocused;
|
||||
|
||||
// Do we have a fixed number of onscreen rows?
|
||||
bool mHasFixedRowCount;
|
||||
|
||||
bool mVerticalOverflow;
|
||||
bool mHorizontalOverflow;
|
||||
|
||||
bool mReflowCallbackPosted;
|
||||
|
||||
// Set while we flush layout to take account of effects of
|
||||
// overflow/underflow event handlers
|
||||
bool mCheckingOverflow;
|
||||
|
||||
// Hash table to keep track of which listeners we created and thus
|
||||
// have pointers to us.
|
||||
nsTHashtable<nsPtrHashKey<nsTreeImageListener> > mCreatedListeners;
|
||||
|
||||
}; // class nsTreeBodyFrame
|
||||
|
||||
#endif
|
||||
201
layout/xul/tree/nsTreeColFrame.cpp
Normal file
201
layout/xul/tree/nsTreeColFrame.cpp
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsCOMPtr.h"
|
||||
#include "nsTreeColFrame.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsIBoxObject.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsITreeColumns.h"
|
||||
#include "nsIDOMXULTreeElement.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsTreeBodyFrame.h"
|
||||
|
||||
//
|
||||
// NS_NewTreeColFrame
|
||||
//
|
||||
// Creates a new col frame
|
||||
//
|
||||
nsIFrame*
|
||||
NS_NewTreeColFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsTreeColFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsTreeColFrame)
|
||||
|
||||
// Destructor
|
||||
nsTreeColFrame::~nsTreeColFrame()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColFrame::Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
||||
InvalidateColumns();
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
InvalidateColumns(false);
|
||||
nsBoxFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
class nsDisplayXULTreeColSplitterTarget : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayXULTreeColSplitterTarget(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame) :
|
||||
nsDisplayItem(aBuilder, aFrame) {
|
||||
MOZ_COUNT_CTOR(nsDisplayXULTreeColSplitterTarget);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayXULTreeColSplitterTarget() {
|
||||
MOZ_COUNT_DTOR(nsDisplayXULTreeColSplitterTarget);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState,
|
||||
nsTArray<nsIFrame*> *aOutFrames) override;
|
||||
NS_DISPLAY_DECL_NAME("XULTreeColSplitterTarget", TYPE_XUL_TREE_COL_SPLITTER_TARGET)
|
||||
};
|
||||
|
||||
void
|
||||
nsDisplayXULTreeColSplitterTarget::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
|
||||
{
|
||||
nsRect rect = aRect - ToReferenceFrame();
|
||||
// If we are in either in the first 4 pixels or the last 4 pixels, we're going to
|
||||
// do something really strange. Check for an adjacent splitter.
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
if (mFrame->GetSize().width - nsPresContext::CSSPixelsToAppUnits(4) <= rect.XMost()) {
|
||||
right = true;
|
||||
} else if (nsPresContext::CSSPixelsToAppUnits(4) > rect.x) {
|
||||
left = true;
|
||||
}
|
||||
|
||||
// Swap left and right for RTL trees in order to find the correct splitter
|
||||
if (mFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
|
||||
bool tmp = left;
|
||||
left = right;
|
||||
right = tmp;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
// We are a header. Look for the correct splitter.
|
||||
nsIFrame* child;
|
||||
if (left)
|
||||
child = mFrame->GetPrevSibling();
|
||||
else
|
||||
child = mFrame->GetNextSibling();
|
||||
|
||||
if (child && child->GetContent()->NodeInfo()->Equals(nsGkAtoms::splitter,
|
||||
kNameSpaceID_XUL)) {
|
||||
aOutFrames->AppendElement(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
if (!aBuilder->IsForEventDelivery()) {
|
||||
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
|
||||
return;
|
||||
}
|
||||
|
||||
nsDisplayListCollection set;
|
||||
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, set);
|
||||
|
||||
WrapListsInRedirector(aBuilder, set, aLists);
|
||||
|
||||
aLists.Content()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayXULTreeColSplitterTarget(aBuilder, this));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeColFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
||||
aModType);
|
||||
|
||||
if (aAttribute == nsGkAtoms::ordinal || aAttribute == nsGkAtoms::primary) {
|
||||
InvalidateColumns();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColFrame::SetXULBounds(nsBoxLayoutState& aBoxLayoutState,
|
||||
const nsRect& aRect,
|
||||
bool aRemoveOverflowArea)
|
||||
{
|
||||
nscoord oldWidth = mRect.width;
|
||||
|
||||
nsBoxFrame::SetXULBounds(aBoxLayoutState, aRect, aRemoveOverflowArea);
|
||||
if (mRect.width != oldWidth) {
|
||||
nsITreeBoxObject* treeBoxObject = GetTreeBoxObject();
|
||||
if (treeBoxObject) {
|
||||
treeBoxObject->Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsITreeBoxObject*
|
||||
nsTreeColFrame::GetTreeBoxObject()
|
||||
{
|
||||
nsITreeBoxObject* result = nullptr;
|
||||
|
||||
nsIContent* parent = mContent->GetParent();
|
||||
if (parent) {
|
||||
nsIContent* grandParent = parent->GetParent();
|
||||
nsCOMPtr<nsIDOMXULElement> treeElement = do_QueryInterface(grandParent);
|
||||
if (treeElement) {
|
||||
nsCOMPtr<nsIBoxObject> boxObject;
|
||||
treeElement->GetBoxObject(getter_AddRefs(boxObject));
|
||||
|
||||
nsCOMPtr<nsITreeBoxObject> treeBoxObject = do_QueryInterface(boxObject);
|
||||
result = treeBoxObject.get();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColFrame::InvalidateColumns(bool aCanWalkFrameTree)
|
||||
{
|
||||
nsITreeBoxObject* treeBoxObject = GetTreeBoxObject();
|
||||
if (treeBoxObject) {
|
||||
nsCOMPtr<nsITreeColumns> columns;
|
||||
|
||||
if (aCanWalkFrameTree) {
|
||||
treeBoxObject->GetColumns(getter_AddRefs(columns));
|
||||
} else {
|
||||
nsTreeBodyFrame* body = static_cast<mozilla::dom::TreeBoxObject*>
|
||||
(treeBoxObject)->GetCachedTreeBodyFrame();
|
||||
if (body) {
|
||||
columns = body->Columns();
|
||||
}
|
||||
}
|
||||
|
||||
if (columns)
|
||||
columns->InvalidateColumns();
|
||||
}
|
||||
}
|
||||
55
layout/xul/tree/nsTreeColFrame.h
Normal file
55
layout/xul/tree/nsTreeColFrame.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/Attributes.h"
|
||||
#include "nsBoxFrame.h"
|
||||
|
||||
class nsITreeBoxObject;
|
||||
|
||||
nsIFrame* NS_NewTreeColFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
|
||||
class nsTreeColFrame : public nsBoxFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
explicit nsTreeColFrame(nsStyleContext* aContext):
|
||||
nsBoxFrame(aContext) {}
|
||||
|
||||
virtual void Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow) override;
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
virtual void BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
|
||||
virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
|
||||
bool aRemoveOverflowArea = false) override;
|
||||
|
||||
friend nsIFrame* NS_NewTreeColFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
|
||||
protected:
|
||||
virtual ~nsTreeColFrame();
|
||||
|
||||
/**
|
||||
* @return the tree box object of the tree this column belongs to, or nullptr.
|
||||
*/
|
||||
nsITreeBoxObject* GetTreeBoxObject();
|
||||
|
||||
/**
|
||||
* Helper method that gets the nsITreeColumns object this column belongs to
|
||||
* and calls InvalidateColumns() on it.
|
||||
*/
|
||||
void InvalidateColumns(bool aCanWalkFrameTree = true);
|
||||
};
|
||||
765
layout/xul/tree/nsTreeColumns.cpp
Normal file
765
layout/xul/tree/nsTreeColumns.cpp
Normal file
|
|
@ -0,0 +1,765 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsNameSpaceManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIBoxObject.h"
|
||||
#include "nsTreeColumns.h"
|
||||
#include "nsTreeUtils.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTreeBodyFrame.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "mozilla/dom/TreeColumnBinding.h"
|
||||
#include "mozilla/dom/TreeColumnsBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// Column class that caches all the info about our column.
|
||||
nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent)
|
||||
: mContent(aContent),
|
||||
mColumns(aColumns),
|
||||
mPrevious(nullptr)
|
||||
{
|
||||
NS_ASSERTION(aContent &&
|
||||
aContent->NodeInfo()->Equals(nsGkAtoms::treecol,
|
||||
kNameSpaceID_XUL),
|
||||
"nsTreeColumn's content must be a <xul:treecol>");
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
nsTreeColumn::~nsTreeColumn()
|
||||
{
|
||||
if (mNext) {
|
||||
mNext->SetPrevious(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsTreeColumn)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTreeColumn)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
|
||||
if (tmp->mNext) {
|
||||
tmp->mNext->SetPrevious(nullptr);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNext)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTreeColumn)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsTreeColumn)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumn)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumn)
|
||||
|
||||
// QueryInterface implementation for nsTreeColumn
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumn)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsITreeColumn)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
if (aIID.Equals(NS_GET_IID(nsTreeColumn))) {
|
||||
AddRef();
|
||||
*aInstancePtr = this;
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsIFrame*
|
||||
nsTreeColumn::GetFrame()
|
||||
{
|
||||
NS_ENSURE_TRUE(mContent, nullptr);
|
||||
|
||||
return mContent->GetPrimaryFrame();
|
||||
}
|
||||
|
||||
bool
|
||||
nsTreeColumn::IsLastVisible(nsTreeBodyFrame* aBodyFrame)
|
||||
{
|
||||
NS_ASSERTION(GetFrame(), "should have checked for this already");
|
||||
|
||||
// cyclers are fixed width, don't adjust them
|
||||
if (IsCycler())
|
||||
return false;
|
||||
|
||||
// we're certainly not the last visible if we're not visible
|
||||
if (GetFrame()->GetRect().width == 0)
|
||||
return false;
|
||||
|
||||
// try to find a visible successor
|
||||
for (nsTreeColumn *next = GetNext(); next; next = next->GetNext()) {
|
||||
nsIFrame* frame = next->GetFrame();
|
||||
if (frame && frame->GetRect().width > 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeColumn::GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult)
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame) {
|
||||
*aResult = nsRect();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool isRTL = aBodyFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
|
||||
*aResult = frame->GetRect();
|
||||
aResult->y = aY;
|
||||
aResult->height = aHeight;
|
||||
if (isRTL)
|
||||
aResult->x += aBodyFrame->mAdjustWidth;
|
||||
else if (IsLastVisible(aBodyFrame))
|
||||
aResult->width += aBodyFrame->mAdjustWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeColumn::GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame) {
|
||||
*aResult = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aResult = frame->GetRect().x;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeColumn::GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame) {
|
||||
*aResult = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aResult = frame->GetRect().width;
|
||||
if (IsLastVisible(aBodyFrame))
|
||||
*aResult += aBodyFrame->mAdjustWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetElement(nsIDOMElement** aElement)
|
||||
{
|
||||
if (mContent) {
|
||||
return CallQueryInterface(mContent, aElement);
|
||||
}
|
||||
*aElement = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetColumns(nsITreeColumns** aColumns)
|
||||
{
|
||||
NS_IF_ADDREF(*aColumns = mColumns);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetX(int32_t* aX)
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
*aX = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetWidth(int32_t* aWidth)
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
*aWidth = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetId(nsAString& aId)
|
||||
{
|
||||
aId = GetId();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetIdConst(const char16_t** aIdConst)
|
||||
{
|
||||
*aIdConst = mId.get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetAtom(nsIAtom** aAtom)
|
||||
{
|
||||
NS_IF_ADDREF(*aAtom = GetAtom());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetIndex(int32_t* aIndex)
|
||||
{
|
||||
*aIndex = GetIndex();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetPrimary(bool* aPrimary)
|
||||
{
|
||||
*aPrimary = IsPrimary();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetCycler(bool* aCycler)
|
||||
{
|
||||
*aCycler = IsCycler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetEditable(bool* aEditable)
|
||||
{
|
||||
*aEditable = IsEditable();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetSelectable(bool* aSelectable)
|
||||
{
|
||||
*aSelectable = IsSelectable();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetType(int16_t* aType)
|
||||
{
|
||||
*aType = GetType();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetNext(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetNext());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetPrevious());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumn::Invalidate()
|
||||
{
|
||||
nsIFrame* frame = GetFrame();
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
// Fetch the Id.
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
|
||||
|
||||
// If we have an Id, cache the Id as an atom.
|
||||
if (!mId.IsEmpty()) {
|
||||
mAtom = NS_Atomize(mId);
|
||||
}
|
||||
|
||||
// Cache our index.
|
||||
nsTreeUtils::GetColumnIndex(mContent, &mIndex);
|
||||
|
||||
const nsStyleVisibility* vis = frame->StyleVisibility();
|
||||
|
||||
// Cache our text alignment policy.
|
||||
const nsStyleText* textStyle = frame->StyleText();
|
||||
|
||||
mTextAlignment = textStyle->mTextAlign;
|
||||
// START or END alignment sometimes means RIGHT
|
||||
if ((mTextAlignment == NS_STYLE_TEXT_ALIGN_START &&
|
||||
vis->mDirection == NS_STYLE_DIRECTION_RTL) ||
|
||||
(mTextAlignment == NS_STYLE_TEXT_ALIGN_END &&
|
||||
vis->mDirection == NS_STYLE_DIRECTION_LTR)) {
|
||||
mTextAlignment = NS_STYLE_TEXT_ALIGN_RIGHT;
|
||||
} else if (mTextAlignment == NS_STYLE_TEXT_ALIGN_START ||
|
||||
mTextAlignment == NS_STYLE_TEXT_ALIGN_END) {
|
||||
mTextAlignment = NS_STYLE_TEXT_ALIGN_LEFT;
|
||||
}
|
||||
|
||||
// Figure out if we're the primary column (that has to have indentation
|
||||
// and twisties drawn.
|
||||
mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
// Figure out if we're a cycling column (one that doesn't cause a selection
|
||||
// to happen).
|
||||
mIsCycler = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
mIsEditable = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
mIsSelectable = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
|
||||
nsGkAtoms::_false, eCaseMatters);
|
||||
|
||||
mOverflow = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
// Figure out our column type. Default type is text.
|
||||
mType = nsITreeColumn::TYPE_TEXT;
|
||||
static nsIContent::AttrValuesArray typestrings[] =
|
||||
{&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, &nsGkAtoms::password,
|
||||
nullptr};
|
||||
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
||||
typestrings, eCaseMatters)) {
|
||||
case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
|
||||
case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break;
|
||||
case 2: mType = nsITreeColumn::TYPE_PASSWORD; break;
|
||||
}
|
||||
|
||||
// Fetch the crop style.
|
||||
mCropStyle = 0;
|
||||
static nsIContent::AttrValuesArray cropstrings[] =
|
||||
{&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr};
|
||||
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
|
||||
cropstrings, eCaseMatters)) {
|
||||
case 0:
|
||||
mCropStyle = 1;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
mCropStyle = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsTreeColumn::GetParentObject() const
|
||||
{
|
||||
return mContent;
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
nsTreeColumn::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return dom::TreeColumnBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
mozilla::dom::Element*
|
||||
nsTreeColumn::GetElement(mozilla::ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> element;
|
||||
aRv = GetElement(getter_AddRefs(element));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(element);
|
||||
return node->AsElement();
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsTreeColumn::GetX(mozilla::ErrorResult& aRv)
|
||||
{
|
||||
int32_t x;
|
||||
aRv = GetX(&x);
|
||||
return x;
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsTreeColumn::GetWidth(mozilla::ErrorResult& aRv)
|
||||
{
|
||||
int32_t width;
|
||||
aRv = GetWidth(&width);
|
||||
return width;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColumn::Invalidate(mozilla::ErrorResult& aRv)
|
||||
{
|
||||
aRv = Invalidate();
|
||||
}
|
||||
|
||||
nsTreeColumns::nsTreeColumns(nsTreeBodyFrame* aTree)
|
||||
: mTree(aTree)
|
||||
{
|
||||
}
|
||||
|
||||
nsTreeColumns::~nsTreeColumns()
|
||||
{
|
||||
nsTreeColumns::InvalidateColumns();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsTreeColumns)
|
||||
|
||||
// QueryInterface implementation for nsTreeColumns
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumns)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsITreeColumns)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumns)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumns)
|
||||
|
||||
nsIContent*
|
||||
nsTreeColumns::GetParentObject() const
|
||||
{
|
||||
return mTree ? mTree->GetBaseElement() : nullptr;
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
nsTreeColumns::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return dom::TreeColumnsBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
dom::TreeBoxObject*
|
||||
nsTreeColumns::GetTree() const
|
||||
{
|
||||
return mTree ? static_cast<mozilla::dom::TreeBoxObject*>(mTree->GetTreeBoxObject()) : nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetTree(nsITreeBoxObject** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetTree());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsTreeColumns::Count()
|
||||
{
|
||||
EnsureColumns();
|
||||
uint32_t count = 0;
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetCount(int32_t* _retval)
|
||||
{
|
||||
*_retval = Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetLength(int32_t* _retval)
|
||||
{
|
||||
*_retval = Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetFirstColumn(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetFirstColumn());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetLastColumn()
|
||||
{
|
||||
EnsureColumns();
|
||||
nsTreeColumn* currCol = mFirstColumn;
|
||||
while (currCol) {
|
||||
nsTreeColumn* next = currCol->GetNext();
|
||||
if (!next) {
|
||||
return currCol;
|
||||
}
|
||||
currCol = next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetLastColumn(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetLastColumn());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetPrimaryColumn(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetPrimaryColumn());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetSortedColumn()
|
||||
{
|
||||
EnsureColumns();
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
if (currCol->mContent &&
|
||||
nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
|
||||
nsGkAtoms::sortDirection)) {
|
||||
return currCol;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetSortedColumn());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetKeyColumn()
|
||||
{
|
||||
EnsureColumns();
|
||||
|
||||
nsTreeColumn* first = nullptr;
|
||||
nsTreeColumn* primary = nullptr;
|
||||
nsTreeColumn* sorted = nullptr;
|
||||
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
// Skip hidden columns.
|
||||
if (!currCol->mContent ||
|
||||
currCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
|
||||
nsGkAtoms::_true, eCaseMatters))
|
||||
continue;
|
||||
|
||||
// Skip non-text column
|
||||
if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
|
||||
continue;
|
||||
|
||||
if (!first)
|
||||
first = currCol;
|
||||
|
||||
if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
|
||||
nsGkAtoms::sortDirection)) {
|
||||
// Use sorted column as the key.
|
||||
sorted = currCol;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currCol->IsPrimary())
|
||||
if (!primary)
|
||||
primary = currCol;
|
||||
}
|
||||
|
||||
if (sorted)
|
||||
return sorted;
|
||||
if (primary)
|
||||
return primary;
|
||||
return first;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetKeyColumn());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetColumnFor(dom::Element* aElement)
|
||||
{
|
||||
EnsureColumns();
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
if (currCol->mContent == aElement) {
|
||||
return currCol;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval)
|
||||
{
|
||||
nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
|
||||
NS_ADDREF(*_retval = GetColumnFor(element));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound)
|
||||
{
|
||||
EnsureColumns();
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
if (currCol->GetId().Equals(aId)) {
|
||||
aFound = true;
|
||||
return currCol;
|
||||
}
|
||||
}
|
||||
aFound = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetNamedColumn(const nsAString& aId)
|
||||
{
|
||||
bool dummy;
|
||||
return NamedGetter(aId, dummy);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetNamedColumn(aId));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColumns::GetSupportedNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
aNames.AppendElement(currCol->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
EnsureColumns();
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
if (currCol->GetIndex() == static_cast<int32_t>(aIndex)) {
|
||||
aFound = true;
|
||||
return currCol;
|
||||
}
|
||||
}
|
||||
aFound = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetColumnAt(uint32_t aIndex)
|
||||
{
|
||||
bool dummy;
|
||||
return IndexedGetter(aIndex, dummy);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::GetColumnAt(int32_t aIndex, nsITreeColumn** _retval)
|
||||
{
|
||||
NS_IF_ADDREF(*_retval = GetColumnAt(static_cast<uint32_t>(aIndex)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::InvalidateColumns()
|
||||
{
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol;
|
||||
currCol = currCol->GetNext()) {
|
||||
currCol->SetColumns(nullptr);
|
||||
}
|
||||
mFirstColumn = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeColumns::RestoreNaturalOrder()
|
||||
{
|
||||
if (!mTree)
|
||||
return NS_OK;
|
||||
|
||||
nsIContent* content = mTree->GetBaseElement();
|
||||
|
||||
// Strong ref, since we'll be setting attributes
|
||||
nsCOMPtr<nsIContent> colsContent =
|
||||
nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treecols);
|
||||
if (!colsContent)
|
||||
return NS_OK;
|
||||
|
||||
for (uint32_t i = 0; i < colsContent->GetChildCount(); ++i) {
|
||||
nsCOMPtr<nsIContent> child = colsContent->GetChildAt(i);
|
||||
nsAutoString ordinal;
|
||||
ordinal.AppendInt(i);
|
||||
child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, true);
|
||||
}
|
||||
|
||||
nsTreeColumns::InvalidateColumns();
|
||||
|
||||
if (mTree) {
|
||||
mTree->Invalidate();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTreeColumn*
|
||||
nsTreeColumns::GetPrimaryColumn()
|
||||
{
|
||||
EnsureColumns();
|
||||
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
|
||||
if (currCol->IsPrimary()) {
|
||||
return currCol;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeColumns::EnsureColumns()
|
||||
{
|
||||
if (mTree && !mFirstColumn) {
|
||||
nsIContent* treeContent = mTree->GetBaseElement();
|
||||
nsIContent* colsContent =
|
||||
nsTreeUtils::GetDescendantChild(treeContent, nsGkAtoms::treecols);
|
||||
if (!colsContent)
|
||||
return;
|
||||
|
||||
nsIContent* colContent =
|
||||
nsTreeUtils::GetDescendantChild(colsContent, nsGkAtoms::treecol);
|
||||
if (!colContent)
|
||||
return;
|
||||
|
||||
nsIFrame* colFrame = colContent->GetPrimaryFrame();
|
||||
if (!colFrame)
|
||||
return;
|
||||
|
||||
colFrame = colFrame->GetParent();
|
||||
if (!colFrame)
|
||||
return;
|
||||
|
||||
colFrame = colFrame->PrincipalChildList().FirstChild();
|
||||
if (!colFrame)
|
||||
return;
|
||||
|
||||
// Now that we have the first visible column,
|
||||
// we can enumerate the columns in visible order
|
||||
nsTreeColumn* currCol = nullptr;
|
||||
while (colFrame) {
|
||||
nsIContent* colContent = colFrame->GetContent();
|
||||
|
||||
if (colContent->NodeInfo()->Equals(nsGkAtoms::treecol,
|
||||
kNameSpaceID_XUL)) {
|
||||
// Create a new column structure.
|
||||
nsTreeColumn* col = new nsTreeColumn(this, colContent);
|
||||
if (!col)
|
||||
return;
|
||||
|
||||
if (currCol) {
|
||||
currCol->SetNext(col);
|
||||
col->SetPrevious(currCol);
|
||||
}
|
||||
else {
|
||||
mFirstColumn = col;
|
||||
}
|
||||
currCol = col;
|
||||
}
|
||||
|
||||
colFrame = colFrame->GetNextSibling();
|
||||
}
|
||||
}
|
||||
}
|
||||
215
layout/xul/tree/nsTreeColumns.h
Normal file
215
layout/xul/tree/nsTreeColumns.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsTreeColumns_h__
|
||||
#define nsTreeColumns_h__
|
||||
|
||||
#include "nsITreeColumns.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsTreeBodyFrame;
|
||||
class nsTreeColumns;
|
||||
class nsIFrame;
|
||||
class nsIContent;
|
||||
struct nsRect;
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
namespace dom {
|
||||
class Element;
|
||||
class TreeBoxObject;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_TREECOLUMN_IMPL_CID \
|
||||
{ /* 02cd1963-4b5d-4a6c-9223-814d3ade93a3 */ \
|
||||
0x02cd1963, \
|
||||
0x4b5d, \
|
||||
0x4a6c, \
|
||||
{0x92, 0x23, 0x81, 0x4d, 0x3a, 0xde, 0x93, 0xa3} \
|
||||
}
|
||||
|
||||
// This class is our column info. We use it to iterate our columns and to obtain
|
||||
// information about each column.
|
||||
class nsTreeColumn final : public nsITreeColumn
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent);
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_TREECOLUMN_IMPL_CID)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsTreeColumn)
|
||||
NS_DECL_NSITREECOLUMN
|
||||
|
||||
// WebIDL
|
||||
nsIContent* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
mozilla::dom::Element* GetElement(mozilla::ErrorResult& aRv);
|
||||
|
||||
nsTreeColumns* GetColumns() const { return mColumns; }
|
||||
|
||||
int32_t GetX(mozilla::ErrorResult& aRv);
|
||||
int32_t GetWidth(mozilla::ErrorResult& aRv);
|
||||
|
||||
// GetId is fine
|
||||
int32_t Index() const { return mIndex; }
|
||||
|
||||
bool Primary() const { return mIsPrimary; }
|
||||
bool Cycler() const { return mIsCycler; }
|
||||
bool Editable() const { return mIsEditable; }
|
||||
bool Selectable() const { return mIsSelectable; }
|
||||
int16_t Type() const { return mType; }
|
||||
|
||||
nsTreeColumn* GetNext() const { return mNext; }
|
||||
nsTreeColumn* GetPrevious() const { return mPrevious; }
|
||||
|
||||
void Invalidate(mozilla::ErrorResult& aRv);
|
||||
|
||||
friend class nsTreeBodyFrame;
|
||||
friend class nsTreeColumns;
|
||||
|
||||
protected:
|
||||
~nsTreeColumn();
|
||||
nsIFrame* GetFrame();
|
||||
nsIFrame* GetFrame(nsTreeBodyFrame* aBodyFrame);
|
||||
// Don't call this if GetWidthInTwips or GetRect fails
|
||||
bool IsLastVisible(nsTreeBodyFrame* aBodyFrame);
|
||||
|
||||
/**
|
||||
* Returns a rect with x and width taken from the frame's rect and specified
|
||||
* y and height. May fail in case there's no frame for the column.
|
||||
*/
|
||||
nsresult GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight,
|
||||
nsRect* aResult);
|
||||
|
||||
nsresult GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult);
|
||||
nsresult GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult);
|
||||
|
||||
void SetColumns(nsTreeColumns* aColumns) { mColumns = aColumns; }
|
||||
|
||||
const nsAString& GetId() { return mId; }
|
||||
nsIAtom* GetAtom() { return mAtom; }
|
||||
|
||||
int32_t GetIndex() { return mIndex; }
|
||||
|
||||
bool IsPrimary() { return mIsPrimary; }
|
||||
bool IsCycler() { return mIsCycler; }
|
||||
bool IsEditable() { return mIsEditable; }
|
||||
bool IsSelectable() { return mIsSelectable; }
|
||||
bool Overflow() { return mOverflow; }
|
||||
|
||||
int16_t GetType() { return mType; }
|
||||
|
||||
int8_t GetCropStyle() { return mCropStyle; }
|
||||
int32_t GetTextAlignment() { return mTextAlignment; }
|
||||
|
||||
void SetNext(nsTreeColumn* aNext) {
|
||||
NS_ASSERTION(!mNext, "already have a next sibling");
|
||||
mNext = aNext;
|
||||
}
|
||||
void SetPrevious(nsTreeColumn* aPrevious) { mPrevious = aPrevious; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Non-null nsIContent for the associated <treecol> element.
|
||||
*/
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
|
||||
nsTreeColumns* mColumns;
|
||||
|
||||
nsString mId;
|
||||
nsCOMPtr<nsIAtom> mAtom;
|
||||
|
||||
int32_t mIndex;
|
||||
|
||||
bool mIsPrimary;
|
||||
bool mIsCycler;
|
||||
bool mIsEditable;
|
||||
bool mIsSelectable;
|
||||
bool mOverflow;
|
||||
|
||||
int16_t mType;
|
||||
|
||||
int8_t mCropStyle;
|
||||
int8_t mTextAlignment;
|
||||
|
||||
RefPtr<nsTreeColumn> mNext;
|
||||
nsTreeColumn* mPrevious;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsTreeColumn, NS_TREECOLUMN_IMPL_CID)
|
||||
|
||||
class nsTreeColumns final : public nsITreeColumns
|
||||
, public nsWrapperCache
|
||||
{
|
||||
private:
|
||||
~nsTreeColumns();
|
||||
|
||||
public:
|
||||
explicit nsTreeColumns(nsTreeBodyFrame* aTree);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsTreeColumns)
|
||||
NS_DECL_NSITREECOLUMNS
|
||||
|
||||
nsIContent* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// WebIDL
|
||||
mozilla::dom::TreeBoxObject* GetTree() const;
|
||||
uint32_t Count();
|
||||
uint32_t Length()
|
||||
{
|
||||
return Count();
|
||||
}
|
||||
|
||||
nsTreeColumn* GetFirstColumn() { EnsureColumns(); return mFirstColumn; }
|
||||
nsTreeColumn* GetLastColumn();
|
||||
|
||||
nsTreeColumn* GetPrimaryColumn();
|
||||
nsTreeColumn* GetSortedColumn();
|
||||
nsTreeColumn* GetKeyColumn();
|
||||
|
||||
nsTreeColumn* GetColumnFor(mozilla::dom::Element* aElement);
|
||||
|
||||
nsTreeColumn* IndexedGetter(uint32_t aIndex, bool& aFound);
|
||||
nsTreeColumn* GetColumnAt(uint32_t aIndex);
|
||||
nsTreeColumn* NamedGetter(const nsAString& aId, bool& aFound);
|
||||
nsTreeColumn* GetNamedColumn(const nsAString& aId);
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames);
|
||||
|
||||
// Uses XPCOM InvalidateColumns().
|
||||
// Uses XPCOM RestoreNaturalOrder().
|
||||
|
||||
friend class nsTreeBodyFrame;
|
||||
protected:
|
||||
void SetTree(nsTreeBodyFrame* aTree) { mTree = aTree; }
|
||||
|
||||
// Builds our cache of column info.
|
||||
void EnsureColumns();
|
||||
|
||||
private:
|
||||
nsTreeBodyFrame* mTree;
|
||||
|
||||
/**
|
||||
* The first column in the list of columns. All of the columns are supposed
|
||||
* to be "alive", i.e. have a frame. This is achieved by clearing the columns
|
||||
* list each time an nsTreeColFrame is destroyed.
|
||||
*
|
||||
* XXX this means that new nsTreeColumn objects are unnecessarily created
|
||||
* for untouched columns.
|
||||
*/
|
||||
RefPtr<nsTreeColumn> mFirstColumn;
|
||||
};
|
||||
|
||||
#endif // nsTreeColumns_h__
|
||||
1372
layout/xul/tree/nsTreeContentView.cpp
Normal file
1372
layout/xul/tree/nsTreeContentView.cpp
Normal file
File diff suppressed because it is too large
Load diff
101
layout/xul/tree/nsTreeContentView.h
Normal file
101
layout/xul/tree/nsTreeContentView.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsTreeContentView_h__
|
||||
#define nsTreeContentView_h__
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsStubDocumentObserver.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
#include "nsITreeColumns.h"
|
||||
#include "nsITreeView.h"
|
||||
#include "nsITreeContentView.h"
|
||||
#include "nsITreeSelection.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
class nsIDocument;
|
||||
class Row;
|
||||
|
||||
nsresult NS_NewTreeContentView(nsITreeView** aResult);
|
||||
|
||||
class nsTreeContentView final : public nsINativeTreeView,
|
||||
public nsITreeContentView,
|
||||
public nsStubDocumentObserver
|
||||
{
|
||||
public:
|
||||
nsTreeContentView(void);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTreeContentView,
|
||||
nsINativeTreeView)
|
||||
|
||||
NS_DECL_NSITREEVIEW
|
||||
// nsINativeTreeView: Untrusted code can use us
|
||||
NS_IMETHOD EnsureNative() override { return NS_OK; }
|
||||
|
||||
NS_DECL_NSITREECONTENTVIEW
|
||||
|
||||
// nsIDocumentObserver
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
|
||||
|
||||
static bool CanTrustTreeSelection(nsISupports* aValue);
|
||||
|
||||
protected:
|
||||
~nsTreeContentView(void);
|
||||
|
||||
// Recursive methods which deal with serializing of nested content.
|
||||
void Serialize(nsIContent* aContent, int32_t aParentIndex, int32_t* aIndex,
|
||||
nsTArray<mozilla::UniquePtr<Row>>& aRows);
|
||||
|
||||
void SerializeItem(nsIContent* aContent, int32_t aParentIndex,
|
||||
int32_t* aIndex, nsTArray<mozilla::UniquePtr<Row>>& aRows);
|
||||
|
||||
void SerializeSeparator(nsIContent* aContent, int32_t aParentIndex,
|
||||
int32_t* aIndex, nsTArray<mozilla::UniquePtr<Row>>& aRows);
|
||||
|
||||
void GetIndexInSubtree(nsIContent* aContainer, nsIContent* aContent, int32_t* aResult);
|
||||
|
||||
// Helper methods which we use to manage our plain array of rows.
|
||||
int32_t EnsureSubtree(int32_t aIndex);
|
||||
|
||||
int32_t RemoveSubtree(int32_t aIndex);
|
||||
|
||||
int32_t InsertRow(int32_t aParentIndex, int32_t aIndex, nsIContent* aContent);
|
||||
|
||||
void InsertRowFor(nsIContent* aParent, nsIContent* aChild);
|
||||
|
||||
int32_t RemoveRow(int32_t aIndex);
|
||||
|
||||
void ClearRows();
|
||||
|
||||
void OpenContainer(int32_t aIndex);
|
||||
|
||||
void CloseContainer(int32_t aIndex);
|
||||
|
||||
int32_t FindContent(nsIContent* aContent);
|
||||
|
||||
void UpdateSubtreeSizes(int32_t aIndex, int32_t aCount);
|
||||
|
||||
void UpdateParentIndexes(int32_t aIndex, int32_t aSkip, int32_t aCount);
|
||||
|
||||
// Content helpers.
|
||||
nsIContent* GetCell(nsIContent* aContainer, nsITreeColumn* aCol);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsITreeBoxObject> mBoxObject;
|
||||
nsCOMPtr<nsITreeSelection> mSelection;
|
||||
nsCOMPtr<nsIContent> mRoot;
|
||||
nsCOMPtr<nsIContent> mBody;
|
||||
nsIDocument* mDocument; // WEAK
|
||||
nsTArray<mozilla::UniquePtr<Row>> mRows;
|
||||
};
|
||||
|
||||
#endif // nsTreeContentView_h__
|
||||
115
layout/xul/tree/nsTreeImageListener.cpp
Normal file
115
layout/xul/tree/nsTreeImageListener.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsTreeImageListener.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsTreeImageListener, imgINotificationObserver)
|
||||
|
||||
nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame)
|
||||
: mTreeFrame(aTreeFrame),
|
||||
mInvalidationSuppressed(true),
|
||||
mInvalidationArea(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
nsTreeImageListener::~nsTreeImageListener()
|
||||
{
|
||||
delete mInvalidationArea;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
|
||||
{
|
||||
if (aType == imgINotificationObserver::IS_ANIMATED) {
|
||||
return mTreeFrame ? mTreeFrame->OnImageIsAnimated(aRequest) : NS_OK;
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
|
||||
// Ensure the animation (if any) is started. Note: There is no
|
||||
// corresponding call to Decrement for this. This Increment will be
|
||||
// 'cleaned up' by the Request when it is destroyed, but only then.
|
||||
aRequest->IncrementAnimationConsumers();
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::FRAME_UPDATE) {
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeImageListener::AddCell(int32_t aIndex, nsITreeColumn* aCol)
|
||||
{
|
||||
if (!mInvalidationArea) {
|
||||
mInvalidationArea = new InvalidationArea(aCol);
|
||||
mInvalidationArea->AddRow(aIndex);
|
||||
}
|
||||
else {
|
||||
InvalidationArea* currArea;
|
||||
for (currArea = mInvalidationArea; currArea; currArea = currArea->GetNext()) {
|
||||
if (currArea->GetCol() == aCol) {
|
||||
currArea->AddRow(aIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!currArea) {
|
||||
currArea = new InvalidationArea(aCol);
|
||||
currArea->SetNext(mInvalidationArea);
|
||||
mInvalidationArea = currArea;
|
||||
mInvalidationArea->AddRow(aIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsTreeImageListener::Invalidate()
|
||||
{
|
||||
if (!mInvalidationSuppressed) {
|
||||
for (InvalidationArea* currArea = mInvalidationArea; currArea;
|
||||
currArea = currArea->GetNext()) {
|
||||
// Loop from min to max, invalidating each cell that was listening for this image.
|
||||
for (int32_t i = currArea->GetMin(); i <= currArea->GetMax(); ++i) {
|
||||
if (mTreeFrame) {
|
||||
nsITreeBoxObject* tree = mTreeFrame->GetTreeBoxObject();
|
||||
if (tree) {
|
||||
tree->InvalidateCell(i, currArea->GetCol());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTreeImageListener::InvalidationArea::InvalidationArea(nsITreeColumn* aCol)
|
||||
: mCol(aCol),
|
||||
mMin(-1), // min should start out "undefined"
|
||||
mMax(0),
|
||||
mNext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeImageListener::InvalidationArea::AddRow(int32_t aIndex)
|
||||
{
|
||||
if (mMin == -1)
|
||||
mMin = mMax = aIndex;
|
||||
else if (aIndex < mMin)
|
||||
mMin = aIndex;
|
||||
else if (aIndex > mMax)
|
||||
mMax = aIndex;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeImageListener::ClearFrame()
|
||||
{
|
||||
mTreeFrame = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
66
layout/xul/tree/nsTreeImageListener.h
Normal file
66
layout/xul/tree/nsTreeImageListener.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsTreeImageListener_h__
|
||||
#define nsTreeImageListener_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsITreeColumns.h"
|
||||
#include "nsTreeBodyFrame.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// This class handles image load observation.
|
||||
class nsTreeImageListener final : public imgINotificationObserver
|
||||
{
|
||||
public:
|
||||
explicit nsTreeImageListener(nsTreeBodyFrame *aTreeFrame);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGINOTIFICATIONOBSERVER
|
||||
|
||||
NS_IMETHOD ClearFrame();
|
||||
|
||||
friend class nsTreeBodyFrame;
|
||||
|
||||
protected:
|
||||
~nsTreeImageListener();
|
||||
|
||||
void UnsuppressInvalidation() { mInvalidationSuppressed = false; }
|
||||
void Invalidate();
|
||||
void AddCell(int32_t aIndex, nsITreeColumn* aCol);
|
||||
|
||||
private:
|
||||
nsTreeBodyFrame* mTreeFrame;
|
||||
|
||||
// A guard that prevents us from recursive painting.
|
||||
bool mInvalidationSuppressed;
|
||||
|
||||
class InvalidationArea {
|
||||
public:
|
||||
explicit InvalidationArea(nsITreeColumn* aCol);
|
||||
~InvalidationArea() { delete mNext; }
|
||||
|
||||
friend class nsTreeImageListener;
|
||||
|
||||
protected:
|
||||
void AddRow(int32_t aIndex);
|
||||
nsITreeColumn* GetCol() { return mCol.get(); }
|
||||
int32_t GetMin() { return mMin; }
|
||||
int32_t GetMax() { return mMax; }
|
||||
InvalidationArea* GetNext() { return mNext; }
|
||||
void SetNext(InvalidationArea* aNext) { mNext = aNext; }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsITreeColumn> mCol;
|
||||
int32_t mMin;
|
||||
int32_t mMax;
|
||||
InvalidationArea* mNext;
|
||||
};
|
||||
|
||||
InvalidationArea* mInvalidationArea;
|
||||
};
|
||||
|
||||
#endif // nsTreeImageListener_h__
|
||||
866
layout/xul/tree/nsTreeSelection.cpp
Normal file
866
layout/xul/tree/nsTreeSelection.cpp
Normal file
|
|
@ -0,0 +1,866 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/AsyncEventDispatcher.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTreeSelection.h"
|
||||
#include "nsIBoxObject.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
#include "nsITreeView.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// A helper class for managing our ranges of selection.
|
||||
struct nsTreeRange
|
||||
{
|
||||
nsTreeSelection* mSelection;
|
||||
|
||||
nsTreeRange* mPrev;
|
||||
nsTreeRange* mNext;
|
||||
|
||||
int32_t mMin;
|
||||
int32_t mMax;
|
||||
|
||||
nsTreeRange(nsTreeSelection* aSel, int32_t aSingleVal)
|
||||
:mSelection(aSel), mPrev(nullptr), mNext(nullptr), mMin(aSingleVal), mMax(aSingleVal) {}
|
||||
nsTreeRange(nsTreeSelection* aSel, int32_t aMin, int32_t aMax)
|
||||
:mSelection(aSel), mPrev(nullptr), mNext(nullptr), mMin(aMin), mMax(aMax) {}
|
||||
|
||||
~nsTreeRange() { delete mNext; }
|
||||
|
||||
void Connect(nsTreeRange* aPrev = nullptr, nsTreeRange* aNext = nullptr) {
|
||||
if (aPrev)
|
||||
aPrev->mNext = this;
|
||||
else
|
||||
mSelection->mFirstRange = this;
|
||||
|
||||
if (aNext)
|
||||
aNext->mPrev = this;
|
||||
|
||||
mPrev = aPrev;
|
||||
mNext = aNext;
|
||||
}
|
||||
|
||||
nsresult RemoveRange(int32_t aStart, int32_t aEnd) {
|
||||
// This should so be a loop... sigh...
|
||||
// We start past the range to remove, so no more to remove
|
||||
if (aEnd < mMin)
|
||||
return NS_OK;
|
||||
// We are the last range to be affected
|
||||
if (aEnd < mMax) {
|
||||
if (aStart <= mMin) {
|
||||
// Just chop the start of the range off
|
||||
mMin = aEnd + 1;
|
||||
} else {
|
||||
// We need to split the range
|
||||
nsTreeRange* range = new nsTreeRange(mSelection, aEnd + 1, mMax);
|
||||
if (!range)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mMax = aStart - 1;
|
||||
range->Connect(this, mNext);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsTreeRange* next = mNext;
|
||||
if (aStart <= mMin) {
|
||||
// The remove includes us, remove ourselves from the list
|
||||
if (mPrev)
|
||||
mPrev->mNext = next;
|
||||
else
|
||||
mSelection->mFirstRange = next;
|
||||
|
||||
if (next)
|
||||
next->mPrev = mPrev;
|
||||
mPrev = mNext = nullptr;
|
||||
delete this;
|
||||
} else if (aStart <= mMax) {
|
||||
// Just chop the end of the range off
|
||||
mMax = aStart - 1;
|
||||
}
|
||||
return next ? next->RemoveRange(aStart, aEnd) : NS_OK;
|
||||
}
|
||||
|
||||
nsresult Remove(int32_t aIndex) {
|
||||
if (aIndex >= mMin && aIndex <= mMax) {
|
||||
// We have found the range that contains us.
|
||||
if (mMin == mMax) {
|
||||
// Delete the whole range.
|
||||
if (mPrev)
|
||||
mPrev->mNext = mNext;
|
||||
if (mNext)
|
||||
mNext->mPrev = mPrev;
|
||||
nsTreeRange* first = mSelection->mFirstRange;
|
||||
if (first == this)
|
||||
mSelection->mFirstRange = mNext;
|
||||
mNext = mPrev = nullptr;
|
||||
delete this;
|
||||
}
|
||||
else if (aIndex == mMin)
|
||||
mMin++;
|
||||
else if (aIndex == mMax)
|
||||
mMax--;
|
||||
else {
|
||||
// We have to break this range.
|
||||
nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex + 1, mMax);
|
||||
if (!newRange)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newRange->Connect(this, mNext);
|
||||
mMax = aIndex - 1;
|
||||
}
|
||||
}
|
||||
else if (mNext)
|
||||
return mNext->Remove(aIndex);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Add(int32_t aIndex) {
|
||||
if (aIndex < mMin) {
|
||||
// We have found a spot to insert.
|
||||
if (aIndex + 1 == mMin)
|
||||
mMin = aIndex;
|
||||
else if (mPrev && mPrev->mMax+1 == aIndex)
|
||||
mPrev->mMax = aIndex;
|
||||
else {
|
||||
// We have to create a new range.
|
||||
nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex);
|
||||
if (!newRange)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newRange->Connect(mPrev, this);
|
||||
}
|
||||
}
|
||||
else if (mNext)
|
||||
mNext->Add(aIndex);
|
||||
else {
|
||||
// Insert on to the end.
|
||||
if (mMax+1 == aIndex)
|
||||
mMax = aIndex;
|
||||
else {
|
||||
// We have to create a new range.
|
||||
nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex);
|
||||
if (!newRange)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newRange->Connect(this, nullptr);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool Contains(int32_t aIndex) {
|
||||
if (aIndex >= mMin && aIndex <= mMax)
|
||||
return true;
|
||||
|
||||
if (mNext)
|
||||
return mNext->Contains(aIndex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t Count() {
|
||||
int32_t total = mMax - mMin + 1;
|
||||
if (mNext)
|
||||
total += mNext->Count();
|
||||
return total;
|
||||
}
|
||||
|
||||
static void CollectRanges(nsTreeRange* aRange, nsTArray<int32_t>& aRanges)
|
||||
{
|
||||
nsTreeRange* cur = aRange;
|
||||
while (cur) {
|
||||
aRanges.AppendElement(cur->mMin);
|
||||
aRanges.AppendElement(cur->mMax);
|
||||
cur = cur->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
static void InvalidateRanges(nsITreeBoxObject* aTree,
|
||||
nsTArray<int32_t>& aRanges)
|
||||
{
|
||||
if (aTree) {
|
||||
nsCOMPtr<nsITreeBoxObject> tree = aTree;
|
||||
for (uint32_t i = 0; i < aRanges.Length(); i += 2) {
|
||||
aTree->InvalidateRange(aRanges[i], aRanges[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Invalidate() {
|
||||
nsTArray<int32_t> ranges;
|
||||
CollectRanges(this, ranges);
|
||||
InvalidateRanges(mSelection->mTree, ranges);
|
||||
|
||||
}
|
||||
|
||||
void RemoveAllBut(int32_t aIndex) {
|
||||
if (aIndex >= mMin && aIndex <= mMax) {
|
||||
|
||||
// Invalidate everything in this list.
|
||||
nsTArray<int32_t> ranges;
|
||||
CollectRanges(mSelection->mFirstRange, ranges);
|
||||
|
||||
mMin = aIndex;
|
||||
mMax = aIndex;
|
||||
|
||||
nsTreeRange* first = mSelection->mFirstRange;
|
||||
if (mPrev)
|
||||
mPrev->mNext = mNext;
|
||||
if (mNext)
|
||||
mNext->mPrev = mPrev;
|
||||
mNext = mPrev = nullptr;
|
||||
|
||||
if (first != this) {
|
||||
delete mSelection->mFirstRange;
|
||||
mSelection->mFirstRange = this;
|
||||
}
|
||||
InvalidateRanges(mSelection->mTree, ranges);
|
||||
}
|
||||
else if (mNext)
|
||||
mNext->RemoveAllBut(aIndex);
|
||||
}
|
||||
|
||||
void Insert(nsTreeRange* aRange) {
|
||||
if (mMin >= aRange->mMax)
|
||||
aRange->Connect(mPrev, this);
|
||||
else if (mNext)
|
||||
mNext->Insert(aRange);
|
||||
else
|
||||
aRange->Connect(this, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
nsTreeSelection::nsTreeSelection(nsITreeBoxObject* aTree)
|
||||
: mTree(aTree),
|
||||
mSuppressed(false),
|
||||
mCurrentIndex(-1),
|
||||
mShiftSelectPivot(-1),
|
||||
mFirstRange(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
nsTreeSelection::~nsTreeSelection()
|
||||
{
|
||||
delete mFirstRange;
|
||||
if (mSelectTimer)
|
||||
mSelectTimer->Cancel();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(nsTreeSelection, mTree, mCurrentColumn)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeSelection)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeSelection)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeSelection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITreeSelection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINativeTreeSelection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TreeSelection)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetTree(nsITreeBoxObject * *aTree)
|
||||
{
|
||||
NS_IF_ADDREF(*aTree = mTree);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::SetTree(nsITreeBoxObject * aTree)
|
||||
{
|
||||
if (mSelectTimer) {
|
||||
mSelectTimer->Cancel();
|
||||
mSelectTimer = nullptr;
|
||||
}
|
||||
|
||||
// Make sure aTree really implements nsITreeBoxObject and nsIBoxObject!
|
||||
nsCOMPtr<nsIBoxObject> bo = do_QueryInterface(aTree);
|
||||
mTree = do_QueryInterface(bo);
|
||||
NS_ENSURE_STATE(mTree == aTree);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetSingle(bool* aSingle)
|
||||
{
|
||||
if (!mTree)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> element;
|
||||
boxObject->GetElement(getter_AddRefs(element));
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(element);
|
||||
|
||||
static nsIContent::AttrValuesArray strings[] =
|
||||
{&nsGkAtoms::single, &nsGkAtoms::cell, &nsGkAtoms::text, nullptr};
|
||||
|
||||
*aSingle = content->FindAttrValueIn(kNameSpaceID_None,
|
||||
nsGkAtoms::seltype,
|
||||
strings, eCaseMatters) >= 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::IsSelected(int32_t aIndex, bool* aResult)
|
||||
{
|
||||
if (mFirstRange)
|
||||
*aResult = mFirstRange->Contains(aIndex);
|
||||
else
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::TimedSelect(int32_t aIndex, int32_t aMsec)
|
||||
{
|
||||
bool suppressSelect = mSuppressed;
|
||||
|
||||
if (aMsec != -1)
|
||||
mSuppressed = true;
|
||||
|
||||
nsresult rv = Select(aIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (aMsec != -1) {
|
||||
mSuppressed = suppressSelect;
|
||||
if (!mSuppressed) {
|
||||
if (mSelectTimer)
|
||||
mSelectTimer->Cancel();
|
||||
|
||||
mSelectTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mSelectTimer->InitWithFuncCallback(SelectCallback, this, aMsec,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::Select(int32_t aIndex)
|
||||
{
|
||||
mShiftSelectPivot = -1;
|
||||
|
||||
nsresult rv = SetCurrentIndex(aIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mFirstRange) {
|
||||
bool alreadySelected = mFirstRange->Contains(aIndex);
|
||||
|
||||
if (alreadySelected) {
|
||||
int32_t count = mFirstRange->Count();
|
||||
if (count > 1) {
|
||||
// We need to deselect everything but our item.
|
||||
mFirstRange->RemoveAllBut(aIndex);
|
||||
FireOnSelectHandler();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
else {
|
||||
// Clear out our selection.
|
||||
mFirstRange->Invalidate();
|
||||
delete mFirstRange;
|
||||
}
|
||||
}
|
||||
|
||||
// Create our new selection.
|
||||
mFirstRange = new nsTreeRange(this, aIndex);
|
||||
if (!mFirstRange)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mFirstRange->Invalidate();
|
||||
|
||||
// Fire the select event
|
||||
FireOnSelectHandler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::ToggleSelect(int32_t aIndex)
|
||||
{
|
||||
// There are six cases that can occur on a ToggleSelect with our
|
||||
// range code.
|
||||
// (1) A new range should be made for a selection.
|
||||
// (2) A single range is removed from the selection.
|
||||
// (3) The item is added to an existing range.
|
||||
// (4) The item is removed from an existing range.
|
||||
// (5) The addition of the item causes two ranges to be merged.
|
||||
// (6) The removal of the item causes two ranges to be split.
|
||||
mShiftSelectPivot = -1;
|
||||
nsresult rv = SetCurrentIndex(aIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!mFirstRange)
|
||||
Select(aIndex);
|
||||
else {
|
||||
if (!mFirstRange->Contains(aIndex)) {
|
||||
bool single;
|
||||
rv = GetSingle(&single);
|
||||
if (NS_SUCCEEDED(rv) && !single)
|
||||
rv = mFirstRange->Add(aIndex);
|
||||
}
|
||||
else
|
||||
rv = mFirstRange->Remove(aIndex);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (mTree)
|
||||
mTree->InvalidateRow(aIndex);
|
||||
|
||||
FireOnSelectHandler();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::RangedSelect(int32_t aStartIndex, int32_t aEndIndex, bool aAugment)
|
||||
{
|
||||
bool single;
|
||||
nsresult rv = GetSingle(&single);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if ((mFirstRange || (aStartIndex != aEndIndex)) && single)
|
||||
return NS_OK;
|
||||
|
||||
if (!aAugment) {
|
||||
// Clear our selection.
|
||||
if (mFirstRange) {
|
||||
mFirstRange->Invalidate();
|
||||
delete mFirstRange;
|
||||
mFirstRange = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aStartIndex == -1) {
|
||||
if (mShiftSelectPivot != -1)
|
||||
aStartIndex = mShiftSelectPivot;
|
||||
else if (mCurrentIndex != -1)
|
||||
aStartIndex = mCurrentIndex;
|
||||
else
|
||||
aStartIndex = aEndIndex;
|
||||
}
|
||||
|
||||
mShiftSelectPivot = aStartIndex;
|
||||
rv = SetCurrentIndex(aEndIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
int32_t start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
|
||||
int32_t end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;
|
||||
|
||||
if (aAugment && mFirstRange) {
|
||||
// We need to remove all the items within our selected range from the selection,
|
||||
// and then we insert our new range into the list.
|
||||
nsresult rv = mFirstRange->RemoveRange(start, end);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsTreeRange* range = new nsTreeRange(this, start, end);
|
||||
if (!range)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
range->Invalidate();
|
||||
|
||||
if (aAugment && mFirstRange)
|
||||
mFirstRange->Insert(range);
|
||||
else
|
||||
mFirstRange = range;
|
||||
|
||||
FireOnSelectHandler();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::ClearRange(int32_t aStartIndex, int32_t aEndIndex)
|
||||
{
|
||||
nsresult rv = SetCurrentIndex(aEndIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mFirstRange) {
|
||||
int32_t start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
|
||||
int32_t end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;
|
||||
|
||||
mFirstRange->RemoveRange(start, end);
|
||||
|
||||
if (mTree)
|
||||
mTree->InvalidateRange(start, end);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::ClearSelection()
|
||||
{
|
||||
if (mFirstRange) {
|
||||
mFirstRange->Invalidate();
|
||||
delete mFirstRange;
|
||||
mFirstRange = nullptr;
|
||||
}
|
||||
mShiftSelectPivot = -1;
|
||||
|
||||
FireOnSelectHandler();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::InvertSelection()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::SelectAll()
|
||||
{
|
||||
if (!mTree)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsITreeView> view;
|
||||
mTree->GetView(getter_AddRefs(view));
|
||||
if (!view)
|
||||
return NS_OK;
|
||||
|
||||
int32_t rowCount;
|
||||
view->GetRowCount(&rowCount);
|
||||
bool single;
|
||||
nsresult rv = GetSingle(&single);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (rowCount == 0 || (rowCount > 1 && single))
|
||||
return NS_OK;
|
||||
|
||||
mShiftSelectPivot = -1;
|
||||
|
||||
// Invalidate not necessary when clearing selection, since
|
||||
// we're going to invalidate the world on the SelectAll.
|
||||
delete mFirstRange;
|
||||
|
||||
mFirstRange = new nsTreeRange(this, 0, rowCount-1);
|
||||
mFirstRange->Invalidate();
|
||||
|
||||
FireOnSelectHandler();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetRangeCount(int32_t* aResult)
|
||||
{
|
||||
int32_t count = 0;
|
||||
nsTreeRange* curr = mFirstRange;
|
||||
while (curr) {
|
||||
count++;
|
||||
curr = curr->mNext;
|
||||
}
|
||||
|
||||
*aResult = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetRangeAt(int32_t aIndex, int32_t* aMin, int32_t* aMax)
|
||||
{
|
||||
*aMin = *aMax = -1;
|
||||
int32_t i = -1;
|
||||
nsTreeRange* curr = mFirstRange;
|
||||
while (curr) {
|
||||
i++;
|
||||
if (i == aIndex) {
|
||||
*aMin = curr->mMin;
|
||||
*aMax = curr->mMax;
|
||||
break;
|
||||
}
|
||||
curr = curr->mNext;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetCount(int32_t *count)
|
||||
{
|
||||
if (mFirstRange)
|
||||
*count = mFirstRange->Count();
|
||||
else // No range available, so there's no selected row.
|
||||
*count = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetSelectEventsSuppressed(bool *aSelectEventsSuppressed)
|
||||
{
|
||||
*aSelectEventsSuppressed = mSuppressed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::SetSelectEventsSuppressed(bool aSelectEventsSuppressed)
|
||||
{
|
||||
mSuppressed = aSelectEventsSuppressed;
|
||||
if (!mSuppressed)
|
||||
FireOnSelectHandler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetCurrentIndex(int32_t *aCurrentIndex)
|
||||
{
|
||||
*aCurrentIndex = mCurrentIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(int32_t aIndex)
|
||||
{
|
||||
if (!mTree) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (mCurrentIndex == aIndex) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mCurrentIndex != -1 && mTree)
|
||||
mTree->InvalidateRow(mCurrentIndex);
|
||||
|
||||
mCurrentIndex = aIndex;
|
||||
if (!mTree)
|
||||
return NS_OK;
|
||||
|
||||
if (aIndex != -1)
|
||||
mTree->InvalidateRow(aIndex);
|
||||
|
||||
// Fire DOMMenuItemActive or DOMMenuItemInactive event for tree.
|
||||
nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
|
||||
NS_ASSERTION(boxObject, "no box object!");
|
||||
if (!boxObject)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMElement> treeElt;
|
||||
boxObject->GetElement(getter_AddRefs(treeElt));
|
||||
|
||||
nsCOMPtr<nsINode> treeDOMNode(do_QueryInterface(treeElt));
|
||||
NS_ENSURE_STATE(treeDOMNode);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(DOMMenuItemActive, "DOMMenuItemActive");
|
||||
NS_NAMED_LITERAL_STRING(DOMMenuItemInactive, "DOMMenuItemInactive");
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(treeDOMNode,
|
||||
(aIndex != -1 ? DOMMenuItemActive :
|
||||
DOMMenuItemInactive),
|
||||
true, false);
|
||||
return asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::GetCurrentColumn(nsITreeColumn** aCurrentColumn)
|
||||
{
|
||||
NS_IF_ADDREF(*aCurrentColumn = mCurrentColumn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTreeSelection::SetCurrentColumn(nsITreeColumn* aCurrentColumn)
|
||||
{
|
||||
if (!mTree) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (mCurrentColumn == aCurrentColumn) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mCurrentColumn) {
|
||||
if (mFirstRange)
|
||||
mTree->InvalidateCell(mFirstRange->mMin, mCurrentColumn);
|
||||
if (mCurrentIndex != -1)
|
||||
mTree->InvalidateCell(mCurrentIndex, mCurrentColumn);
|
||||
}
|
||||
|
||||
mCurrentColumn = aCurrentColumn;
|
||||
|
||||
if (mCurrentColumn) {
|
||||
if (mFirstRange)
|
||||
mTree->InvalidateCell(mFirstRange->mMin, mCurrentColumn);
|
||||
if (mCurrentIndex != -1)
|
||||
mTree->InvalidateCell(mCurrentIndex, mCurrentColumn);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define ADD_NEW_RANGE(macro_range, macro_selection, macro_start, macro_end) \
|
||||
{ \
|
||||
int32_t start = macro_start; \
|
||||
int32_t end = macro_end; \
|
||||
if (start > end) { \
|
||||
end = start; \
|
||||
} \
|
||||
nsTreeRange* macro_new_range = new nsTreeRange(macro_selection, start, end); \
|
||||
if (macro_range) \
|
||||
macro_range->Insert(macro_new_range); \
|
||||
else \
|
||||
macro_range = macro_new_range; \
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeSelection::AdjustSelection(int32_t aIndex, int32_t aCount)
|
||||
{
|
||||
NS_ASSERTION(aCount != 0, "adjusting by zero");
|
||||
if (!aCount) return NS_OK;
|
||||
|
||||
// adjust mShiftSelectPivot, if necessary
|
||||
if ((mShiftSelectPivot != 1) && (aIndex <= mShiftSelectPivot)) {
|
||||
// if we are deleting and the delete includes the shift select pivot, reset it
|
||||
if (aCount < 0 && (mShiftSelectPivot <= (aIndex -aCount -1))) {
|
||||
mShiftSelectPivot = -1;
|
||||
}
|
||||
else {
|
||||
mShiftSelectPivot += aCount;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust mCurrentIndex, if necessary
|
||||
if ((mCurrentIndex != -1) && (aIndex <= mCurrentIndex)) {
|
||||
// if we are deleting and the delete includes the current index, reset it
|
||||
if (aCount < 0 && (mCurrentIndex <= (aIndex -aCount -1))) {
|
||||
mCurrentIndex = -1;
|
||||
}
|
||||
else {
|
||||
mCurrentIndex += aCount;
|
||||
}
|
||||
}
|
||||
|
||||
// no selection, so nothing to do.
|
||||
if (!mFirstRange) return NS_OK;
|
||||
|
||||
bool selChanged = false;
|
||||
nsTreeRange* oldFirstRange = mFirstRange;
|
||||
nsTreeRange* curr = mFirstRange;
|
||||
mFirstRange = nullptr;
|
||||
while (curr) {
|
||||
if (aCount > 0) {
|
||||
// inserting
|
||||
if (aIndex > curr->mMax) {
|
||||
// adjustment happens after the range, so no change
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax);
|
||||
}
|
||||
else if (aIndex <= curr->mMin) {
|
||||
// adjustment happens before the start of the range, so shift down
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount);
|
||||
selChanged = true;
|
||||
}
|
||||
else {
|
||||
// adjustment happen inside the range.
|
||||
// break apart the range and create two ranges
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1);
|
||||
ADD_NEW_RANGE(mFirstRange, this, aIndex + aCount, curr->mMax + aCount);
|
||||
selChanged = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// deleting
|
||||
if (aIndex > curr->mMax) {
|
||||
// adjustment happens after the range, so no change
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax);
|
||||
}
|
||||
else {
|
||||
// remember, aCount is negative
|
||||
selChanged = true;
|
||||
int32_t lastIndexOfAdjustment = aIndex - aCount - 1;
|
||||
if (aIndex <= curr->mMin) {
|
||||
if (lastIndexOfAdjustment < curr->mMin) {
|
||||
// adjustment happens before the start of the range, so shift up
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount);
|
||||
}
|
||||
else if (lastIndexOfAdjustment >= curr->mMax) {
|
||||
// adjustment contains the range. remove the range by not adding it to the newRange
|
||||
}
|
||||
else {
|
||||
// adjustment starts before the range, and ends in the middle of it, so trim the range
|
||||
ADD_NEW_RANGE(mFirstRange, this, aIndex, curr->mMax + aCount)
|
||||
}
|
||||
}
|
||||
else if (lastIndexOfAdjustment >= curr->mMax) {
|
||||
// adjustment starts in the middle of the current range, and contains the end of the range, so trim the range
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1)
|
||||
}
|
||||
else {
|
||||
// range contains the adjustment, so shorten the range
|
||||
ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax + aCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
curr = curr->mNext;
|
||||
}
|
||||
|
||||
delete oldFirstRange;
|
||||
|
||||
// Fire the select event
|
||||
if (selChanged)
|
||||
FireOnSelectHandler();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeSelection::InvalidateSelection()
|
||||
{
|
||||
if (mFirstRange)
|
||||
mFirstRange->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTreeSelection::GetShiftSelectPivot(int32_t* aIndex)
|
||||
{
|
||||
*aIndex = mShiftSelectPivot;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTreeSelection::FireOnSelectHandler()
|
||||
{
|
||||
if (mSuppressed || !mTree)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
|
||||
NS_ASSERTION(boxObject, "no box object!");
|
||||
if (!boxObject)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMElement> elt;
|
||||
boxObject->GetElement(getter_AddRefs(elt));
|
||||
NS_ENSURE_STATE(elt);
|
||||
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(elt));
|
||||
NS_ENSURE_STATE(node);
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(node, NS_LITERAL_STRING("select"), true, false);
|
||||
asyncDispatcher->RunDOMEventWhenSafe();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeSelection::SelectCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
RefPtr<nsTreeSelection> self = static_cast<nsTreeSelection*>(aClosure);
|
||||
if (self) {
|
||||
self->FireOnSelectHandler();
|
||||
aTimer->Cancel();
|
||||
self->mSelectTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewTreeSelection(nsITreeBoxObject* aTree, nsITreeSelection** aResult)
|
||||
{
|
||||
*aResult = new nsTreeSelection(aTree);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
56
layout/xul/tree/nsTreeSelection.h
Normal file
56
layout/xul/tree/nsTreeSelection.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
#ifndef nsTreeSelection_h__
|
||||
#define nsTreeSelection_h__
|
||||
|
||||
#include "nsITreeSelection.h"
|
||||
#include "nsITreeColumns.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsITreeBoxObject;
|
||||
struct nsTreeRange;
|
||||
|
||||
class nsTreeSelection final : public nsINativeTreeSelection
|
||||
{
|
||||
public:
|
||||
explicit nsTreeSelection(nsITreeBoxObject* aTree);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsTreeSelection)
|
||||
NS_DECL_NSITREESELECTION
|
||||
|
||||
// nsINativeTreeSelection: Untrusted code can use us
|
||||
NS_IMETHOD EnsureNative() override { return NS_OK; }
|
||||
|
||||
friend struct nsTreeRange;
|
||||
|
||||
protected:
|
||||
~nsTreeSelection();
|
||||
|
||||
nsresult FireOnSelectHandler();
|
||||
static void SelectCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
nsCOMPtr<nsITreeBoxObject> mTree; // The tree will hold on to us through the view and let go when it dies.
|
||||
|
||||
bool mSuppressed; // Whether or not we should be firing onselect events.
|
||||
int32_t mCurrentIndex; // The item to draw the rect around. The last one clicked, etc.
|
||||
nsCOMPtr<nsITreeColumn> mCurrentColumn;
|
||||
int32_t mShiftSelectPivot; // Used when multiple SHIFT+selects are performed to pivot on.
|
||||
|
||||
nsTreeRange* mFirstRange; // Our list of ranges.
|
||||
|
||||
nsCOMPtr<nsITimer> mSelectTimer;
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewTreeSelection(nsITreeBoxObject* aTree, nsITreeSelection** aResult);
|
||||
|
||||
#endif
|
||||
99
layout/xul/tree/nsTreeStyleCache.cpp
Normal file
99
layout/xul/tree/nsTreeStyleCache.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsTreeStyleCache.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
|
||||
nsTreeStyleCache::Transition::Transition(DFAState aState, nsIAtom* aSymbol)
|
||||
: mState(aState), mInputSymbol(aSymbol)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
nsTreeStyleCache::Transition::operator==(const Transition& aOther) const
|
||||
{
|
||||
return aOther.mState == mState && aOther.mInputSymbol == mInputSymbol;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsTreeStyleCache::Transition::Hash() const
|
||||
{
|
||||
// Make a 32-bit integer that combines the low-order 16 bits of the state and the input symbol.
|
||||
uint32_t hb = mState << 16;
|
||||
uint32_t lb = (NS_PTR_TO_UINT32(mInputSymbol.get()) << 16) >> 16;
|
||||
return hb+lb;
|
||||
}
|
||||
|
||||
|
||||
// The style context cache impl
|
||||
nsStyleContext*
|
||||
nsTreeStyleCache::GetStyleContext(nsICSSPseudoComparator* aComparator,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aContext,
|
||||
nsIAtom* aPseudoElement,
|
||||
const AtomArray & aInputWord)
|
||||
{
|
||||
uint32_t count = aInputWord.Length();
|
||||
|
||||
// Go ahead and init the transition table.
|
||||
if (!mTransitionTable) {
|
||||
// Automatic miss. Build the table
|
||||
mTransitionTable = new TransitionTable();
|
||||
}
|
||||
|
||||
// The first transition is always made off the supplied pseudo-element.
|
||||
Transition transition(0, aPseudoElement);
|
||||
DFAState currState = mTransitionTable->Get(transition);
|
||||
|
||||
if (!currState) {
|
||||
// We had a miss. Make a new state and add it to our hash.
|
||||
currState = mNextState;
|
||||
mNextState++;
|
||||
mTransitionTable->Put(transition, currState);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
Transition transition(currState, aInputWord[i]);
|
||||
currState = mTransitionTable->Get(transition);
|
||||
|
||||
if (!currState) {
|
||||
// We had a miss. Make a new state and add it to our hash.
|
||||
currState = mNextState;
|
||||
mNextState++;
|
||||
mTransitionTable->Put(transition, currState);
|
||||
}
|
||||
}
|
||||
|
||||
// We're in a final state.
|
||||
// Look up our style context for this state.
|
||||
nsStyleContext* result = nullptr;
|
||||
if (mCache) {
|
||||
result = mCache->GetWeak(currState);
|
||||
}
|
||||
if (!result) {
|
||||
// We missed the cache. Resolve this pseudo-style.
|
||||
// XXXheycam ServoStyleSets do not support XUL tree styles.
|
||||
if (aPresContext->StyleSet()->IsServo()) {
|
||||
MOZ_CRASH("stylo: ServoStyleSets should not support XUL tree styles yet");
|
||||
}
|
||||
RefPtr<nsStyleContext> newResult = aPresContext->StyleSet()->AsGecko()->
|
||||
ResolveXULTreePseudoStyle(aContent->AsElement(), aPseudoElement,
|
||||
aContext, aComparator);
|
||||
|
||||
// Put the style context in our table, transferring the owning reference to the table.
|
||||
if (!mCache) {
|
||||
mCache = new StyleContextCache();
|
||||
}
|
||||
result = newResult.get();
|
||||
mCache->Put(currState, newResult.forget());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
89
layout/xul/tree/nsTreeStyleCache.h
Normal file
89
layout/xul/tree/nsTreeStyleCache.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsTreeStyleCache_h__
|
||||
#define nsTreeStyleCache_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsICSSPseudoComparator.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
typedef nsCOMArray<nsIAtom> AtomArray;
|
||||
|
||||
class nsTreeStyleCache
|
||||
{
|
||||
public:
|
||||
nsTreeStyleCache()
|
||||
: mNextState(0)
|
||||
{
|
||||
}
|
||||
|
||||
~nsTreeStyleCache()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mTransitionTable = nullptr;
|
||||
mCache = nullptr;
|
||||
mNextState = 0;
|
||||
}
|
||||
|
||||
nsStyleContext* GetStyleContext(nsICSSPseudoComparator* aComparator,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aContext,
|
||||
nsIAtom* aPseudoElement,
|
||||
const AtomArray & aInputWord);
|
||||
|
||||
protected:
|
||||
typedef uint32_t DFAState;
|
||||
|
||||
class Transition final
|
||||
{
|
||||
public:
|
||||
Transition(DFAState aState, nsIAtom* aSymbol);
|
||||
bool operator==(const Transition& aOther) const;
|
||||
uint32_t Hash() const;
|
||||
|
||||
private:
|
||||
DFAState mState;
|
||||
nsCOMPtr<nsIAtom> mInputSymbol;
|
||||
};
|
||||
|
||||
typedef nsDataHashtable<nsGenericHashKey<Transition>, DFAState> TransitionTable;
|
||||
|
||||
// A transition table for a deterministic finite automaton. The DFA
|
||||
// takes as its input a single pseudoelement and an ordered set of properties.
|
||||
// It transitions on an input word that is the concatenation of the pseudoelement supplied
|
||||
// with the properties in the array.
|
||||
//
|
||||
// It transitions from state to state by looking up entries in the transition table (which is
|
||||
// a mapping from (S,i)->S', where S is the current state, i is the next
|
||||
// property in the input word, and S' is the state to transition to.
|
||||
//
|
||||
// If S' is not found, it is constructed and entered into the hashtable
|
||||
// under the key (S,i).
|
||||
//
|
||||
// Once the entire word has been consumed, the final state is used
|
||||
// to reference the cache table to locate the style context.
|
||||
nsAutoPtr<TransitionTable> mTransitionTable;
|
||||
|
||||
// The cache of all active style contexts. This is a hash from
|
||||
// a final state in the DFA, Sf, to the resultant style context.
|
||||
typedef nsRefPtrHashtable<nsUint32HashKey, nsStyleContext> StyleContextCache;
|
||||
nsAutoPtr<StyleContextCache> mCache;
|
||||
|
||||
// An integer counter that is used when we need to make new states in the
|
||||
// DFA.
|
||||
DFAState mNextState;
|
||||
};
|
||||
|
||||
#endif // nsTreeStyleCache_h__
|
||||
140
layout/xul/tree/nsTreeUtils.cpp
Normal file
140
layout/xul/tree/nsTreeUtils.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsReadableUtils.h"
|
||||
#include "nsTreeUtils.h"
|
||||
#include "ChildIterator.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsresult
|
||||
nsTreeUtils::TokenizeProperties(const nsAString& aProperties, AtomArray & aPropertiesArray)
|
||||
{
|
||||
nsAString::const_iterator end;
|
||||
aProperties.EndReading(end);
|
||||
|
||||
nsAString::const_iterator iter;
|
||||
aProperties.BeginReading(iter);
|
||||
|
||||
do {
|
||||
// Skip whitespace
|
||||
while (iter != end && nsCRT::IsAsciiSpace(*iter))
|
||||
++iter;
|
||||
|
||||
// If only whitespace, we're done
|
||||
if (iter == end)
|
||||
break;
|
||||
|
||||
// Note the first non-whitespace character
|
||||
nsAString::const_iterator first = iter;
|
||||
|
||||
// Advance to the next whitespace character
|
||||
while (iter != end && ! nsCRT::IsAsciiSpace(*iter))
|
||||
++iter;
|
||||
|
||||
// XXX this would be nonsensical
|
||||
NS_ASSERTION(iter != first, "eh? something's wrong here");
|
||||
if (iter == first)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIAtom> atom = NS_Atomize(Substring(first, iter));
|
||||
aPropertiesArray.AppendElement(atom);
|
||||
} while (iter != end);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsTreeUtils::GetImmediateChild(nsIContent* aContainer, nsIAtom* aTag)
|
||||
{
|
||||
dom::FlattenedChildIterator iter(aContainer);
|
||||
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
||||
if (child->IsXULElement(aTag)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsTreeUtils::GetDescendantChild(nsIContent* aContainer, nsIAtom* aTag)
|
||||
{
|
||||
dom::FlattenedChildIterator iter(aContainer);
|
||||
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
||||
if (child->IsXULElement(aTag)) {
|
||||
return child;
|
||||
}
|
||||
|
||||
child = GetDescendantChild(child, aTag);
|
||||
if (child) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeUtils::UpdateSortIndicators(nsIContent* aColumn, const nsAString& aDirection)
|
||||
{
|
||||
aColumn->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, aDirection, true);
|
||||
aColumn->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive, NS_LITERAL_STRING("true"), true);
|
||||
|
||||
// Unset sort attribute(s) on the other columns
|
||||
nsCOMPtr<nsIContent> parentContent = aColumn->GetParent();
|
||||
if (parentContent &&
|
||||
parentContent->NodeInfo()->Equals(nsGkAtoms::treecols,
|
||||
kNameSpaceID_XUL)) {
|
||||
uint32_t i, numChildren = parentContent->GetChildCount();
|
||||
for (i = 0; i < numChildren; ++i) {
|
||||
nsCOMPtr<nsIContent> childContent = parentContent->GetChildAt(i);
|
||||
|
||||
if (childContent &&
|
||||
childContent != aColumn &&
|
||||
childContent->NodeInfo()->Equals(nsGkAtoms::treecol,
|
||||
kNameSpaceID_XUL)) {
|
||||
childContent->UnsetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::sortDirection, true);
|
||||
childContent->UnsetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::sortActive, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTreeUtils::GetColumnIndex(nsIContent* aColumn, int32_t* aResult)
|
||||
{
|
||||
nsIContent* parentContent = aColumn->GetParent();
|
||||
if (parentContent &&
|
||||
parentContent->NodeInfo()->Equals(nsGkAtoms::treecols,
|
||||
kNameSpaceID_XUL)) {
|
||||
uint32_t i, numChildren = parentContent->GetChildCount();
|
||||
int32_t colIndex = 0;
|
||||
for (i = 0; i < numChildren; ++i) {
|
||||
nsIContent *childContent = parentContent->GetChildAt(i);
|
||||
if (childContent &&
|
||||
childContent->NodeInfo()->Equals(nsGkAtoms::treecol,
|
||||
kNameSpaceID_XUL)) {
|
||||
if (childContent == aColumn) {
|
||||
*aResult = colIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
++colIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*aResult = -1;
|
||||
return NS_OK;
|
||||
}
|
||||
39
layout/xul/tree/nsTreeUtils.h
Normal file
39
layout/xul/tree/nsTreeUtils.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef nsTreeUtils_h__
|
||||
#define nsTreeUtils_h__
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTreeStyleCache.h"
|
||||
|
||||
class nsIAtom;
|
||||
class nsIContent;
|
||||
|
||||
class nsTreeUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse a whitespace separated list of properties into an array
|
||||
* of atoms.
|
||||
*/
|
||||
static nsresult
|
||||
TokenizeProperties(const nsAString& aProperties, AtomArray & aPropertiesArray);
|
||||
|
||||
static nsIContent*
|
||||
GetImmediateChild(nsIContent* aContainer, nsIAtom* aTag);
|
||||
|
||||
static nsIContent*
|
||||
GetDescendantChild(nsIContent* aContainer, nsIAtom* aTag);
|
||||
|
||||
static nsresult
|
||||
UpdateSortIndicators(nsIContent* aColumn, const nsAString& aDirection);
|
||||
|
||||
static nsresult
|
||||
GetColumnIndex(nsIContent* aColumn, int32_t* aResult);
|
||||
};
|
||||
|
||||
#endif // nsTreeUtils_h__
|
||||
Loading…
Add table
Add a link
Reference in a new issue