allow DOM to unhide menus and menu items whether or not their initial state is hidden. fixes bidi menu items. b=364994 r=mano sr=roc

This commit is contained in:
joshmoz@gmail.com 2007-03-22 17:57:45 -07:00
parent 7a5fefa6c5
commit e660d48ecc
6 changed files with 81 additions and 53 deletions

View File

@ -115,25 +115,29 @@ class nsIMenu : public nsISupports {
NS_IMETHOD GetEnabled(PRBool* aIsEnabled) = 0; NS_IMETHOD GetEnabled(PRBool* aIsEnabled) = 0;
/** /**
* Adds a Menu Item * Adds a Menu Item. Do not use outside of widget menu implementations.
* Add and modify menu items via DOM content.
* *
*/ */
NS_IMETHOD AddItem(nsISupports* aItem) = 0; NS_IMETHOD AddItem(nsISupports* aItem) = 0;
/** /**
* Adds a separator * Adds a separator. Do not use outside of widget menu implementations.
* Add and modify menu separators via DOM content.
* *
*/ */
NS_IMETHOD AddSeparator() = 0; NS_IMETHOD AddSeparator() = 0;
/** /**
* Returns the number of menu items * Returns the number of menu items
* This does count separators as items * This includes separators. It does not include hidden items.
*
*/ */
NS_IMETHOD GetItemCount(PRUint32 &aCount) = 0; NS_IMETHOD GetItemCount(PRUint32 &aCount) = 0;
/** /**
* Returns a Menu or Menu Item at a specified Index * Returns a Menu or Menu Item at a specified Index.
* This includes separators. It does not include hidden items.
* *
*/ */
NS_IMETHOD GetItemAt(const PRUint32 aPos, nsISupports *& aMenuItem) = 0; NS_IMETHOD GetItemAt(const PRUint32 aPos, nsISupports *& aMenuItem) = 0;

View File

@ -45,10 +45,10 @@
#include "nsIDocShell.h" #include "nsIDocShell.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
// {4E3931A7-D7E5-47FC-9489-83928536DA9D} // {F9A30AA5-D526-4C19-8418-C21BF6B31837}
#define NS_IMENUITEM_IID \ #define NS_IMENUITEM_IID \
{ 0x4E3931A7, 0xD7E5, 0x47FC, \ { 0xF9A30AA5, 0xD526, 0x4C19, \
{ 0x94, 0x89, 0x83, 0x92, 0x85, 0x36, 0xDA, 0x9D } } { 0x84, 0x18, 0xC2, 0x1B, 0xF6, 0xB3, 0x18, 0x37 } }
class nsIMenu; class nsIMenu;
class nsIWidget; class nsIWidget;
@ -170,6 +170,12 @@ class nsIMenuItem : public nsISupports {
* Sets an appropriate icon for the menu item. * Sets an appropriate icon for the menu item.
*/ */
NS_IMETHOD SetupIcon() = 0; NS_IMETHOD SetupIcon() = 0;
/**
* Get GetMenuItemContent
*
*/
NS_IMETHOD GetMenuItemContent(nsIContent ** aMenuItemContent) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuItem, NS_IMENUITEM_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuItem, NS_IMENUITEM_IID)

View File

@ -88,6 +88,7 @@ public:
NS_IMETHOD SetModifiers(PRUint8 aModifiers); NS_IMETHOD SetModifiers(PRUint8 aModifiers);
NS_IMETHOD GetModifiers(PRUint8 * aModifiers); NS_IMETHOD GetModifiers(PRUint8 * aModifiers);
NS_IMETHOD SetupIcon(); NS_IMETHOD SetupIcon();
NS_IMETHOD GetMenuItemContent(nsIContent ** aMenuItemContent);
// nsIMenuListener interface // nsIMenuListener interface
nsEventStatus MenuItemSelected(const nsMenuEvent & aMenuEvent); nsEventStatus MenuItemSelected(const nsMenuEvent & aMenuEvent);

View File

@ -513,3 +513,12 @@ nsMenuItemX::SetupIcon()
{ {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP
nsMenuItemX::GetMenuItemContent(nsIContent ** aMenuItemContent)
{
NS_ENSURE_ARG_POINTER(aMenuItemContent);
NS_IF_ADDREF(*aMenuItemContent = mContent);
return NS_OK;
}

View File

@ -136,8 +136,8 @@ protected:
nsresult AddMenuItem(nsIMenuItem * aMenuItem); nsresult AddMenuItem(nsIMenuItem * aMenuItem);
nsresult AddMenu(nsIMenu * aMenu); nsresult AddMenu(nsIMenu * aMenu);
void LoadMenuItem(nsIMenu* pParentMenu, nsIContent* inMenuItemContent); void LoadMenuItem(nsIContent* inMenuItemContent);
void LoadSubMenu(nsIMenu * pParentMenu, nsIContent* inMenuContent); void LoadSubMenu(nsIContent* inMenuContent);
void LoadSeparator(nsIContent* inSeparatorContent); void LoadSeparator(nsIContent* inSeparatorContent);
NSMenu* CreateMenuWithGeckoString(nsString& menuTitle); NSMenu* CreateMenuWithGeckoString(nsString& menuTitle);
@ -145,6 +145,7 @@ protected:
protected: protected:
nsString mLabel; nsString mLabel;
nsCOMArray<nsISupports> mMenuItemsArray; nsCOMArray<nsISupports> mMenuItemsArray;
nsCOMArray<nsISupports> mHiddenMenuItemsArray;
nsISupports* mParent; // weak, my parent owns me nsISupports* mParent; // weak, my parent owns me
nsIChangeManager* mManager; // weak ref, it will outlive us [menubar] nsIChangeManager* mManager; // weak ref, it will outlive us [menubar]

View File

@ -207,21 +207,26 @@ NS_IMETHODIMP nsMenuX::SetAccessKey(const nsAString &aText)
} }
// This should only be used internally by our menu implementation. In all other
// cases menus and their items should be added and modified via the DOM.
NS_IMETHODIMP nsMenuX::AddItem(nsISupports* aItem) NS_IMETHODIMP nsMenuX::AddItem(nsISupports* aItem)
{ {
nsresult rv = NS_ERROR_FAILURE; nsresult rv = NS_ERROR_FAILURE;
if (aItem) {
// Figure out what we're adding if (!aItem)
nsCOMPtr<nsIMenuItem> menuItem(do_QueryInterface(aItem)); return NS_ERROR_INVALID_ARG;
if (menuItem) {
rv = AddMenuItem(menuItem); // Figure out what we're adding
} nsCOMPtr<nsIMenuItem> menuItem(do_QueryInterface(aItem, &rv));
else { if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIMenu> menu(do_QueryInterface(aItem)); rv = AddMenuItem(menuItem);
if (menu)
rv = AddMenu(menu);
}
} }
else {
nsCOMPtr<nsIMenu> menu(do_QueryInterface(aItem, &rv));
if (NS_SUCCEEDED(rv))
rv = AddMenu(menu);
}
return rv; return rv;
} }
@ -231,7 +236,15 @@ nsresult nsMenuX::AddMenuItem(nsIMenuItem * aMenuItem)
if (!aMenuItem) if (!aMenuItem)
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
mMenuItemsArray.AppendObject(aMenuItem); // owning ref nsCOMPtr<nsIContent> menuItemContent;
aMenuItem->GetMenuItemContent(getter_AddRefs(menuItemContent));
if (menuItemContent && NodeIsHiddenOrCollapsed(menuItemContent)) {
mHiddenMenuItemsArray.AppendObject(aMenuItem); // owning ref
return NS_OK;
}
else {
mMenuItemsArray.AppendObject(aMenuItem); // owning ref
}
// add the menu item to this menu // add the menu item to this menu
NSMenuItem* newNativeMenuItem; NSMenuItem* newNativeMenuItem;
@ -263,12 +276,15 @@ nsresult nsMenuX::AddMenu(nsIMenu * aMenu)
if (!aMenu) if (!aMenu)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISupports> supports = do_QueryInterface(aMenu); nsCOMPtr<nsIContent> menuContent;
if (!supports) aMenu->GetMenuContent(getter_AddRefs(menuContent));
return NS_ERROR_NO_INTERFACE; if (menuContent && NodeIsHiddenOrCollapsed(menuContent)) {
mHiddenMenuItemsArray.AppendObject(aMenu); // owning ref
PRUint32 currItemIndex = mMenuItemsArray.Count(); return NS_OK;
mMenuItemsArray.AppendObject(supports); // owning ref }
else {
mMenuItemsArray.AppendObject(aMenu); // owning ref
}
// We have to add a menu item and then associate the menu with it // We have to add a menu item and then associate the menu with it
nsAutoString label; nsAutoString label;
@ -284,7 +300,7 @@ nsresult nsMenuX::AddMenu(nsIMenu * aMenu)
NSMenu* childMenu; NSMenu* childMenu;
if (aMenu->GetNativeData((void**)&childMenu) == NS_OK) if (aMenu->GetNativeData((void**)&childMenu) == NS_OK)
[[mMacMenu itemAtIndex:currItemIndex] setSubmenu:childMenu]; [newNativeMenuItem setSubmenu:childMenu];
return NS_OK; return NS_OK;
} }
@ -294,7 +310,7 @@ NS_IMETHODIMP nsMenuX::AddSeparator()
{ {
// We're not really appending an nsMenuItem but a placeholder needs to be // We're not really appending an nsMenuItem but a placeholder needs to be
// here to make sure that event dispatching isn't off by one. // here to make sure that event dispatching isn't off by one.
mMenuItemsArray.AppendObject(&gDummyMenuItemX); // owning ref mMenuItemsArray.AppendObject(&gDummyMenuItemX); // owning ref
[mMacMenu addItem:[NSMenuItem separatorItem]]; [mMacMenu addItem:[NSMenuItem separatorItem]];
return NS_OK; return NS_OK;
} }
@ -342,6 +358,7 @@ NS_IMETHODIMP nsMenuX::RemoveAll()
} }
// get rid of Gecko menu items // get rid of Gecko menu items
mMenuItemsArray.Clear(); mMenuItemsArray.Clear();
mHiddenMenuItemsArray.Clear();
return NS_OK; return NS_OK;
} }
@ -431,8 +448,7 @@ nsEventStatus nsMenuX::MenuSelected(const nsMenuEvent & aMenuEvent)
// Make sure none of our submenus are the ones that should be handling this // Make sure none of our submenus are the ones that should be handling this
for (PRUint32 i = mMenuItemsArray.Count() - 1; i >= 0; i--) { for (PRUint32 i = mMenuItemsArray.Count() - 1; i >= 0; i--) {
nsISupports* menuSupports = mMenuItemsArray.ObjectAt(i); nsISupports* menuSupports = mMenuItemsArray.ObjectAt(i);
nsCOMPtr<nsIMenu> submenu = do_QueryInterface(menuSupports); nsCOMPtr<nsIMenuListener> menuListener = do_QueryInterface(menuSupports);
nsCOMPtr<nsIMenuListener> menuListener = do_QueryInterface(submenu);
if (menuListener) { if (menuListener) {
eventStatus = menuListener->MenuSelected(aMenuEvent); eventStatus = menuListener->MenuSelected(aMenuEvent);
if (nsEventStatus_eIgnore != eventStatus) if (nsEventStatus_eIgnore != eventStatus)
@ -511,11 +527,11 @@ nsEventStatus nsMenuX::MenuConstruct(
// depending on the type, create a menu item, separator, or submenu // depending on the type, create a menu item, separator, or submenu
nsIAtom *tag = child->Tag(); nsIAtom *tag = child->Tag();
if (tag == nsWidgetAtoms::menuitem) if (tag == nsWidgetAtoms::menuitem)
LoadMenuItem(this, child); LoadMenuItem(child);
else if (tag == nsWidgetAtoms::menuseparator) else if (tag == nsWidgetAtoms::menuseparator)
LoadSeparator(child); LoadSeparator(child);
else if (tag == nsWidgetAtoms::menu) else if (tag == nsWidgetAtoms::menu)
LoadSubMenu(this, child); LoadSubMenu(child);
} }
} // for each menu item } // for each menu item
@ -606,14 +622,11 @@ NSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& menuTitle)
} }
void nsMenuX::LoadMenuItem(nsIMenu* inParentMenu, nsIContent* inMenuItemContent) void nsMenuX::LoadMenuItem(nsIContent* inMenuItemContent)
{ {
if (!inMenuItemContent) if (!inMenuItemContent)
return; return;
if (NodeIsHiddenOrCollapsed(inMenuItemContent))
return;
// create nsMenuItem // create nsMenuItem
nsCOMPtr<nsIMenuItem> pnsMenuItem = do_CreateInstance(kMenuItemCID); nsCOMPtr<nsIMenuItem> pnsMenuItem = do_CreateInstance(kMenuItemCID);
if (!pnsMenuItem) if (!pnsMenuItem)
@ -638,7 +651,7 @@ void nsMenuX::LoadMenuItem(nsIMenu* inParentMenu, nsIContent* inMenuItemContent)
return; return;
// Create the item. // Create the item.
pnsMenuItem->Create(inParentMenu, menuitemName, PR_FALSE, itemType, mManager, pnsMenuItem->Create(this, menuitemName, PR_FALSE, itemType, mManager,
docShell, inMenuItemContent); docShell, inMenuItemContent);
// Set key shortcut and modifiers // Set key shortcut and modifiers
@ -677,16 +690,12 @@ void nsMenuX::LoadMenuItem(nsIMenu* inParentMenu, nsIContent* inMenuItemContent)
else else
pnsMenuItem->SetChecked(PR_FALSE); pnsMenuItem->SetChecked(PR_FALSE);
nsCOMPtr<nsISupports> supports(do_QueryInterface(pnsMenuItem)); AddMenuItem(pnsMenuItem);
inParentMenu->AddItem(supports); // Parent now owns menu item
} }
void nsMenuX::LoadSubMenu(nsIMenu * pParentMenu, nsIContent* inMenuContent) void nsMenuX::LoadSubMenu(nsIContent* inMenuContent)
{ {
if (NodeIsHiddenOrCollapsed(inMenuContent))
return;
nsAutoString menuName; nsAutoString menuName;
inMenuContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::label, menuName); inMenuContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::label, menuName);
//printf("Creating Menu [%s] \n", NS_LossyConvertUTF16toASCII(menuName).get()); //printf("Creating Menu [%s] \n", NS_LossyConvertUTF16toASCII(menuName).get());
@ -700,8 +709,7 @@ void nsMenuX::LoadSubMenu(nsIMenu * pParentMenu, nsIContent* inMenuContent)
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShellWeakRef); nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShellWeakRef);
if (!docShell) if (!docShell)
return; return;
nsCOMPtr<nsISupports> supports(do_QueryInterface(pParentMenu)); pnsMenu->Create(NS_REINTERPRET_CAST(nsISupports*, this), menuName, EmptyString(), mManager, docShell, inMenuContent);
pnsMenu->Create(supports, menuName, EmptyString(), mManager, docShell, inMenuContent);
// set if it's enabled or disabled // set if it's enabled or disabled
if (inMenuContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::disabled, if (inMenuContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::disabled,
@ -710,18 +718,17 @@ void nsMenuX::LoadSubMenu(nsIMenu * pParentMenu, nsIContent* inMenuContent)
else else
pnsMenu->SetEnabled(PR_TRUE); pnsMenu->SetEnabled(PR_TRUE);
// Make nsMenu a child of parent nsMenu. The parent takes ownership AddMenu(pnsMenu);
nsCOMPtr<nsISupports> supports2(do_QueryInterface(pnsMenu));
pParentMenu->AddItem(supports2);
} }
void nsMenuX::LoadSeparator(nsIContent* inSeparatorContent) void nsMenuX::LoadSeparator(nsIContent* inSeparatorContent)
{ {
if (NodeIsHiddenOrCollapsed(inSeparatorContent)) // Currently we don't create nsIMenuItem objects for separators so we can't
return; // track changes in their hidden/collapsed attributes. If it is hidden now it
// is hidden forever.
AddSeparator(); if (!NodeIsHiddenOrCollapsed(inSeparatorContent))
AddSeparator();
} }