Back to index

lightning-sunbird  0.9+nobinonly
nsMenuItemX.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsCOMPtr.h"
00039 #include "nsIDocumentViewer.h"
00040 #include "nsIContent.h"
00041 #include "nsPresContext.h"
00042 
00043 #include "nsMenuBarX.h"         // for MenuHelpers namespace
00044 #include "nsMenuItemX.h"
00045 #include "nsIMenu.h"
00046 #include "nsIMenuBar.h"
00047 #include "nsIWidget.h"
00048 #include "nsIMenuListener.h"
00049 #include "nsINameSpaceManager.h"
00050 #include "nsWidgetAtoms.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsIDocument.h"
00053 #include "nsIDOMDocument.h"
00054 
00055 #include "nsGUIEvent.h"
00056 
00057 
00058 #if 0
00059 nsInstanceCounter   gMenuItemCounterX("nsMenuItemX");
00060 #endif
00061 
00062 
00063 NS_IMPL_ISUPPORTS4(nsMenuItemX, nsIMenuItem, nsIMenuListener, nsIChangeObserver, nsISupportsWeakReference)
00064 
00065 //
00066 // nsMenuItemX constructor
00067 //
00068 nsMenuItemX::nsMenuItemX()
00069 {
00070   mMenuParent         = nsnull;
00071   mIsSeparator        = PR_FALSE;
00072   mKeyEquivalent.AssignLiteral(" ");
00073   mEnabled            = PR_TRUE;
00074   mIsChecked          = PR_FALSE;
00075   mMenuType           = eRegular;
00076 
00077 #if 0
00078   ++gMenuItemCounterX;
00079 #endif 
00080 }
00081 
00082 //
00083 // nsMenuItemX destructor
00084 //
00085 nsMenuItemX::~nsMenuItemX()
00086 {
00087   mManager->Unregister(mContent);
00088 
00089 #if 0
00090   --gMenuItemCounterX;
00091 #endif 
00092 }
00093 
00094 
00095 NS_METHOD nsMenuItemX::Create ( nsIMenu* aParent, const nsString & aLabel, PRBool aIsSeparator,
00096                                 EMenuItemType aItemType, PRBool aEnabled, 
00097                                 nsIChangeManager* aManager, nsIDocShell* aShell, nsIContent* aNode )
00098 {
00099   mContent = aNode;         // addref
00100   mMenuParent = aParent;    // weak
00101   mDocShellWeakRef = do_GetWeakReference(aShell);
00102   
00103   mEnabled = aEnabled;
00104   mMenuType = aItemType;
00105   
00106   // register for AttributeChanged messages
00107   mManager = aManager;
00108   nsCOMPtr<nsIChangeObserver> obs = do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this));
00109   mManager->Register(mContent, obs);   // does not addref this
00110   
00111   mIsSeparator = aIsSeparator;
00112   mLabel = aLabel;
00113   return NS_OK;
00114 }
00115 
00116 NS_METHOD
00117 nsMenuItemX::GetLabel(nsString &aText)
00118 {
00119   aText = mLabel;
00120   return NS_OK;
00121 }
00122 
00123 
00124 NS_METHOD 
00125 nsMenuItemX::GetEnabled(PRBool *aIsEnabled)
00126 {
00127   *aIsEnabled = mEnabled;
00128   return NS_OK;
00129 }
00130 
00131 
00132 NS_METHOD nsMenuItemX::SetChecked(PRBool aIsEnabled)
00133 {
00134   mIsChecked = aIsEnabled;
00135   
00136   // update the content model. This will also handle unchecking our siblings
00137   // if we are a radiomenu
00138   mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, 
00139                     mIsChecked ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"), PR_TRUE);
00140 
00141   return NS_OK;
00142 }
00143 
00144 //-------------------------------------------------------------------------
00145 NS_METHOD nsMenuItemX::GetChecked(PRBool *aIsEnabled)
00146 {
00147   *aIsEnabled = mIsChecked;
00148   return NS_OK;
00149 }
00150 
00151 
00152 //-------------------------------------------------------------------------
00153 NS_METHOD nsMenuItemX::GetMenuItemType(EMenuItemType *aType)
00154 {
00155   *aType = mMenuType;
00156   return NS_OK;
00157 }
00158 
00159 
00160 //-------------------------------------------------------------------------
00161 NS_METHOD nsMenuItemX::GetTarget(nsIWidget *& aTarget)
00162 {
00163   NS_IF_ADDREF(aTarget = mTarget);
00164   return NS_OK;
00165 }
00166 
00167 //-------------------------------------------------------------------------
00168 NS_METHOD nsMenuItemX::GetNativeData(void *& aData)
00169 {
00170   //aData = (void *)mMenu;
00171   return NS_OK;
00172 }
00173 
00174 //-------------------------------------------------------------------------
00175 NS_METHOD nsMenuItemX::AddMenuListener(nsIMenuListener * aMenuListener)
00176 {
00177   mXULCommandListener = aMenuListener;    // addref
00178   return NS_OK;
00179 }
00180 
00181 //-------------------------------------------------------------------------
00182 NS_METHOD nsMenuItemX::RemoveMenuListener(nsIMenuListener * aMenuListener)
00183 {
00184   if (mXULCommandListener.get() == aMenuListener)
00185     mXULCommandListener = nsnull;
00186   return NS_OK;
00187 }
00188 
00189 //-------------------------------------------------------------------------
00190 NS_METHOD nsMenuItemX::IsSeparator(PRBool & aIsSep)
00191 {
00192   aIsSep = mIsSeparator;
00193   return NS_OK;
00194 }
00195 
00196 
00197 //-------------------------------------------------------------------------
00198 // nsIMenuListener interface
00199 //-------------------------------------------------------------------------
00200 nsEventStatus nsMenuItemX::MenuItemSelected(const nsMenuEvent & aMenuEvent)
00201 {
00202   // this is all handled by Carbon Events
00203   return nsEventStatus_eConsumeNoDefault;
00204 }
00205 
00206 //-------------------------------------------------------------------------
00207 nsEventStatus nsMenuItemX::MenuSelected(const nsMenuEvent & aMenuEvent)
00208 {
00209   return nsEventStatus_eIgnore;
00210 }
00211 
00212 //-------------------------------------------------------------------------
00213 // nsIMenuListener interface
00214 //-------------------------------------------------------------------------
00215 nsEventStatus nsMenuItemX::MenuDeselected(const nsMenuEvent & aMenuEvent)
00216 {
00217     return nsEventStatus_eIgnore;
00218 }
00219 
00220 //-------------------------------------------------------------------------
00221 nsEventStatus nsMenuItemX::MenuConstruct(
00222     const nsMenuEvent & aMenuEvent,
00223     nsIWidget         * aParentWindow, 
00224     void              * menuNode,
00225     void              * aDocShell)
00226 {
00227     return nsEventStatus_eIgnore;
00228 }
00229 
00230 //-------------------------------------------------------------------------
00231 nsEventStatus nsMenuItemX::MenuDestruct(const nsMenuEvent & aMenuEvent)
00232 {
00233     return nsEventStatus_eIgnore;
00234 }
00235 
00236 //-------------------------------------------------------------------------
00237 nsEventStatus nsMenuItemX::CheckRebuild(PRBool & aNeedsRebuild)
00238 {
00239   aNeedsRebuild = PR_TRUE; 
00240   return nsEventStatus_eIgnore;
00241 }
00242 
00243 //-------------------------------------------------------------------------
00244 nsEventStatus nsMenuItemX::SetRebuild(PRBool aNeedsRebuild)
00245 {
00246   //mNeedsRebuild = aNeedsRebuild; 
00247   return nsEventStatus_eIgnore;
00248 }
00249 
00250 //-------------------------------------------------------------------------
00255 NS_METHOD nsMenuItemX::DoCommand()
00256 {
00257   nsCOMPtr<nsPresContext> presContext;
00258   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShellWeakRef);
00259   if (!docShell)
00260     return nsEventStatus_eConsumeNoDefault;
00261   MenuHelpersX::DocShellToPresContext(docShell, getter_AddRefs(presContext));
00262 
00263   nsEventStatus status = nsEventStatus_eIgnore;
00264   nsXULCommandEvent event(PR_TRUE, NS_XUL_COMMAND, nsnull);
00265 
00266   mContent->HandleDOMEvent(presContext, &event, nsnull,
00267                            NS_EVENT_FLAG_INIT, &status);
00268   return nsEventStatus_eConsumeNoDefault;
00269 }
00270     
00271    
00272    //-------------------------------------------------------------------------
00273 NS_METHOD nsMenuItemX::GetModifiers(PRUint8 * aModifiers) 
00274 {
00275     nsresult res = NS_OK;
00276     *aModifiers = mModifiers; 
00277     return res; 
00278 }
00279 
00280 //-------------------------------------------------------------------------
00281 NS_METHOD nsMenuItemX::SetModifiers(PRUint8 aModifiers)
00282 {
00283     nsresult res = NS_OK;
00284     
00285     mModifiers = aModifiers;
00286     return res;
00287 }
00288  
00289 //-------------------------------------------------------------------------
00290 NS_METHOD nsMenuItemX::SetShortcutChar(const nsString &aText)
00291 {
00292     nsresult res = NS_OK;
00293     mKeyEquivalent = aText;
00294     return res;
00295 } 
00296 
00297 //-------------------------------------------------------------------------
00298 NS_METHOD nsMenuItemX::GetShortcutChar(nsString &aText)
00299 {
00300     nsresult res = NS_OK;
00301     aText = mKeyEquivalent;
00302     return res;
00303 } 
00304 
00305 //
00306 // UncheckRadioSiblings
00307 //
00308 // walk the sibling list looking for nodes with the same name and
00309 // uncheck them all.
00310 //
00311 void
00312 nsMenuItemX :: UncheckRadioSiblings(nsIContent* inCheckedContent)
00313 {
00314   nsAutoString myGroupName;
00315   inCheckedContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::name, myGroupName);
00316   if ( ! myGroupName.Length() )        // no groupname, nothing to do
00317     return;
00318   
00319   nsCOMPtr<nsIContent> parent = inCheckedContent->GetParent();
00320   if ( !parent )
00321     return;
00322 
00323   // loop over siblings
00324   PRUint32 count = parent->GetChildCount();
00325   for ( PRUint32 i = 0; i < count; ++i ) {
00326     nsIContent *sibling = parent->GetChildAt(i);
00327     if ( sibling ) {      
00328       if ( sibling != inCheckedContent ) {                    // skip this node
00329         // if the current sibling is in the same group, clear it
00330         nsAutoString currGroupName;
00331         sibling->GetAttr(kNameSpaceID_None, nsWidgetAtoms::name, currGroupName);
00332         if ( currGroupName == myGroupName )
00333           sibling->SetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, NS_LITERAL_STRING("false"), PR_TRUE);
00334       }
00335     }    
00336   } // for each sibling
00337 
00338 } // UncheckRadioSiblings
00339 
00340 #pragma mark -
00341 
00342 //
00343 // nsIChangeObserver
00344 //
00345 
00346 
00347 NS_IMETHODIMP
00348 nsMenuItemX :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAtom *aAttribute )
00349 {
00350   if (aAttribute == nsWidgetAtoms::checked) {
00351     // if we're a radio menu, uncheck our sibling radio items. No need to
00352     // do any of this if we're just a normal check menu.
00353     if ( mMenuType == eRadio ) {
00354       nsAutoString checked;
00355       mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, checked);
00356       if (checked.EqualsLiteral("true") ) 
00357         UncheckRadioSiblings(mContent);
00358     }
00359     
00360     nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
00361     listener->SetRebuild(PR_TRUE);
00362     
00363   } 
00364   else if (aAttribute == nsWidgetAtoms::disabled || aAttribute == nsWidgetAtoms::hidden ||
00365              aAttribute == nsWidgetAtoms::collapsed )  {
00366     nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
00367     listener->SetRebuild(PR_TRUE);
00368   }
00369   
00370   return NS_OK;
00371 
00372 } // AttributeChanged
00373 
00374 
00375 NS_IMETHODIMP
00376 nsMenuItemX :: ContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
00377 {
00378   
00379   nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
00380   listener->SetRebuild(PR_TRUE);
00381   return NS_OK;
00382   
00383 } // ContentRemoved
00384 
00385 NS_IMETHODIMP
00386 nsMenuItemX :: ContentInserted(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
00387 {
00388   
00389   nsCOMPtr<nsIMenuListener> listener = do_QueryInterface(mMenuParent);
00390   listener->SetRebuild(PR_TRUE);
00391   return NS_OK;
00392   
00393 } // ContentInserted