Back to index

lightning-sunbird  0.9+nobinonly
nsListBoxObject.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 Communicator client 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  *   David W. Hyatt (hyatt@netscape.com) (Original Author)
00024  *   Joe Hewitt (hewitt@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsPIListBoxObject.h"
00042 #include "nsBoxObject.h"
00043 #include "nsIFrame.h"
00044 #include "nsIDocument.h"
00045 #include "nsIBindingManager.h"
00046 #include "nsIDOMElement.h"
00047 #include "nsIDOMNodeList.h"
00048 #include "nsXULAtoms.h"
00049 #include "nsIScrollableFrame.h"
00050 
00051 class nsListBoxObject : public nsPIListBoxObject_MOZILLA_1_8_BRANCH,
00052                         public nsBoxObject
00053 {
00054 public:
00055   NS_DECL_ISUPPORTS_INHERITED
00056   NS_DECL_NSILISTBOXOBJECT
00057 
00058   // nsPIListBoxObject
00059   virtual void ClearCachedListBoxBody();
00060   virtual nsIListBoxObject* GetListBoxBody()
00061   {
00062     return GetListBoxBodyImpl(PR_TRUE);
00063   }
00064 
00065   // nsPIListBoxObject_MOZILLA_1_8_BRANCH
00066   virtual nsIListBoxObject* GetListBoxBody(PRBool aFlush)
00067   {
00068     return GetListBoxBodyImpl(aFlush);
00069   }
00070 
00071   nsIListBoxObject* GetListBoxBodyImpl(PRBool aFlush);
00072 
00073   nsListBoxObject();
00074   virtual ~nsListBoxObject();
00075 
00076   NS_IMETHOD InvalidatePresentationStuff();
00077   
00078 protected:
00079   nsIListBoxObject* mListBoxBody;
00080 };
00081 
00082 NS_IMPL_ISUPPORTS_INHERITED3(nsListBoxObject, nsBoxObject, nsIListBoxObject,
00083                              nsPIListBoxObject, nsPIListBoxObject_MOZILLA_1_8_BRANCH)
00084 
00085 nsListBoxObject::nsListBoxObject()
00086   : mListBoxBody(nsnull)
00087 {
00088 }
00089 
00090 nsListBoxObject::~nsListBoxObject()
00091 {
00092 }
00093 
00094 
00097 
00098 NS_IMETHODIMP
00099 nsListBoxObject::GetListboxBody(nsIListBoxObject * *aListboxBody)
00100 {
00101   *aListboxBody = nsnull;
00102   return NS_OK;
00103 }
00104 
00105 NS_IMETHODIMP
00106 nsListBoxObject::GetRowCount(PRInt32 *aResult)
00107 {
00108   nsIListBoxObject* body = GetListBoxBody();
00109   if (body)
00110     return body->GetRowCount(aResult);
00111   return NS_OK;
00112 }
00113 
00114 NS_IMETHODIMP
00115 nsListBoxObject::GetNumberOfVisibleRows(PRInt32 *aResult)
00116 {
00117   nsIListBoxObject* body = GetListBoxBody();
00118   if (body)
00119     return body->GetNumberOfVisibleRows(aResult);
00120   return NS_OK;
00121 }
00122 
00123 NS_IMETHODIMP
00124 nsListBoxObject::GetIndexOfFirstVisibleRow(PRInt32 *aResult)
00125 {
00126   nsIListBoxObject* body = GetListBoxBody();
00127   if (body)
00128     return body->GetIndexOfFirstVisibleRow(aResult);
00129   return NS_OK;
00130 }
00131 
00132 NS_IMETHODIMP nsListBoxObject::EnsureIndexIsVisible(PRInt32 aRowIndex)
00133 {
00134   nsIListBoxObject* body = GetListBoxBody();
00135   if (body)
00136     return body->EnsureIndexIsVisible(aRowIndex);
00137   return NS_OK;
00138 }
00139 
00140 NS_IMETHODIMP
00141 nsListBoxObject::ScrollToIndex(PRInt32 aRowIndex)
00142 {
00143   nsIListBoxObject* body = GetListBoxBody();
00144   if (body)
00145     return body->ScrollToIndex(aRowIndex);
00146   return NS_OK;
00147 }
00148 
00149 NS_IMETHODIMP
00150 nsListBoxObject::ScrollByLines(PRInt32 aNumLines)
00151 {
00152   nsIListBoxObject* body = GetListBoxBody();
00153   if (body)
00154     return body->ScrollByLines(aNumLines);
00155   return NS_OK;
00156 }
00157 
00158 NS_IMETHODIMP
00159 nsListBoxObject::GetItemAtIndex(PRInt32 index, nsIDOMElement **_retval)
00160 {
00161   nsIListBoxObject* body = GetListBoxBody();
00162   if (body)
00163     return body->GetItemAtIndex(index, _retval);
00164   return NS_OK;
00165 }
00166 
00167 NS_IMETHODIMP
00168 nsListBoxObject::GetIndexOfItem(nsIDOMElement* aElement, PRInt32 *aResult)
00169 {
00170   *aResult = 0;
00171 
00172   nsIListBoxObject* body = GetListBoxBody();
00173   if (body)
00174     return body->GetIndexOfItem(aElement, aResult);
00175   return NS_OK;
00176 }
00177 
00178 void
00179 nsListBoxObject::ClearCachedListBoxBody()
00180 {
00181   mListBoxBody = nsnull;
00182 }
00183 
00185 
00186 static void
00187 FindBodyContent(nsIContent* aParent, nsIContent** aResult)
00188 {
00189   if (aParent->Tag() == nsXULAtoms::listboxbody) {
00190     *aResult = aParent;
00191     NS_IF_ADDREF(*aResult);
00192   }
00193   else {
00194     nsCOMPtr<nsIDOMNodeList> kids;
00195     aParent->GetDocument()->BindingManager()->GetXBLChildNodesFor(aParent, getter_AddRefs(kids));
00196     if (!kids) return;
00197 
00198     PRUint32 i;
00199     kids->GetLength(&i);
00200     // start from the end, cuz we're smart and we know the listboxbody is probably at the end
00201     while (i > 0) {
00202       nsCOMPtr<nsIDOMNode> childNode;
00203       kids->Item(--i, getter_AddRefs(childNode));
00204       nsCOMPtr<nsIContent> childContent(do_QueryInterface(childNode));
00205       FindBodyContent(childContent, aResult);
00206       if (*aResult)
00207         break;
00208     }
00209   }
00210 }
00211 
00212 nsIListBoxObject*
00213 nsListBoxObject::GetListBoxBodyImpl(PRBool aFlush)
00214 {
00215   if (mListBoxBody) {
00216     return mListBoxBody;
00217   }
00218 
00219   nsIFrame* frame;
00220   if (aFlush) {
00221     frame = GetFrame(); // does Flush_Frames
00222   }
00223   else {
00224     frame = nsnull;
00225     nsCOMPtr<nsIPresShell> shell = GetPresShell();
00226     if (shell) {
00227       shell->GetPrimaryFrameFor(mContent, &frame);
00228     }
00229   }
00230   if (!frame)
00231     return nsnull;
00232 
00233   nsCOMPtr<nsIPresShell> shell = GetPresShell();
00234   if (!shell) {
00235     return nsnull;
00236   }
00237 
00238   // Iterate over our content model children looking for the body.
00239   nsCOMPtr<nsIContent> content;
00240   FindBodyContent(frame->GetContent(), getter_AddRefs(content));
00241 
00242   // this frame will be a nsGFXScrollFrame
00243   shell->GetPrimaryFrameFor(content, &frame);
00244   if (!frame)
00245      return nsnull;
00246   nsIScrollableFrame* scrollFrame;
00247   CallQueryInterface(frame, &scrollFrame);
00248   if (!scrollFrame)
00249     return nsnull;
00250 
00251   // this frame will be the one we want
00252   nsIFrame* yeahBaby = scrollFrame->GetScrolledFrame();
00253   if (!yeahBaby)
00254      return nsnull;
00255 
00256   // It's a frame. Refcounts are irrelevant.
00257   CallQueryInterface(yeahBaby, &mListBoxBody);
00258   return mListBoxBody;
00259 }
00260 
00261 NS_IMETHODIMP
00262 nsListBoxObject::InvalidatePresentationStuff()
00263 {
00264   ClearCachedListBoxBody();
00265 
00266   return nsBoxObject::InvalidatePresentationStuff();
00267 }
00268 
00269 // Creation Routine ///////////////////////////////////////////////////////////////////////
00270 
00271 nsresult
00272 NS_NewListBoxObject(nsIBoxObject** aResult)
00273 {
00274   *aResult = new nsListBoxObject;
00275   if (!*aResult)
00276     return NS_ERROR_OUT_OF_MEMORY;
00277   NS_ADDREF(*aResult);
00278   return NS_OK;
00279 }