зеркало из https://github.com/mozilla/pjs.git
refactor menu item code in cocoa widgets. also allow menu items to be disabled. b=316076 r=mento sr=pinkerton
This commit is contained in:
Родитель
19aceeea8b
Коммит
185ae97b7e
|
@ -63,6 +63,7 @@ namespace MenuHelpersX
|
|||
nsresult DocShellToPresContext(nsIDocShell* inDocShell, nsPresContext** outContext);
|
||||
nsEventStatus DispatchCommandTo(nsIWeakReference* aDocShellWeakRef,
|
||||
nsIContent* aTargetContent);
|
||||
NSString* CreateTruncatedCocoaLabel(nsString itemLabel);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -905,3 +905,16 @@ MenuHelpersX::DispatchCommandTo(nsIWeakReference* aDocShellWeakRef,
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
NSString* MenuHelpersX::CreateTruncatedCocoaLabel(nsString itemLabel)
|
||||
{
|
||||
// ::TruncateThemeText() doesn't take the number of characters to truncate to, it takes a pixel with
|
||||
// to fit the string in. Ugh. I talked it over with sfraser and we couldn't come up with an
|
||||
// easy way to compute what this should be given the system font, etc, so we're just going
|
||||
// to hard code it to something reasonable and bigger fonts will just have to deal.
|
||||
const short kMaxItemPixelWidth = 300;
|
||||
CFMutableStringRef labelRef = ::CFStringCreateMutable(kCFAllocatorDefault, itemLabel.Length());
|
||||
::CFStringAppendCharacters(labelRef, (UniChar*)itemLabel.get(), itemLabel.Length());
|
||||
::TruncateThemeText(labelRef, kThemeMenuItemFont, kThemeStateActive, kMaxItemPixelWidth, truncMiddle, NULL);
|
||||
return (NSString*)labelRef; // caller releases
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -38,7 +39,6 @@
|
|||
#ifndef nsMenuItemX_h__
|
||||
#define nsMenuItemX_h__
|
||||
|
||||
|
||||
#include "nsIMenuItem.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIMenuListener.h"
|
||||
|
@ -46,6 +46,8 @@
|
|||
#include "nsWeakReference.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
class nsIMenu;
|
||||
|
||||
/**
|
||||
|
@ -66,9 +68,9 @@ public:
|
|||
NS_DECL_NSICHANGEOBSERVER
|
||||
|
||||
// nsIMenuItem Methods
|
||||
NS_IMETHOD Create ( nsIMenu* aParent, const nsString & aLabel, PRBool aIsSeparator,
|
||||
EMenuItemType aItemType, PRBool aEnabled,
|
||||
nsIChangeManager* aManager, nsIDocShell* aShell, nsIContent* aNode ) ;
|
||||
NS_IMETHOD Create (nsIMenu* aParent, const nsString & aLabel, PRBool aIsSeparator,
|
||||
EMenuItemType aItemType, PRBool aEnabled,
|
||||
nsIChangeManager* aManager, nsIDocShell* aShell, nsIContent* aNode);
|
||||
NS_IMETHOD GetLabel(nsString &aText);
|
||||
NS_IMETHOD SetShortcutChar(const nsString &aText);
|
||||
NS_IMETHOD GetShortcutChar(nsString &aText);
|
||||
|
@ -91,7 +93,7 @@ public:
|
|||
nsEventStatus MenuSelected(const nsMenuEvent & aMenuEvent);
|
||||
nsEventStatus MenuDeselected(const nsMenuEvent & aMenuEvent);
|
||||
nsEventStatus MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget * aParentWindow,
|
||||
void * menuNode, void * aDocShell);
|
||||
void * menuNode, void * aDocShell);
|
||||
nsEventStatus MenuDestruct(const nsMenuEvent & aMenuEvent);
|
||||
nsEventStatus CheckRebuild(PRBool & aMenuEvent);
|
||||
nsEventStatus SetRebuild(PRBool aMenuEvent);
|
||||
|
@ -100,8 +102,10 @@ protected:
|
|||
|
||||
void UncheckRadioSiblings ( nsIContent* inCheckedElement ) ;
|
||||
|
||||
nsString mLabel;
|
||||
nsString mKeyEquivalent;
|
||||
NSMenuItem* mNativeMenuItem; // strong ref, we own
|
||||
|
||||
nsString mLabel;
|
||||
nsString mKeyEquivalent;
|
||||
|
||||
nsIMenu* mMenuParent; // weak, parent owns us
|
||||
nsIChangeManager* mManager; // weak
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -40,7 +41,7 @@
|
|||
#include "nsIContent.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
#include "nsMenuBarX.h" // for MenuHelpers namespace
|
||||
#include "nsMenuBarX.h" // for MenuHelpers namespace
|
||||
#include "nsMenuItemX.h"
|
||||
#include "nsIMenu.h"
|
||||
#include "nsIMenuBar.h"
|
||||
|
@ -55,49 +56,34 @@
|
|||
#include "nsGUIEvent.h"
|
||||
|
||||
|
||||
#if 0
|
||||
nsInstanceCounter gMenuItemCounterX("nsMenuItemX");
|
||||
#endif
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS4(nsMenuItemX, nsIMenuItem, nsIMenuListener, nsIChangeObserver, nsISupportsWeakReference)
|
||||
|
||||
//
|
||||
// nsMenuItemX constructor
|
||||
//
|
||||
|
||||
nsMenuItemX::nsMenuItemX()
|
||||
{
|
||||
mNativeMenuItem = nil;
|
||||
mMenuParent = nsnull;
|
||||
mIsSeparator = PR_FALSE;
|
||||
mKeyEquivalent.AssignLiteral(" ");
|
||||
mEnabled = PR_TRUE;
|
||||
mIsChecked = PR_FALSE;
|
||||
mMenuType = eRegular;
|
||||
|
||||
#if 0
|
||||
++gMenuItemCounterX;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// nsMenuItemX destructor
|
||||
//
|
||||
|
||||
nsMenuItemX::~nsMenuItemX()
|
||||
{
|
||||
[mNativeMenuItem release];
|
||||
mManager->Unregister(mContent);
|
||||
|
||||
#if 0
|
||||
--gMenuItemCounterX;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::Create ( nsIMenu* aParent, const nsString & aLabel, PRBool aIsSeparator,
|
||||
EMenuItemType aItemType, PRBool aEnabled,
|
||||
nsIChangeManager* aManager, nsIDocShell* aShell, nsIContent* aNode )
|
||||
NS_METHOD nsMenuItemX::Create(nsIMenu* aParent, const nsString & aLabel, PRBool aIsSeparator,
|
||||
EMenuItemType aItemType, PRBool aEnabled,
|
||||
nsIChangeManager* aManager, nsIDocShell* aShell, nsIContent* aNode)
|
||||
{
|
||||
mContent = aNode; // addref
|
||||
mMenuParent = aParent; // weak
|
||||
mContent = aNode; // addref
|
||||
mMenuParent = aParent; // weak
|
||||
mDocShellWeakRef = do_GetWeakReference(aShell);
|
||||
|
||||
mEnabled = aEnabled;
|
||||
|
@ -106,10 +92,23 @@ NS_METHOD nsMenuItemX::Create ( nsIMenu* aParent, const nsString & aLabel, PRBoo
|
|||
// register for AttributeChanged messages
|
||||
mManager = aManager;
|
||||
nsCOMPtr<nsIChangeObserver> obs = do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this));
|
||||
mManager->Register(mContent, obs); // does not addref this
|
||||
mManager->Register(mContent, obs); // does not addref this
|
||||
|
||||
mIsSeparator = aIsSeparator;
|
||||
mLabel = aLabel;
|
||||
|
||||
// set up the native menu item
|
||||
if (aIsSeparator) {
|
||||
mNativeMenuItem = [[NSMenuItem separatorItem] retain];
|
||||
}
|
||||
else {
|
||||
NSString *newCocoaLabelString = MenuHelpersX::CreateTruncatedCocoaLabel(mLabel);
|
||||
mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString action:nil keyEquivalent:@""];
|
||||
[newCocoaLabelString release];
|
||||
|
||||
[mNativeMenuItem setEnabled:(BOOL)aEnabled];
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -129,19 +128,25 @@ nsMenuItemX::GetEnabled(PRBool *aIsEnabled)
|
|||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::SetChecked(PRBool aIsEnabled)
|
||||
NS_METHOD nsMenuItemX::SetChecked(PRBool aIsChecked)
|
||||
{
|
||||
mIsChecked = aIsEnabled;
|
||||
mIsChecked = aIsChecked;
|
||||
|
||||
// update the content model. This will also handle unchecking our siblings
|
||||
// if we are a radiomenu
|
||||
mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::checked,
|
||||
mIsChecked ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"), PR_TRUE);
|
||||
|
||||
// update native menu item
|
||||
if (mIsChecked)
|
||||
[mNativeMenuItem setState:NSOnState];
|
||||
else
|
||||
[mNativeMenuItem setState:NSOffState];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::GetChecked(PRBool *aIsEnabled)
|
||||
{
|
||||
*aIsEnabled = mIsChecked;
|
||||
|
@ -149,7 +154,6 @@ NS_METHOD nsMenuItemX::GetChecked(PRBool *aIsEnabled)
|
|||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetMenuItemType(EMenuItemType *aType)
|
||||
{
|
||||
*aType = mMenuType;
|
||||
|
@ -157,28 +161,27 @@ NS_METHOD nsMenuItemX::GetMenuItemType(EMenuItemType *aType)
|
|||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetTarget(nsIWidget *& aTarget)
|
||||
{
|
||||
NS_IF_ADDREF(aTarget = mTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::GetNativeData(void *& aData)
|
||||
{
|
||||
//aData = (void *)mMenu;
|
||||
aData = mNativeMenuItem;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::AddMenuListener(nsIMenuListener * aMenuListener)
|
||||
{
|
||||
mXULCommandListener = aMenuListener; // addref
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::RemoveMenuListener(nsIMenuListener * aMenuListener)
|
||||
{
|
||||
if (mXULCommandListener.get() == aMenuListener)
|
||||
|
@ -186,7 +189,7 @@ NS_METHOD nsMenuItemX::RemoveMenuListener(nsIMenuListener * aMenuListener)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::IsSeparator(PRBool & aIsSep)
|
||||
{
|
||||
aIsSep = mIsSeparator;
|
||||
|
@ -203,12 +206,13 @@ nsEventStatus nsMenuItemX::MenuItemSelected(const nsMenuEvent & aMenuEvent)
|
|||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
nsEventStatus nsMenuItemX::MenuSelected(const nsMenuEvent & aMenuEvent)
|
||||
{
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// nsIMenuListener interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -217,7 +221,7 @@ nsEventStatus nsMenuItemX::MenuDeselected(const nsMenuEvent & aMenuEvent)
|
|||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
nsEventStatus nsMenuItemX::MenuConstruct(
|
||||
const nsMenuEvent & aMenuEvent,
|
||||
nsIWidget * aParentWindow,
|
||||
|
@ -227,27 +231,26 @@ nsEventStatus nsMenuItemX::MenuConstruct(
|
|||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
nsEventStatus nsMenuItemX::MenuDestruct(const nsMenuEvent & aMenuEvent)
|
||||
{
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
nsEventStatus nsMenuItemX::CheckRebuild(PRBool & aNeedsRebuild)
|
||||
{
|
||||
aNeedsRebuild = PR_TRUE;
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
nsEventStatus nsMenuItemX::SetRebuild(PRBool aNeedsRebuild)
|
||||
{
|
||||
//mNeedsRebuild = aNeedsRebuild;
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Executes the "cached" JavaScript Command
|
||||
* @return NS_OK if the command was executed properly, otherwise an error code
|
||||
|
@ -282,38 +285,52 @@ NS_METHOD nsMenuItemX::DoCommand()
|
|||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetModifiers(PRUint8 * aModifiers)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
*aModifiers = mModifiers;
|
||||
return res;
|
||||
*aModifiers = mModifiers;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::SetModifiers(PRUint8 aModifiers)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
|
||||
mModifiers = aModifiers;
|
||||
return res;
|
||||
{
|
||||
mModifiers = aModifiers;
|
||||
|
||||
// set up shortcut key modifiers on native menu item
|
||||
unsigned int macModifiers = 0;
|
||||
if (mModifiers & knsMenuItemShiftModifier)
|
||||
macModifiers |= NSShiftKeyMask;
|
||||
if (mModifiers & knsMenuItemAltModifier)
|
||||
macModifiers |= NSAlternateKeyMask;
|
||||
if (mModifiers & knsMenuItemControlModifier)
|
||||
macModifiers |= NSControlKeyMask;
|
||||
if (mModifiers & knsMenuItemCommandModifier)
|
||||
macModifiers |= NSCommandKeyMask;
|
||||
[mNativeMenuItem setKeyEquivalentModifierMask:macModifiers];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsMenuItemX::SetShortcutChar(const nsString &aText)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
mKeyEquivalent = aText;
|
||||
return res;
|
||||
}
|
||||
mKeyEquivalent = aText;
|
||||
|
||||
// set up shortcut key on native menu item
|
||||
NSString *keyEquivalent = [[NSString stringWithCharacters:(unichar*)mKeyEquivalent.get()
|
||||
length:mKeyEquivalent.Length()] lowercaseString];
|
||||
if (![keyEquivalent isEqualToString:@" "])
|
||||
[mNativeMenuItem setKeyEquivalent:keyEquivalent];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetShortcutChar(nsString &aText)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
aText = mKeyEquivalent;
|
||||
return res;
|
||||
}
|
||||
aText = mKeyEquivalent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// UncheckRadioSiblings
|
||||
|
@ -322,35 +339,33 @@ NS_METHOD nsMenuItemX::GetShortcutChar(nsString &aText)
|
|||
// uncheck them all.
|
||||
//
|
||||
void
|
||||
nsMenuItemX :: UncheckRadioSiblings(nsIContent* inCheckedContent)
|
||||
nsMenuItemX::UncheckRadioSiblings(nsIContent* inCheckedContent)
|
||||
{
|
||||
nsAutoString myGroupName;
|
||||
inCheckedContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::name, myGroupName);
|
||||
if ( ! myGroupName.Length() ) // no groupname, nothing to do
|
||||
if (!myGroupName.Length()) // no groupname, nothing to do
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIContent> parent = inCheckedContent->GetParent();
|
||||
if ( !parent )
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
// loop over siblings
|
||||
PRUint32 count = parent->GetChildCount();
|
||||
for ( PRUint32 i = 0; i < count; ++i ) {
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
nsIContent *sibling = parent->GetChildAt(i);
|
||||
if ( sibling ) {
|
||||
if ( sibling != inCheckedContent ) { // skip this node
|
||||
if (sibling) {
|
||||
if (sibling != inCheckedContent) { // skip this node
|
||||
// if the current sibling is in the same group, clear it
|
||||
nsAutoString currGroupName;
|
||||
sibling->GetAttr(kNameSpaceID_None, nsWidgetAtoms::name, currGroupName);
|
||||
if ( currGroupName == myGroupName )
|
||||
if (currGroupName == myGroupName)
|
||||
sibling->SetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, NS_LITERAL_STRING("false"), PR_TRUE);
|
||||
}
|
||||
}
|
||||
} // for each sibling
|
||||
|
||||
} // UncheckRadioSiblings
|
||||
|
||||
#pragma mark -
|
||||
|
||||
//
|
||||
// nsIChangeObserver
|
||||
|
@ -358,49 +373,44 @@ nsMenuItemX :: UncheckRadioSiblings(nsIContent* inCheckedContent)
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAtom *aAttribute )
|
||||
nsMenuItemX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, 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 (mMenuType == eRadio) {
|
||||
nsAutoString checked;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, checked);
|
||||
if (checked.EqualsLiteral("true") )
|
||||
if (checked.EqualsLiteral("true"))
|
||||
UncheckRadioSiblings(mContent);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
|
||||
}
|
||||
}
|
||||
else if (aAttribute == nsWidgetAtoms::disabled || aAttribute == nsWidgetAtoms::hidden ||
|
||||
aAttribute == nsWidgetAtoms::collapsed ) {
|
||||
aAttribute == nsWidgetAtoms::collapsed) {
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
} // AttributeChanged
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX :: ContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
nsMenuItemX::ContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
{
|
||||
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
return NS_OK;
|
||||
|
||||
} // ContentRemoved
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuItemX :: ContentInserted(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
{
|
||||
|
||||
nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
|
||||
listener->SetRebuild(PR_TRUE);
|
||||
return NS_OK;
|
||||
|
||||
} // ContentInserted
|
||||
|
|
|
@ -122,11 +122,6 @@ protected:
|
|||
|
||||
// fetch the content node associated with the menupopup item
|
||||
void GetMenuPopupContent(nsIContent** aResult);
|
||||
|
||||
// Insert a new item in this menu with index |inItemIndex| with the text |inItemLabel|,
|
||||
// middle-truncated to a certain pixel width with an elipsis.
|
||||
void InsertMenuItemWithTruncation(nsAutoString & inItemLabel,
|
||||
PRUint32 inItemIndex);
|
||||
|
||||
// fire handlers for oncreate/ondestroy
|
||||
PRBool OnDestroy();
|
||||
|
|
|
@ -146,7 +146,6 @@ nsMenuX::Create(nsISupports * aParent, const nsAString &aLabel, const nsAString
|
|||
NS_ASSERTION(menubar || menu, "Menu parent not a menu bar or menu!");
|
||||
|
||||
SetLabel(aLabel);
|
||||
SetAccessKey(aAccessKey);
|
||||
|
||||
nsAutoString hiddenValue, collapsedValue;
|
||||
mMenuContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::hidden, hiddenValue);
|
||||
|
@ -222,40 +221,17 @@ NS_IMETHODIMP nsMenuX::AddMenuItem(nsIMenuItem * aMenuItem)
|
|||
if (!aMenuItem)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRUint32 currItemIndex = mMenuItemsArray.Count();
|
||||
mMenuItemsArray.AppendObject(aMenuItem); // owning ref
|
||||
|
||||
nsAutoString label;
|
||||
aMenuItem->GetLabel(label);
|
||||
InsertMenuItemWithTruncation(label, currItemIndex);
|
||||
NSMenuItem *newNativeMenuItem = [mMacMenu itemAtIndex:currItemIndex];
|
||||
|
||||
// add the menu item to this menu
|
||||
NSMenuItem* newNativeMenuItem;
|
||||
aMenuItem->GetNativeData((void*&)newNativeMenuItem);
|
||||
[mMacMenu addItem:newNativeMenuItem];
|
||||
|
||||
// set up target/action
|
||||
[newNativeMenuItem setTarget:mMenuDelegate];
|
||||
[newNativeMenuItem setAction:@selector(menuItemHit:)];
|
||||
|
||||
// set up shortcut keys
|
||||
nsAutoString geckoKeyEquivalent(NS_LITERAL_STRING(" "));
|
||||
aMenuItem->GetShortcutChar(geckoKeyEquivalent);
|
||||
NSString *keyEquivalent = [[NSString stringWithCharacters:(unichar*)geckoKeyEquivalent.get()
|
||||
length:geckoKeyEquivalent.Length()] lowercaseString];
|
||||
if (![keyEquivalent isEqualToString:@" "])
|
||||
[newNativeMenuItem setKeyEquivalent:keyEquivalent];
|
||||
|
||||
// set up shortcut key modifiers
|
||||
PRUint8 modifiers;
|
||||
aMenuItem->GetModifiers(&modifiers);
|
||||
unsigned int macModifiers = 0;
|
||||
if (knsMenuItemShiftModifier & modifiers)
|
||||
macModifiers |= NSShiftKeyMask;
|
||||
if (knsMenuItemAltModifier & modifiers)
|
||||
macModifiers |= NSAlternateKeyMask;
|
||||
if (knsMenuItemControlModifier & modifiers)
|
||||
macModifiers |= NSControlKeyMask;
|
||||
if (knsMenuItemCommandModifier & modifiers)
|
||||
macModifiers |= NSCommandKeyMask;
|
||||
[newNativeMenuItem setKeyEquivalentModifierMask:macModifiers];
|
||||
|
||||
// set its command. we get the unique command id from the menubar
|
||||
nsCOMPtr<nsIMenuCommandDispatcher> dispatcher(do_QueryInterface(mManager));
|
||||
if (dispatcher) {
|
||||
|
@ -265,20 +241,6 @@ NS_IMETHODIMP nsMenuX::AddMenuItem(nsIMenuItem * aMenuItem)
|
|||
[newNativeMenuItem setTag:commandID];
|
||||
}
|
||||
|
||||
PRBool isEnabled;
|
||||
aMenuItem->GetEnabled(&isEnabled);
|
||||
if (isEnabled)
|
||||
[newNativeMenuItem setEnabled:YES];
|
||||
else
|
||||
[newNativeMenuItem setEnabled:NO];
|
||||
|
||||
PRBool isChecked;
|
||||
aMenuItem->GetChecked(&isChecked);
|
||||
if (isChecked)
|
||||
[newNativeMenuItem setState:NSOnState];
|
||||
else
|
||||
[newNativeMenuItem setState:NSOffState];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -296,19 +258,14 @@ NS_IMETHODIMP nsMenuX::AddMenu(nsIMenu * aMenu)
|
|||
PRUint32 currItemIndex = mMenuItemsArray.Count();
|
||||
mMenuItemsArray.AppendObject(supports); // owning ref
|
||||
|
||||
// We have to add it as a menu item and then associate it with the item
|
||||
// We have to add a menu item and then associate the menu with it
|
||||
nsAutoString label;
|
||||
aMenu->GetLabel(label);
|
||||
InsertMenuItemWithTruncation(label, currItemIndex);
|
||||
|
||||
PRBool isEnabled;
|
||||
aMenu->GetEnabled(&isEnabled);
|
||||
if (isEnabled) {
|
||||
[[mMacMenu itemAtIndex:currItemIndex] setEnabled:YES];
|
||||
}
|
||||
else {
|
||||
[[mMacMenu itemAtIndex:currItemIndex] setEnabled:NO];
|
||||
}
|
||||
NSString *newCocoaLabelString = MenuHelpersX::CreateTruncatedCocoaLabel(mLabel);
|
||||
NSMenuItem* newNativeMenuItem= [[NSMenuItem alloc] initWithTitle:newCocoaLabelString action:NULL keyEquivalent:@""];
|
||||
[newCocoaLabelString release];
|
||||
[mMacMenu addItem:newNativeMenuItem];
|
||||
|
||||
NSMenu* childMenu;
|
||||
if (aMenu->GetNativeData((void**)&childMenu) == NS_OK) {
|
||||
[[mMacMenu itemAtIndex:currItemIndex] setSubmenu:childMenu];
|
||||
|
@ -317,29 +274,6 @@ NS_IMETHODIMP nsMenuX::AddMenu(nsIMenu * aMenu)
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// InsertMenuItemWithTruncation
|
||||
//
|
||||
// Insert a new item in this menu with index |inItemIndex| with the text |inItemLabel|,
|
||||
// middle-truncated to a certain pixel width with an elipsis.
|
||||
//
|
||||
void
|
||||
nsMenuX::InsertMenuItemWithTruncation(nsAutoString & inItemLabel, PRUint32 inItemIndex)
|
||||
{
|
||||
// ::TruncateThemeText() doesn't take the number of characters to truncate to, it takes a pixel with
|
||||
// to fit the string in. Ugh. I talked it over with sfraser and we couldn't come up with an
|
||||
// easy way to compute what this should be given the system font, etc, so we're just going
|
||||
// to hard code it to something reasonable and bigger fonts will just have to deal.
|
||||
const short kMaxItemPixelWidth = 300;
|
||||
|
||||
CFMutableStringRef labelRef = ::CFStringCreateMutable(kCFAllocatorDefault, inItemLabel.Length());
|
||||
::CFStringAppendCharacters(labelRef, (UniChar*)inItemLabel.get(), inItemLabel.Length());
|
||||
::TruncateThemeText(labelRef, kThemeMenuItemFont, kThemeStateActive, kMaxItemPixelWidth, truncMiddle, NULL);
|
||||
[mMacMenu insertItem:[[[NSMenuItem alloc] initWithTitle:(NSString*)labelRef action:NULL keyEquivalent:@""] autorelease] atIndex:(inItemIndex)];
|
||||
::CFRelease(labelRef);
|
||||
} // InsertMenuItemWithTruncation
|
||||
|
||||
|
||||
NS_IMETHODIMP nsMenuX::AddSeparator()
|
||||
{
|
||||
// We're not really appending an nsMenuItem but it needs to be here to make
|
||||
|
@ -682,6 +616,10 @@ NSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& menuTitle)
|
|||
NSMenu* myMenu = [[NSMenu alloc] initWithTitle:title];
|
||||
[myMenu setDelegate:mMenuDelegate];
|
||||
|
||||
// We don't want this menu to auto-enable menu items because then Cocoa
|
||||
// overrides our decisions and things get incorrectly enabled/disabled.
|
||||
[myMenu setAutoenablesItems:NO];
|
||||
|
||||
// we used to install Carbon event handlers here, but since NSMenu* doesn't
|
||||
// create its underlying MenuRef until just before display, we delay until
|
||||
// that happens. Now we install the event handlers when Cocoa notifies
|
||||
|
@ -819,9 +757,9 @@ nsMenuX::LoadSubMenu(nsIMenu * pParentMenu, nsIContent* inMenuItemContent)
|
|||
nsAutoString disabled;
|
||||
inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, disabled);
|
||||
if (disabled.EqualsLiteral("true"))
|
||||
pnsMenu->SetEnabled (PR_FALSE);
|
||||
pnsMenu->SetEnabled(PR_FALSE);
|
||||
else
|
||||
pnsMenu->SetEnabled (PR_TRUE);
|
||||
pnsMenu->SetEnabled(PR_TRUE);
|
||||
|
||||
// Make nsMenu a child of parent nsMenu. The parent takes ownership
|
||||
nsCOMPtr<nsISupports> supports2(do_QueryInterface(pnsMenu));
|
||||
|
@ -873,7 +811,7 @@ nsMenuX::OnCreate()
|
|||
rv = dispatchTo->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
||||
if (NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault)
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// the menu is going to show and the oncreate handler has executed. We
|
||||
// now need to walk our menu items, checking to see if any of them have
|
||||
|
@ -1161,10 +1099,9 @@ nsMenuX::AttributeChanged(nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAtom
|
|||
// reuse the existing menu, to avoid rebuilding the root menu bar.
|
||||
NS_ASSERTION(mMacMenu != NULL, "nsMenuX::AttributeChanged: invalid menu handle.");
|
||||
RemoveAll();
|
||||
CFStringRef titleRef = ::CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)mLabel.get(), mLabel.Length());
|
||||
NS_ASSERTION(titleRef, "nsMenuX::AttributeChanged: CFStringCreateWithCharacters failed.");
|
||||
[mMacMenu setTitle:(NSString*)titleRef];
|
||||
::CFRelease(titleRef);
|
||||
NSString *newCocoaLabelString = MenuHelpersX::CreateTruncatedCocoaLabel(mLabel);
|
||||
[mMacMenu setTitle:newCocoaLabelString];
|
||||
[newCocoaLabelString release];
|
||||
}
|
||||
}
|
||||
else if (aAttribute == nsWidgetAtoms::hidden || aAttribute == nsWidgetAtoms::collapsed) {
|
||||
|
|
|
@ -276,34 +276,29 @@ NS_METHOD nsMenuItemX::DoCommand()
|
|||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetModifiers(PRUint8 * aModifiers)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
*aModifiers = mModifiers;
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::SetModifiers(PRUint8 aModifiers)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
|
||||
mModifiers = aModifiers;
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::SetShortcutChar(const nsString &aText)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
mKeyEquivalent = aText;
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsMenuItemX::GetShortcutChar(nsString &aText)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
aText = mKeyEquivalent;
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Загрузка…
Ссылка в новой задаче