mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
Fix for several bugs (12299, 12289, 12295).
This commit is contained in:
parent
ed5a2f8522
commit
b77644e753
@ -360,6 +360,8 @@ public:
|
||||
const nsString& aAttributeValue,
|
||||
nsRDFDOMNodeList* aElements);
|
||||
|
||||
static PRBool IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode);
|
||||
|
||||
// Helper routine that crawls a parent chain looking for a tree element.
|
||||
NS_IMETHOD GetParentTree(nsIDOMXULTreeElement** aTreeElement);
|
||||
|
||||
@ -380,6 +382,7 @@ private:
|
||||
static nsIAtom* kTreeItemAtom;
|
||||
static nsIAtom* kTreeRowAtom;
|
||||
static nsIAtom* kTreeCellAtom;
|
||||
static nsIAtom* kTreeChildrenAtom;
|
||||
|
||||
static nsIAtom* kSelectedAtom;
|
||||
|
||||
@ -425,6 +428,7 @@ nsIAtom* RDFElementImpl::kTreeAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeItemAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeRowAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeCellAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeChildrenAtom;
|
||||
nsIAtom* RDFElementImpl::kSelectedAtom;
|
||||
nsIAtom* RDFElementImpl::kPopupAtom;
|
||||
nsIAtom* RDFElementImpl::kTooltipAtom;
|
||||
@ -518,6 +522,7 @@ RDFElementImpl::RDFElementImpl(PRInt32 aNameSpaceID, nsIAtom* aTag)
|
||||
kTreeItemAtom = NS_NewAtom("treeitem");
|
||||
kTreeRowAtom = NS_NewAtom("treerow");
|
||||
kTreeCellAtom = NS_NewAtom("treecell");
|
||||
kTreeChildrenAtom = NS_NewAtom("treechildren");
|
||||
kSelectedAtom = NS_NewAtom("selected");
|
||||
kPopupAtom = NS_NewAtom("popup");
|
||||
kTooltipAtom = NS_NewAtom("tooltip");
|
||||
@ -599,6 +604,7 @@ RDFElementImpl::~RDFElementImpl()
|
||||
NS_IF_RELEASE(kTreeItemAtom);
|
||||
NS_IF_RELEASE(kTreeRowAtom);
|
||||
NS_IF_RELEASE(kTreeCellAtom);
|
||||
NS_IF_RELEASE(kTreeChildrenAtom);
|
||||
NS_IF_RELEASE(kSelectedAtom);
|
||||
NS_IF_RELEASE(kPopupAtom);
|
||||
NS_IF_RELEASE(kContextAtom);
|
||||
@ -1632,16 +1638,13 @@ RDFElementImpl::GetParent(nsIContent*& aResult) const
|
||||
NS_IMETHODIMP
|
||||
RDFElementImpl::SetParent(nsIContent* aParent)
|
||||
{
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// This is the point where we teach an observes node's parent that it is a broadcast
|
||||
// listener.
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
nsCOMPtr<nsIAtom> tagName;
|
||||
GetTag(*getter_AddRefs(tagName));
|
||||
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
if (tagName && tagName.get() == kObservesAtom) {
|
||||
// Find the node that we're supposed to be
|
||||
// observing and perform the hookup.
|
||||
@ -1877,6 +1880,70 @@ RDFElementImpl::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
|
||||
if (! oldKid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
|
||||
// the possibility exists that some of the items in the removed subtree
|
||||
// are selected (and therefore need to be deselected). We need to account for this.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
oldKid->GetTag(*getter_AddRefs(tag));
|
||||
if (tag && (tag.get() == kTreeChildrenAtom || tag.get() == kTreeItemAtom ||
|
||||
tag.get() == kTreeCellAtom)) {
|
||||
// This is the nasty case. We have (potentially) a slew of selected items
|
||||
// and cells going away.
|
||||
// First, retrieve the tree.
|
||||
nsRDFDOMNodeList* itemList = nsnull;
|
||||
nsRDFDOMNodeList* cellList = nsnull;
|
||||
nsCOMPtr<nsIDOMXULTreeElement> treeElement;
|
||||
GetParentTree(getter_AddRefs(treeElement));
|
||||
if (treeElement) {
|
||||
nsCOMPtr<nsIDOMNodeList> nodes;
|
||||
treeElement->GetSelectedItems(getter_AddRefs(nodes));
|
||||
itemList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
treeElement->GetSelectedCells(getter_AddRefs(nodes));
|
||||
cellList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
nsCOMPtr<nsIDOMNode> parentKid = do_QueryInterface(oldKid);
|
||||
PRBool fireSelectionHandler = PR_FALSE;
|
||||
if (itemList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
itemList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
itemList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cellList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
cellList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
cellList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fireSelectionHandler) {
|
||||
nsXULTreeElement* tree = (nsXULTreeElement*)(treeElement.get()); // XXX Yes, I am evil.
|
||||
tree->FireOnSelectHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldKid) {
|
||||
nsIDocument* doc = mDocument;
|
||||
PRBool removeOk = mChildren->RemoveElementAt(aIndex);
|
||||
@ -2586,20 +2653,24 @@ RDFElementImpl::HandleDOMEvent(nsIPresContext& aPresContext,
|
||||
if (NS_EVENT_FLAG_INIT == aFlags) {
|
||||
aDOMEvent = &domEvent;
|
||||
aEvent->flags = NS_EVENT_FLAG_NONE;
|
||||
// In order for the event to have a proper target for menus (which have no corresponding
|
||||
// frame target in the visual model), we have to explicitly set the target of the
|
||||
// event to prevent it from trying to retrieve the target from a frame.
|
||||
// In order for the event to have a proper target for events that don't go through
|
||||
// the presshell (onselect, oncommand, oncreate, ondestroy) we need to set our target
|
||||
// ourselves. Also, key sets and menus don't have frames and therefore need their
|
||||
// targets explicitly specified.
|
||||
nsAutoString tagName;
|
||||
GetTagName(tagName);
|
||||
if (tagName == "menu" || tagName == "menuitem" ||
|
||||
if (aEvent->message == NS_MENU_ACTION || aEvent->message == NS_MENU_CREATE ||
|
||||
aEvent->message == NS_MENU_DESTROY || aEvent->message == NS_FORM_SELECTED ||
|
||||
aEvent->message == NS_FORM_CHANGE ||
|
||||
tagName == "menu" || tagName == "menuitem" ||
|
||||
tagName == "menubar" || tagName == "key" || tagName == "keyset") {
|
||||
nsCOMPtr<nsIEventListenerManager> listenerManager;
|
||||
if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) {
|
||||
NS_ERROR("Unable to instantiate a listener manager on a menu/key event.");
|
||||
NS_ERROR("Unable to instantiate a listener manager on this event.");
|
||||
return ret;
|
||||
}
|
||||
if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent, aDOMEvent))) {
|
||||
NS_ERROR("Menu/key event will fail without the ability to create the event early.");
|
||||
NS_ERROR("This event will fail without the ability to create the event early.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3308,3 +3379,17 @@ RDFElementImpl::GetParentTree(nsIDOMXULTreeElement** aTreeElement)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
RDFElementImpl::IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent = dont_QueryInterface(aChildNode);
|
||||
while (parent && (parent.get() != aParentNode)) {
|
||||
nsCOMPtr<nsIDOMNode> newParent;
|
||||
parent->GetParentNode(getter_AddRefs(newParent));
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
if (parent)
|
||||
return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsString.h"
|
||||
|
||||
nsIAtom* nsXULTreeElement::kSelectedAtom;
|
||||
int nsXULTreeElement::gRefCnt = 0;
|
||||
@ -312,6 +313,14 @@ nsXULTreeElement::FireOnSelectHandler()
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
content->GetDocument(*getter_AddRefs(document));
|
||||
|
||||
// The frame code can suppress the firing of this handler by setting an attribute
|
||||
// for us. Look for that and bail if it's present.
|
||||
nsCOMPtr<nsIAtom> kSuppressSelectChange = dont_AddRef(NS_NewAtom("suppressonselect"));
|
||||
nsAutoString value;
|
||||
content->GetAttribute(kNameSpaceID_None, kSuppressSelectChange, value);
|
||||
if (value == "true")
|
||||
return;
|
||||
|
||||
PRInt32 count = document->GetNumberOfShells();
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
nsIPresShell* shell = document->GetShellAt(i);
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
static nsIAtom* kSelectedAtom;
|
||||
static int gRefCnt;
|
||||
|
||||
void FireOnSelectHandler();
|
||||
|
||||
protected:
|
||||
// Helpers
|
||||
void ClearItemSelectionInternal();
|
||||
@ -63,8 +65,6 @@ protected:
|
||||
void AddCellToSelectionInternal(nsIDOMXULElement* aTreeCell);
|
||||
void RemoveCellFromSelectionInternal(nsIDOMXULElement* aTreeCell);
|
||||
|
||||
void FireOnSelectHandler();
|
||||
|
||||
protected:
|
||||
nsRDFDOMNodeList* mSelectedItems;
|
||||
nsRDFDOMNodeList* mSelectedCells;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsTreeCellFrame.h"
|
||||
#include "nsCellMap.h"
|
||||
#include "nsIDOMXULTreeElement.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
|
||||
//
|
||||
// NS_NewTreeFrame
|
||||
@ -71,7 +72,11 @@ void nsTreeFrame::SetSelection(nsIPresContext& aPresContext, nsTreeCellFrame* aF
|
||||
nsCOMPtr<nsIDOMXULTreeElement> treeElement = do_QueryInterface(mContent);
|
||||
nsCOMPtr<nsIDOMXULElement> cellElement = do_QueryInterface(cellContent);
|
||||
nsCOMPtr<nsIDOMXULElement> itemElement = do_QueryInterface(itemContent);
|
||||
|
||||
nsCOMPtr<nsIAtom> kSuppressSelectChange = dont_AddRef(NS_NewAtom("suppressonselect"));
|
||||
mContent->SetAttribute(kNameSpaceID_None, kSuppressSelectChange, "true", PR_FALSE);
|
||||
treeElement->SelectItem(itemElement);
|
||||
mContent->UnsetAttribute(kNameSpaceID_None, kSuppressSelectChange, PR_FALSE);
|
||||
treeElement->SelectCell(cellElement);
|
||||
}
|
||||
|
||||
@ -90,7 +95,10 @@ void nsTreeFrame::ToggleSelection(nsIPresContext& aPresContext, nsTreeCellFrame*
|
||||
nsCOMPtr<nsIDOMXULElement> cellElement = do_QueryInterface(cellContent);
|
||||
nsCOMPtr<nsIDOMXULElement> itemElement = do_QueryInterface(itemContent);
|
||||
|
||||
nsCOMPtr<nsIAtom> kSuppressSelectChange = dont_AddRef(NS_NewAtom("suppressonselect"));
|
||||
mContent->SetAttribute(kNameSpaceID_None, kSuppressSelectChange, "true", PR_FALSE);
|
||||
treeElement->ToggleItemSelection(itemElement);
|
||||
mContent->UnsetAttribute(kNameSpaceID_None, kSuppressSelectChange, PR_FALSE);
|
||||
treeElement->ToggleCellSelection(cellElement);
|
||||
}
|
||||
|
||||
|
@ -360,6 +360,8 @@ public:
|
||||
const nsString& aAttributeValue,
|
||||
nsRDFDOMNodeList* aElements);
|
||||
|
||||
static PRBool IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode);
|
||||
|
||||
// Helper routine that crawls a parent chain looking for a tree element.
|
||||
NS_IMETHOD GetParentTree(nsIDOMXULTreeElement** aTreeElement);
|
||||
|
||||
@ -380,6 +382,7 @@ private:
|
||||
static nsIAtom* kTreeItemAtom;
|
||||
static nsIAtom* kTreeRowAtom;
|
||||
static nsIAtom* kTreeCellAtom;
|
||||
static nsIAtom* kTreeChildrenAtom;
|
||||
|
||||
static nsIAtom* kSelectedAtom;
|
||||
|
||||
@ -425,6 +428,7 @@ nsIAtom* RDFElementImpl::kTreeAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeItemAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeRowAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeCellAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeChildrenAtom;
|
||||
nsIAtom* RDFElementImpl::kSelectedAtom;
|
||||
nsIAtom* RDFElementImpl::kPopupAtom;
|
||||
nsIAtom* RDFElementImpl::kTooltipAtom;
|
||||
@ -518,6 +522,7 @@ RDFElementImpl::RDFElementImpl(PRInt32 aNameSpaceID, nsIAtom* aTag)
|
||||
kTreeItemAtom = NS_NewAtom("treeitem");
|
||||
kTreeRowAtom = NS_NewAtom("treerow");
|
||||
kTreeCellAtom = NS_NewAtom("treecell");
|
||||
kTreeChildrenAtom = NS_NewAtom("treechildren");
|
||||
kSelectedAtom = NS_NewAtom("selected");
|
||||
kPopupAtom = NS_NewAtom("popup");
|
||||
kTooltipAtom = NS_NewAtom("tooltip");
|
||||
@ -599,6 +604,7 @@ RDFElementImpl::~RDFElementImpl()
|
||||
NS_IF_RELEASE(kTreeItemAtom);
|
||||
NS_IF_RELEASE(kTreeRowAtom);
|
||||
NS_IF_RELEASE(kTreeCellAtom);
|
||||
NS_IF_RELEASE(kTreeChildrenAtom);
|
||||
NS_IF_RELEASE(kSelectedAtom);
|
||||
NS_IF_RELEASE(kPopupAtom);
|
||||
NS_IF_RELEASE(kContextAtom);
|
||||
@ -1632,16 +1638,13 @@ RDFElementImpl::GetParent(nsIContent*& aResult) const
|
||||
NS_IMETHODIMP
|
||||
RDFElementImpl::SetParent(nsIContent* aParent)
|
||||
{
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// This is the point where we teach an observes node's parent that it is a broadcast
|
||||
// listener.
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
nsCOMPtr<nsIAtom> tagName;
|
||||
GetTag(*getter_AddRefs(tagName));
|
||||
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
if (tagName && tagName.get() == kObservesAtom) {
|
||||
// Find the node that we're supposed to be
|
||||
// observing and perform the hookup.
|
||||
@ -1877,6 +1880,70 @@ RDFElementImpl::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
|
||||
if (! oldKid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
|
||||
// the possibility exists that some of the items in the removed subtree
|
||||
// are selected (and therefore need to be deselected). We need to account for this.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
oldKid->GetTag(*getter_AddRefs(tag));
|
||||
if (tag && (tag.get() == kTreeChildrenAtom || tag.get() == kTreeItemAtom ||
|
||||
tag.get() == kTreeCellAtom)) {
|
||||
// This is the nasty case. We have (potentially) a slew of selected items
|
||||
// and cells going away.
|
||||
// First, retrieve the tree.
|
||||
nsRDFDOMNodeList* itemList = nsnull;
|
||||
nsRDFDOMNodeList* cellList = nsnull;
|
||||
nsCOMPtr<nsIDOMXULTreeElement> treeElement;
|
||||
GetParentTree(getter_AddRefs(treeElement));
|
||||
if (treeElement) {
|
||||
nsCOMPtr<nsIDOMNodeList> nodes;
|
||||
treeElement->GetSelectedItems(getter_AddRefs(nodes));
|
||||
itemList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
treeElement->GetSelectedCells(getter_AddRefs(nodes));
|
||||
cellList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
nsCOMPtr<nsIDOMNode> parentKid = do_QueryInterface(oldKid);
|
||||
PRBool fireSelectionHandler = PR_FALSE;
|
||||
if (itemList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
itemList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
itemList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cellList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
cellList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
cellList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fireSelectionHandler) {
|
||||
nsXULTreeElement* tree = (nsXULTreeElement*)(treeElement.get()); // XXX Yes, I am evil.
|
||||
tree->FireOnSelectHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldKid) {
|
||||
nsIDocument* doc = mDocument;
|
||||
PRBool removeOk = mChildren->RemoveElementAt(aIndex);
|
||||
@ -2586,20 +2653,24 @@ RDFElementImpl::HandleDOMEvent(nsIPresContext& aPresContext,
|
||||
if (NS_EVENT_FLAG_INIT == aFlags) {
|
||||
aDOMEvent = &domEvent;
|
||||
aEvent->flags = NS_EVENT_FLAG_NONE;
|
||||
// In order for the event to have a proper target for menus (which have no corresponding
|
||||
// frame target in the visual model), we have to explicitly set the target of the
|
||||
// event to prevent it from trying to retrieve the target from a frame.
|
||||
// In order for the event to have a proper target for events that don't go through
|
||||
// the presshell (onselect, oncommand, oncreate, ondestroy) we need to set our target
|
||||
// ourselves. Also, key sets and menus don't have frames and therefore need their
|
||||
// targets explicitly specified.
|
||||
nsAutoString tagName;
|
||||
GetTagName(tagName);
|
||||
if (tagName == "menu" || tagName == "menuitem" ||
|
||||
if (aEvent->message == NS_MENU_ACTION || aEvent->message == NS_MENU_CREATE ||
|
||||
aEvent->message == NS_MENU_DESTROY || aEvent->message == NS_FORM_SELECTED ||
|
||||
aEvent->message == NS_FORM_CHANGE ||
|
||||
tagName == "menu" || tagName == "menuitem" ||
|
||||
tagName == "menubar" || tagName == "key" || tagName == "keyset") {
|
||||
nsCOMPtr<nsIEventListenerManager> listenerManager;
|
||||
if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) {
|
||||
NS_ERROR("Unable to instantiate a listener manager on a menu/key event.");
|
||||
NS_ERROR("Unable to instantiate a listener manager on this event.");
|
||||
return ret;
|
||||
}
|
||||
if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent, aDOMEvent))) {
|
||||
NS_ERROR("Menu/key event will fail without the ability to create the event early.");
|
||||
NS_ERROR("This event will fail without the ability to create the event early.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3308,3 +3379,17 @@ RDFElementImpl::GetParentTree(nsIDOMXULTreeElement** aTreeElement)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
RDFElementImpl::IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent = dont_QueryInterface(aChildNode);
|
||||
while (parent && (parent.get() != aParentNode)) {
|
||||
nsCOMPtr<nsIDOMNode> newParent;
|
||||
parent->GetParentNode(getter_AddRefs(newParent));
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
if (parent)
|
||||
return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -360,6 +360,8 @@ public:
|
||||
const nsString& aAttributeValue,
|
||||
nsRDFDOMNodeList* aElements);
|
||||
|
||||
static PRBool IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode);
|
||||
|
||||
// Helper routine that crawls a parent chain looking for a tree element.
|
||||
NS_IMETHOD GetParentTree(nsIDOMXULTreeElement** aTreeElement);
|
||||
|
||||
@ -380,6 +382,7 @@ private:
|
||||
static nsIAtom* kTreeItemAtom;
|
||||
static nsIAtom* kTreeRowAtom;
|
||||
static nsIAtom* kTreeCellAtom;
|
||||
static nsIAtom* kTreeChildrenAtom;
|
||||
|
||||
static nsIAtom* kSelectedAtom;
|
||||
|
||||
@ -425,6 +428,7 @@ nsIAtom* RDFElementImpl::kTreeAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeItemAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeRowAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeCellAtom;
|
||||
nsIAtom* RDFElementImpl::kTreeChildrenAtom;
|
||||
nsIAtom* RDFElementImpl::kSelectedAtom;
|
||||
nsIAtom* RDFElementImpl::kPopupAtom;
|
||||
nsIAtom* RDFElementImpl::kTooltipAtom;
|
||||
@ -518,6 +522,7 @@ RDFElementImpl::RDFElementImpl(PRInt32 aNameSpaceID, nsIAtom* aTag)
|
||||
kTreeItemAtom = NS_NewAtom("treeitem");
|
||||
kTreeRowAtom = NS_NewAtom("treerow");
|
||||
kTreeCellAtom = NS_NewAtom("treecell");
|
||||
kTreeChildrenAtom = NS_NewAtom("treechildren");
|
||||
kSelectedAtom = NS_NewAtom("selected");
|
||||
kPopupAtom = NS_NewAtom("popup");
|
||||
kTooltipAtom = NS_NewAtom("tooltip");
|
||||
@ -599,6 +604,7 @@ RDFElementImpl::~RDFElementImpl()
|
||||
NS_IF_RELEASE(kTreeItemAtom);
|
||||
NS_IF_RELEASE(kTreeRowAtom);
|
||||
NS_IF_RELEASE(kTreeCellAtom);
|
||||
NS_IF_RELEASE(kTreeChildrenAtom);
|
||||
NS_IF_RELEASE(kSelectedAtom);
|
||||
NS_IF_RELEASE(kPopupAtom);
|
||||
NS_IF_RELEASE(kContextAtom);
|
||||
@ -1632,16 +1638,13 @@ RDFElementImpl::GetParent(nsIContent*& aResult) const
|
||||
NS_IMETHODIMP
|
||||
RDFElementImpl::SetParent(nsIContent* aParent)
|
||||
{
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// This is the point where we teach an observes node's parent that it is a broadcast
|
||||
// listener.
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
nsCOMPtr<nsIAtom> tagName;
|
||||
GetTag(*getter_AddRefs(tagName));
|
||||
|
||||
mParent = aParent; // no refcount
|
||||
|
||||
// If we're an observes node, then we need to add our parent element
|
||||
// as a broadcast listener.
|
||||
if (tagName && tagName.get() == kObservesAtom) {
|
||||
// Find the node that we're supposed to be
|
||||
// observing and perform the hookup.
|
||||
@ -1877,6 +1880,70 @@ RDFElementImpl::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
|
||||
if (! oldKid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
|
||||
// the possibility exists that some of the items in the removed subtree
|
||||
// are selected (and therefore need to be deselected). We need to account for this.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
oldKid->GetTag(*getter_AddRefs(tag));
|
||||
if (tag && (tag.get() == kTreeChildrenAtom || tag.get() == kTreeItemAtom ||
|
||||
tag.get() == kTreeCellAtom)) {
|
||||
// This is the nasty case. We have (potentially) a slew of selected items
|
||||
// and cells going away.
|
||||
// First, retrieve the tree.
|
||||
nsRDFDOMNodeList* itemList = nsnull;
|
||||
nsRDFDOMNodeList* cellList = nsnull;
|
||||
nsCOMPtr<nsIDOMXULTreeElement> treeElement;
|
||||
GetParentTree(getter_AddRefs(treeElement));
|
||||
if (treeElement) {
|
||||
nsCOMPtr<nsIDOMNodeList> nodes;
|
||||
treeElement->GetSelectedItems(getter_AddRefs(nodes));
|
||||
itemList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
treeElement->GetSelectedCells(getter_AddRefs(nodes));
|
||||
cellList = (nsRDFDOMNodeList*)(nodes.get()); // XXX I am evil. Hear me roar.
|
||||
nsCOMPtr<nsIDOMNode> parentKid = do_QueryInterface(oldKid);
|
||||
PRBool fireSelectionHandler = PR_FALSE;
|
||||
if (itemList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
itemList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
itemList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cellList) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
PRUint32 length;
|
||||
cellList->GetLength(&length);
|
||||
for (PRUint32 i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
cellList->Item(i, getter_AddRefs(node));
|
||||
if (IsAncestor(parentKid, node)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
content->UnsetAttribute(kNameSpaceID_None, kSelectedAtom, PR_FALSE);
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fireSelectionHandler) {
|
||||
nsXULTreeElement* tree = (nsXULTreeElement*)(treeElement.get()); // XXX Yes, I am evil.
|
||||
tree->FireOnSelectHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldKid) {
|
||||
nsIDocument* doc = mDocument;
|
||||
PRBool removeOk = mChildren->RemoveElementAt(aIndex);
|
||||
@ -2586,20 +2653,24 @@ RDFElementImpl::HandleDOMEvent(nsIPresContext& aPresContext,
|
||||
if (NS_EVENT_FLAG_INIT == aFlags) {
|
||||
aDOMEvent = &domEvent;
|
||||
aEvent->flags = NS_EVENT_FLAG_NONE;
|
||||
// In order for the event to have a proper target for menus (which have no corresponding
|
||||
// frame target in the visual model), we have to explicitly set the target of the
|
||||
// event to prevent it from trying to retrieve the target from a frame.
|
||||
// In order for the event to have a proper target for events that don't go through
|
||||
// the presshell (onselect, oncommand, oncreate, ondestroy) we need to set our target
|
||||
// ourselves. Also, key sets and menus don't have frames and therefore need their
|
||||
// targets explicitly specified.
|
||||
nsAutoString tagName;
|
||||
GetTagName(tagName);
|
||||
if (tagName == "menu" || tagName == "menuitem" ||
|
||||
if (aEvent->message == NS_MENU_ACTION || aEvent->message == NS_MENU_CREATE ||
|
||||
aEvent->message == NS_MENU_DESTROY || aEvent->message == NS_FORM_SELECTED ||
|
||||
aEvent->message == NS_FORM_CHANGE ||
|
||||
tagName == "menu" || tagName == "menuitem" ||
|
||||
tagName == "menubar" || tagName == "key" || tagName == "keyset") {
|
||||
nsCOMPtr<nsIEventListenerManager> listenerManager;
|
||||
if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) {
|
||||
NS_ERROR("Unable to instantiate a listener manager on a menu/key event.");
|
||||
NS_ERROR("Unable to instantiate a listener manager on this event.");
|
||||
return ret;
|
||||
}
|
||||
if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent, aDOMEvent))) {
|
||||
NS_ERROR("Menu/key event will fail without the ability to create the event early.");
|
||||
NS_ERROR("This event will fail without the ability to create the event early.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3308,3 +3379,17 @@ RDFElementImpl::GetParentTree(nsIDOMXULTreeElement** aTreeElement)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
RDFElementImpl::IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent = dont_QueryInterface(aChildNode);
|
||||
while (parent && (parent.get() != aParentNode)) {
|
||||
nsCOMPtr<nsIDOMNode> newParent;
|
||||
parent->GetParentNode(getter_AddRefs(newParent));
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
if (parent)
|
||||
return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsString.h"
|
||||
|
||||
nsIAtom* nsXULTreeElement::kSelectedAtom;
|
||||
int nsXULTreeElement::gRefCnt = 0;
|
||||
@ -312,6 +313,14 @@ nsXULTreeElement::FireOnSelectHandler()
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
content->GetDocument(*getter_AddRefs(document));
|
||||
|
||||
// The frame code can suppress the firing of this handler by setting an attribute
|
||||
// for us. Look for that and bail if it's present.
|
||||
nsCOMPtr<nsIAtom> kSuppressSelectChange = dont_AddRef(NS_NewAtom("suppressonselect"));
|
||||
nsAutoString value;
|
||||
content->GetAttribute(kNameSpaceID_None, kSuppressSelectChange, value);
|
||||
if (value == "true")
|
||||
return;
|
||||
|
||||
PRInt32 count = document->GetNumberOfShells();
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
nsIPresShell* shell = document->GetShellAt(i);
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
static nsIAtom* kSelectedAtom;
|
||||
static int gRefCnt;
|
||||
|
||||
void FireOnSelectHandler();
|
||||
|
||||
protected:
|
||||
// Helpers
|
||||
void ClearItemSelectionInternal();
|
||||
@ -63,8 +65,6 @@ protected:
|
||||
void AddCellToSelectionInternal(nsIDOMXULElement* aTreeCell);
|
||||
void RemoveCellFromSelectionInternal(nsIDOMXULElement* aTreeCell);
|
||||
|
||||
void FireOnSelectHandler();
|
||||
|
||||
protected:
|
||||
nsRDFDOMNodeList* mSelectedItems;
|
||||
nsRDFDOMNodeList* mSelectedCells;
|
||||
|
Loading…
Reference in New Issue
Block a user