Back to index

lightning-sunbird  0.9+nobinonly
nsTreeBodyFrame.h
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  *   Dave Hyatt <hyatt@mozilla.org> (Original Author)
00024  *   Dean Tessman <dean_tessman@hotmail.com>
00025  *   Brian Ryner <bryner@brianryner.com>
00026  *   Jan Varga <varga@ku.sk>
00027  *   Mark Banner <mark@standard8.demon.co.uk>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include "nsLeafBoxFrame.h"
00044 #include "nsPITreeBoxObject.h"
00045 #include "nsITreeView.h"
00046 #include "nsICSSPseudoComparator.h"
00047 #include "nsIScrollbarMediator.h"
00048 #include "nsIDragSession.h"
00049 #include "nsITimer.h"
00050 #include "nsIReflowCallback.h"
00051 #include "nsILookAndFeel.h"
00052 #include "nsValueArray.h"
00053 #include "nsTreeStyleCache.h"
00054 #include "nsTreeColumns.h"
00055 #include "nsTreeImageListener.h"
00056 #include "nsAutoPtr.h"
00057 #include "nsDataHashtable.h"
00058 #include "imgIRequest.h"
00059 #include "imgIDecoderObserver.h"
00060 
00061 class nsTreeBodyFrame;
00062 class nsTreeReflowCallback : public nsIReflowCallback
00063 {
00064 public:
00065   nsTreeReflowCallback(nsTreeBodyFrame* aFrame) : mFrame(aFrame) {}
00066   NS_DECL_ISUPPORTS
00067   NS_IMETHOD ReflowFinished(nsIPresShell* aShell, PRBool* aFlushFlag);
00068   nsTreeBodyFrame* mFrame;
00069 };
00070 
00071 // An entry in the tree's image cache
00072 struct nsTreeImageCacheEntry
00073 {
00074   nsTreeImageCacheEntry() {}
00075   nsTreeImageCacheEntry(imgIRequest *aRequest, imgIDecoderObserver *aListener)
00076     : request(aRequest), listener(aListener) {}
00077 
00078   nsCOMPtr<imgIRequest> request;
00079   nsCOMPtr<imgIDecoderObserver> listener;
00080 };
00081 
00082 // The actual frame that paints the cells and rows.
00083 class nsTreeBodyFrame : public nsLeafBoxFrame,
00084                         public nsITreeBoxObject,
00085                         public nsICSSPseudoComparator,
00086                         public nsIScrollbarMediator
00087 {
00088 public:
00089   nsTreeBodyFrame(nsIPresShell* aPresShell);
00090   virtual ~nsTreeBodyFrame();
00091 
00092   NS_DECL_ISUPPORTS
00093   NS_DECL_NSITREEBOXOBJECT
00094 
00095   // nsIBox
00096   NS_IMETHOD GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);
00097   NS_IMETHOD SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
00098                        PRBool aRemoveOverflowArea = PR_FALSE);
00099 
00100   nsresult ReflowFinished(nsIPresShell* aPresShell, PRBool* aFlushFlag);
00101 
00102   // nsICSSPseudoComparator
00103   NS_IMETHOD PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBool* aResult);
00104 
00105   // nsIScrollbarMediator
00106   NS_IMETHOD PositionChanged(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32& aNewIndex);
00107   NS_IMETHOD ScrollbarButtonPressed(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32 aNewIndex);
00108   NS_IMETHOD VisibilityChanged(nsISupports* aScrollbar, PRBool aVisible) { Invalidate(); return NS_OK; };
00109 
00110   // Overridden from nsIFrame to cache our pres context.
00111   NS_IMETHOD Init(nsPresContext* aPresContext, nsIContent* aContent,
00112                   nsIFrame* aParent, nsStyleContext* aContext, nsIFrame* aPrevInFlow);
00113   NS_IMETHOD Destroy(nsPresContext* aPresContext);
00114   NS_IMETHOD GetCursor(const nsPoint& aPoint,
00115                        nsIFrame::Cursor& aCursor);
00116 
00117   NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
00118                          nsGUIEvent* aEvent,
00119                          nsEventStatus* aEventStatus);
00120 
00121   // Painting methods.
00122   // Paint is the generic nsIFrame paint method.  We override this method
00123   // to paint our contents (our rows and cells).
00124   NS_IMETHOD Paint(nsPresContext*      aPresContext,
00125                    nsIRenderingContext& aRenderingContext,
00126                    const nsRect&        aDirtyRect,
00127                    nsFramePaintLayer    aWhichLayer,
00128                    PRUint32             aFlags = 0);
00129 
00130   // This method paints a specific column background of the tree.
00131   void PaintColumn(nsTreeColumn*        aColumn,
00132                    const nsRect&        aColumnRect,
00133                    nsPresContext*      aPresContext,
00134                    nsIRenderingContext& aRenderingContext,
00135                    const nsRect&        aDirtyRect);
00136 
00137   // This method paints a single row in the tree.
00138   void PaintRow(PRInt32              aRowIndex,
00139                 const nsRect&        aRowRect,
00140                 nsPresContext*      aPresContext,
00141                 nsIRenderingContext& aRenderingContext,
00142                 const nsRect&        aDirtyRect);
00143 
00144   // This method paints a single separator in the tree.
00145   void PaintSeparator(PRInt32              aRowIndex,
00146                       const nsRect&        aSeparatorRect,
00147                       nsPresContext*      aPresContext,
00148                       nsIRenderingContext& aRenderingContext,
00149                       const nsRect&        aDirtyRect);
00150 
00151   // This method paints a specific cell in a given row of the tree.
00152   void PaintCell(PRInt32              aRowIndex, 
00153                  nsTreeColumn*        aColumn,
00154                  const nsRect&        aCellRect,
00155                  nsPresContext*      aPresContext,
00156                  nsIRenderingContext& aRenderingContext,
00157                  const nsRect&        aDirtyRect,
00158                  nscoord&             aCurrX);
00159 
00160   // This method paints the twisty inside a cell in the primary column of an tree.
00161   void PaintTwisty(PRInt32              aRowIndex,
00162                    nsTreeColumn*        aColumn,
00163                    const nsRect&        aTwistyRect,
00164                    nsPresContext*      aPresContext,
00165                    nsIRenderingContext& aRenderingContext,
00166                    const nsRect&        aDirtyRect,
00167                    nscoord&             aRemainingWidth,
00168                    nscoord&             aCurrX);
00169 
00170   // This method paints the image inside the cell of an tree.
00171   void PaintImage(PRInt32              aRowIndex,
00172                   nsTreeColumn*        aColumn,
00173                   const nsRect&        aImageRect,
00174                   nsPresContext*      aPresContext,
00175                   nsIRenderingContext& aRenderingContext,
00176                   const nsRect&        aDirtyRect,
00177                   nscoord&             aRemainingWidth,
00178                   nscoord&             aCurrX);
00179 
00180   // This method paints the text string inside a particular cell of the tree.
00181   void PaintText(PRInt32              aRowIndex, 
00182                  nsTreeColumn*        aColumn,
00183                  const nsRect&        aTextRect,
00184                  nsPresContext*      aPresContext,
00185                  nsIRenderingContext& aRenderingContext,
00186                  const nsRect&        aDirtyRect,
00187                  nscoord&             aCurrX);
00188 
00189   // This method paints the checkbox inside a particular cell of the tree.
00190   void PaintCheckbox(PRInt32              aRowIndex, 
00191                      nsTreeColumn*        aColumn,
00192                      const nsRect&        aCheckboxRect,
00193                      nsPresContext*      aPresContext,
00194                      nsIRenderingContext& aRenderingContext,
00195                      const nsRect&        aDirtyRect);
00196 
00197   // This method paints the progress meter inside a particular cell of the tree.
00198   void PaintProgressMeter(PRInt32              aRowIndex, 
00199                           nsTreeColumn*        aColumn,
00200                           const nsRect&        aProgressMeterRect,
00201                           nsPresContext*      aPresContext,
00202                           nsIRenderingContext& aRenderingContext,
00203                           const nsRect&        aDirtyRect);
00204 
00205   // This method paints a drop feedback of the tree.
00206   void PaintDropFeedback(const nsRect&        aDropFeedbackRect, 
00207                          nsPresContext*      aPresContext,
00208                          nsIRenderingContext& aRenderingContext,
00209                          const nsRect&        aDirtyRect);
00210 
00211   // This method is called with a specific style context and rect to
00212   // paint the background rect as if it were a full-blown frame.
00213   void PaintBackgroundLayer(nsStyleContext*      aStyleContext,
00214                             nsPresContext*      aPresContext, 
00215                             nsIRenderingContext& aRenderingContext, 
00216                             const nsRect&        aRect,
00217                             const nsRect&        aDirtyRect);
00218 
00219   friend nsresult NS_NewTreeBodyFrame(nsIPresShell* aPresShell, 
00220                                           nsIFrame** aNewFrame);
00221 
00222   struct ScrollParts {
00223     nsIScrollbarFrame* mVScrollbar;
00224     nsIContent*        mVScrollbarContent;
00225   };
00226 
00227 protected:
00228   PRInt32 GetLastVisibleRow() {
00229     return mTopRowIndex + mPageLength;
00230   };
00231 
00232   // An internal hit test.  aX and aY are expected to be in twips in the
00233   // coordinate system of this frame.
00234   PRInt32 GetRowAt(nscoord aX, nscoord aY);
00235 
00236   // A helper used when hit testing.
00237   nsIAtom* GetItemWithinCellAt(nscoord aX, const nsRect& aCellRect,
00238                                PRInt32 aRowIndex, nsTreeColumn* aColumn);
00239 
00240   // An internal hit test.  aX and aY are expected to be in twips in the
00241   // coordinate system of this frame.
00242   void GetCellAt(nscoord aX, nscoord aY, PRInt32* aRow, nsTreeColumn** aCol,
00243                  nsIAtom** aChildElt);
00244 
00245   // Fetch an image from the image cache.
00246   nsresult GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, PRBool aUseContext,
00247                     nsStyleContext* aStyleContext, PRBool& aAllowImageRegions, imgIContainer** aResult);
00248 
00249   // Returns the size of a given image.   This size *includes* border and
00250   // padding.  It does not include margins.
00251   nsRect GetImageSize(PRInt32 aRowIndex, nsTreeColumn* aCol, PRBool aUseContext, nsStyleContext* aStyleContext);
00252 
00253   // Returns the height of rows in the tree.
00254   PRInt32 GetRowHeight();
00255 
00256   // Returns our indentation width.
00257   PRInt32 GetIndentation();
00258 
00259   // Calculates our width/height once border and padding have been removed.
00260   void CalcInnerBox();
00261 
00262   // Looks up a style context in the style cache.  On a cache miss we resolve
00263   // the pseudo-styles passed in and place them into the cache.
00264   nsStyleContext* GetPseudoStyleContext(nsIAtom* aPseudoElement);
00265 
00266   // Retrieves the scrollbars and scrollview relevant to this treebody. We
00267   // traverse the frame tree under our base element, in frame order, looking
00268   // for the first relevant vertical scrollbar, horizontal scrollbar, and
00269   // scrollable frame (with associated content and scrollable view). These
00270   // are all volatile and should not be retained.
00271   ScrollParts GetScrollParts();
00272 
00273   // Update the curpos of the scrollbar.
00274   void UpdateScrollbar(const ScrollParts& aParts);
00275 
00276   // Update the maxpos of the scrollbar.
00277   void InvalidateScrollbar(const ScrollParts& aParts);
00278 
00279   // Check vertical overflow.
00280   void CheckVerticalOverflow();
00281   
00282   // Calls UpdateScrollbar, Invalidate if aNeedsFullInvalidation is PR_TRUE,
00283   // InvalidateScrollbar and finally CheckVerticalOverflow.
00284   // Returns PR_TRUE if the frame is still alive after the method call.
00285   PRBool FullScrollbarUpdate(PRBool aNeedsFullInvalidation);
00286 
00287   // Use to auto-fill some of the common properties without the view having to do it.
00288   // Examples include container, open, selected, and focus.
00289   void PrefillPropertyArray(PRInt32 aRowIndex, nsTreeColumn* aCol);
00290 
00291   nsresult ScrollInternal(const ScrollParts& aParts, PRInt32 aRow);
00292   nsresult ScrollToRowInternal(const ScrollParts& aParts, PRInt32 aRow);
00293   nsresult EnsureRowIsVisibleInternal(const ScrollParts& aParts, PRInt32 aRow);
00294 
00295   // Convert client pixels into twips in our coordinate space.
00296   void AdjustClientCoordsToBoxCoordSpace(PRInt32 aX, PRInt32 aY,
00297                                          nscoord* aResultX, nscoord* aResultY);
00298 
00299   // Convert a border style into line style.
00300   nsLineStyle ConvertBorderStyleToLineStyle(PRUint8 aBorderStyle);
00301 
00302   // Cache the box object
00303   void EnsureBoxObject();
00304 
00305   void EnsureView();
00306 
00307   // Get the base element, <tree> or <select>
00308   nsIContent* GetBaseElement();
00309 
00310   void GetCellWidth(PRInt32 aRow, nsTreeColumn* aCol,
00311                     nsIRenderingContext* aRenderingContext,
00312                     nscoord& aDesiredSize, nscoord& aCurrentSize);
00313   nscoord CalcMaxRowWidth();
00314 
00315   PRBool CanAutoScroll(PRInt32 aRowIndex);
00316 
00317   // Calc the row and above/below/on status given where the mouse currently is hovering.
00318   // Also calc if we're in the region in which we want to auto-scroll the tree.
00319   // A positive value of |aScrollLines| means scroll down, a negative value
00320   // means scroll up, a zero value means that we aren't in drag scroll region.
00321   void ComputeDropPosition(nsGUIEvent* aEvent, PRInt32* aRow, PRInt16* aOrient,
00322                            PRInt16* aScrollLines);
00323 
00324   // Mark ourselves dirty if we're a select widget
00325   void MarkDirtyIfSelect();
00326 
00327   void InvalidateDropFeedback(PRInt32 aRow, PRInt16 aOrientation) {
00328     InvalidateRow(aRow);
00329     if (aOrientation != nsITreeView::DROP_ON)
00330       InvalidateRow(aRow + aOrientation);
00331   };
00332 
00333   // Create a new timer. This method is used to delay various actions like
00334   // opening/closing folders or tree scrolling.
00335   // aID is type of the action, aFunc is the function to be called when
00336   // the timer fires and aType is type of timer - one shot or repeating.
00337   nsresult CreateTimer(const nsILookAndFeel::nsMetricID aID,
00338                        nsTimerCallbackFunc aFunc, PRInt32 aType,
00339                        nsITimer** aTimer);
00340 
00341   static void OpenCallback(nsITimer *aTimer, void *aClosure);
00342 
00343   static void CloseCallback(nsITimer *aTimer, void *aClosure);
00344 
00345   static void LazyScrollCallback(nsITimer *aTimer, void *aClosure);
00346 
00347   static void ScrollCallback(nsITimer *aTimer, void *aClosure);
00348 
00349 protected: // Data Members
00350   // Our cached pres context.
00351   nsPresContext* mPresContext;
00352 
00353   // The cached box object parent.
00354   nsCOMPtr<nsPITreeBoxObject> mTreeBoxObject;
00355 
00356   // Cached column information.
00357   nsRefPtr<nsTreeColumns> mColumns;
00358 
00359   // The current view for this tree widget.  We get all of our row and cell data
00360   // from the view.
00361   nsCOMPtr<nsITreeView> mView;    
00362 
00363   // A cache of all the style contexts we have seen for rows and cells of the tree.  This is a mapping from
00364   // a list of atoms to a corresponding style context.  This cache stores every combination that
00365   // occurs in the tree, so for n distinct properties, this cache could have 2 to the n entries
00366   // (the power set of all row properties).
00367   nsTreeStyleCache mStyleCache;
00368 
00369   // A hashtable that maps from URLs to image request/listener pairs.  The URL
00370   // is provided by the view or by the style context. The style context
00371   // represents a resolved :-moz-tree-cell-image (or twisty) pseudo-element.
00372   // It maps directly to an imgIRequest.
00373   nsDataHashtable<nsStringHashKey, nsTreeImageCacheEntry> mImageCache;
00374 
00375   // The index of the first visible row and the # of rows visible onscreen.  
00376   // The tree only examines onscreen rows, starting from
00377   // this index and going up to index+pageLength.
00378   PRInt32 mTopRowIndex;
00379   PRInt32 mPageLength;
00380 
00381   // Cached heights and indent info.
00382   nsRect mInnerBox;
00383   PRInt32 mRowHeight;
00384   PRInt32 mIndentation;
00385   nscoord mStringWidth;
00386 
00387   // A scratch array used when looking up cached style contexts.
00388   nsCOMPtr<nsISupportsArray> mScratchArray;
00389 
00390   // Whether or not we're currently focused.
00391   PRPackedBool mFocused;
00392 
00393   // Do we have a fixed number of onscreen rows?
00394   PRPackedBool mHasFixedRowCount;
00395 
00396   PRPackedBool mVerticalOverflow;
00397 
00398   nsRefPtr<nsTreeReflowCallback> mReflowCallback;
00399 
00400   PRInt32 mUpdateBatchNest;
00401 
00402   // Cached row count.
00403   PRInt32 mRowCount;
00404 
00405   class Slots {
00406     public:
00407       Slots()
00408         : mValueArray(~PRInt32(0)) {
00409       };
00410 
00411       ~Slots() {
00412         if (mTimer)
00413           mTimer->Cancel();
00414       };
00415 
00416       friend class nsTreeBodyFrame;
00417 
00418     protected:
00419       // If the drop is actually allowed here or not.
00420       PRBool                   mDropAllowed;
00421 
00422       // The row the mouse is hovering over during a drop.
00423       PRInt32                  mDropRow;
00424 
00425       // Where we want to draw feedback (above/on this row/below) if allowed.
00426       PRInt16                  mDropOrient;
00427 
00428       // Number of lines to be scrolled.
00429       PRInt16                  mScrollLines;
00430 
00431       // The drag action that was received for this slot
00432       PRUint32                 mDragAction;
00433 
00434       nsCOMPtr<nsIDragSession> mDragSession;
00435 
00436       // Timer for opening/closing spring loaded folders or scrolling the tree.
00437       nsCOMPtr<nsITimer>       mTimer;
00438 
00439       // A value array used to keep track of all spring loaded folders.
00440       nsValueArray             mValueArray;
00441   };
00442 
00443   Slots* mSlots;
00444 }; // class nsTreeBodyFrame