mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 06:45:42 +00:00
menu item enabled state needs to be actively updated based on DOM activity. b=341528 r=mento
This commit is contained in:
parent
358294fe69
commit
bef4565f61
@ -54,11 +54,13 @@ interface nsIDocument;
|
||||
// its corresponding content object.
|
||||
// (NOTE: If we need more things, we can add them later)
|
||||
//
|
||||
[scriptable, uuid(d8cf3bd0-1dd1-11b2-a837-fec5f865b071)]
|
||||
[uuid(f5734700-fb27-11da-974d-0800200c9a66)]
|
||||
interface nsIChangeObserver : nsISupports
|
||||
{
|
||||
void AttributeChanged ( in nsIDocument aDocument,
|
||||
in long aNameSpaceID, in nsIAtom aAttribute ) ;
|
||||
void AttributeChanged(in nsIDocument aDocument,
|
||||
in long aNameSpaceID,
|
||||
in nsIContent aContent,
|
||||
in nsIAtom aAttribute);
|
||||
|
||||
void ContentRemoved ( in nsIDocument aDocument, in nsIContent aChild,
|
||||
in long aIndexInContainer ) ;
|
||||
|
@ -869,7 +869,7 @@ nsMenuBarX::AttributeChanged(nsIDocument * aDocument, nsIContent * aContent,
|
||||
nsCOMPtr<nsIChangeObserver> obs;
|
||||
Lookup(aContent, getter_AddRefs(obs));
|
||||
if (obs)
|
||||
obs->AttributeChanged(aDocument, aNameSpaceID, aAttribute);
|
||||
obs->AttributeChanged(aDocument, aNameSpaceID, aContent, aAttribute);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -113,7 +113,8 @@ protected:
|
||||
nsCOMPtr<nsIMenuListener> mXULCommandListener;
|
||||
|
||||
nsWeakPtr mDocShellWeakRef; // weak ref to docshell
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
nsCOMPtr<nsIContent> mCommandContent;
|
||||
|
||||
PRUint8 mModifiers;
|
||||
PRPackedBool mIsSeparator;
|
||||
|
@ -66,6 +66,7 @@ nsMenuItemX::nsMenuItemX()
|
||||
{
|
||||
mNativeMenuItem = nil;
|
||||
mMenuParent = nsnull;
|
||||
mManager = nsnull;
|
||||
mIsSeparator = PR_FALSE;
|
||||
mKeyEquivalent.AssignLiteral(" ");
|
||||
mEnabled = PR_TRUE;
|
||||
@ -77,7 +78,10 @@ nsMenuItemX::nsMenuItemX()
|
||||
nsMenuItemX::~nsMenuItemX()
|
||||
{
|
||||
[mNativeMenuItem autorelease];
|
||||
mManager->Unregister(mContent);
|
||||
if (mContent)
|
||||
mManager->Unregister(mContent);
|
||||
if (mCommandContent)
|
||||
mManager->Unregister(mCommandContent);
|
||||
}
|
||||
|
||||
|
||||
@ -97,6 +101,27 @@ NS_METHOD nsMenuItemX::Create(nsIMenu* aParent, const nsString & aLabel, PRBool
|
||||
nsCOMPtr<nsIChangeObserver> obs = do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this));
|
||||
mManager->Register(mContent, obs); // does not addref this
|
||||
|
||||
// if we have a command associated with this menu item, register for changes
|
||||
// to the command DOM node
|
||||
nsAutoString ourCommand;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::command, ourCommand);
|
||||
if (!ourCommand.IsEmpty()) {
|
||||
nsIDocument* currDoc = mContent->GetCurrentDoc();
|
||||
if (currDoc) {
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(currDoc));
|
||||
if (domDoc) {
|
||||
// get the command DOM element
|
||||
nsCOMPtr<nsIDOMElement> commandElt;
|
||||
domDoc->GetElementById(ourCommand, getter_AddRefs(commandElt));
|
||||
if (commandElt) {
|
||||
mCommandContent = do_QueryInterface(commandElt);
|
||||
// register to observe the command DOM element
|
||||
mManager->Register(mCommandContent, obs); // does not addref this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mIsSeparator = aIsSeparator;
|
||||
mLabel = aLabel;
|
||||
|
||||
@ -390,23 +415,51 @@ nsMenuItemX::UncheckRadioSiblings(nsIContent* inCheckedContent)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAtom *aAttribute)
|
||||
nsMenuItemX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIContent *aContent, nsIAtom *aAttribute)
|
||||
{
|
||||
if (aAttribute == nsWidgetAtoms::checked) {
|
||||
// if we're a radio menu, uncheck our sibling radio items. No need to
|
||||
// do any of this if we're just a normal check menu.
|
||||
if (mMenuType == eRadio) {
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::checked,
|
||||
nsWidgetAtoms::_true, eCaseMatters))
|
||||
UncheckRadioSiblings(mContent);
|
||||
if (!aContent)
|
||||
return NS_OK;
|
||||
|
||||
if (aContent == mContent) { // our own content node changed
|
||||
if (aAttribute == nsWidgetAtoms::checked) {
|
||||
// if we're a radio menu, uncheck our sibling radio items. No need to
|
||||
// do any of this if we're just a normal check menu.
|
||||
if (mMenuType == eRadio) {
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::checked,
|
||||
nsWidgetAtoms::_true, eCaseMatters))
|
||||
UncheckRadioSiblings(mContent);
|
||||
}
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
}
|
||||
else if (aAttribute == nsWidgetAtoms::hidden ||
|
||||
aAttribute == nsWidgetAtoms::collapsed) {
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
}
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
}
|
||||
else if (aAttribute == nsWidgetAtoms::disabled || aAttribute == nsWidgetAtoms::hidden ||
|
||||
aAttribute == nsWidgetAtoms::collapsed) {
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
else if (aContent == mCommandContent) {
|
||||
// the only thing that really matters when the menu isn't showing is the
|
||||
// enabled state since it enables/disables keyboard commands
|
||||
if (aAttribute == nsWidgetAtoms::disabled) {
|
||||
// first we sync our menu item DOM node with the command DOM node
|
||||
nsAutoString commandDisabled;
|
||||
nsAutoString menuDisabled;
|
||||
aContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, commandDisabled);
|
||||
mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, menuDisabled);
|
||||
if (!commandDisabled.Equals(menuDisabled)) {
|
||||
// The menu's disabled state needs to be updated to match the command.
|
||||
if (commandDisabled.IsEmpty())
|
||||
mContent->UnsetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, PR_TRUE);
|
||||
else
|
||||
mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, commandDisabled, PR_TRUE);
|
||||
}
|
||||
// now we sync our native menu item with the command DOM node
|
||||
if (aContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::disabled, nsWidgetAtoms::_true, eCaseMatters))
|
||||
[mNativeMenuItem setEnabled:NO];
|
||||
else
|
||||
[mNativeMenuItem setEnabled:YES];
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -416,15 +469,19 @@ nsMenuItemX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIA
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX::ContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
{
|
||||
if (aChild == mCommandContent) {
|
||||
mManager->Unregister(mCommandContent);
|
||||
mCommandContent = nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
return NS_OK;
|
||||
|
||||
} // ContentRemoved
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX :: ContentInserted(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
nsMenuItemX::ContentInserted(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
{
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
|
@ -992,7 +992,7 @@ nsMenuX::CountVisibleBefore(PRUint32* outVisibleBefore)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAtom *aAttribute)
|
||||
nsMenuX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIContent *aContent, nsIAtom *aAttribute)
|
||||
{
|
||||
// ignore the |open| attribute, which is by far the most common
|
||||
if (gConstructingMenu || (aAttribute == nsWidgetAtoms::open))
|
||||
|
Loading…
Reference in New Issue
Block a user