/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Original Author: David W. Hyatt (hyatt@netscape.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 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsXULTreeFrame.h" #include "nsIScrollableFrame.h" #include "nsIDOMElement.h" #include "nsXULTreeOuterGroupFrame.h" #include "nsXULAtoms.h" #include "nsINameSpaceManager.h" // // NS_NewXULTreeFrame // // Creates a new tree frame // nsresult NS_NewXULTreeFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool aIsRoot, nsIBoxLayout* aLayoutManager) { NS_PRECONDITION(aNewFrame, "null OUT ptr"); if (nsnull == aNewFrame) { return NS_ERROR_NULL_POINTER; } nsXULTreeFrame* it = new (aPresShell) nsXULTreeFrame(aPresShell, aIsRoot, aLayoutManager); if (!it) return NS_ERROR_OUT_OF_MEMORY; *aNewFrame = it; return NS_OK; } // NS_NewXULTreeFrame // Constructor nsXULTreeFrame::nsXULTreeFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager) :nsBoxFrame(aPresShell, aIsRoot, aLayoutManager) { mPresShell = aPresShell; } // Destructor nsXULTreeFrame::~nsXULTreeFrame() { } NS_IMETHODIMP_(nsrefcnt) nsXULTreeFrame::AddRef(void) { return NS_OK; } NS_IMETHODIMP_(nsrefcnt) nsXULTreeFrame::Release(void) { return NS_OK; } // // QueryInterface // NS_INTERFACE_MAP_BEGIN(nsXULTreeFrame) NS_INTERFACE_MAP_ENTRY(nsITreeFrame) NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame) static void GetImmediateChild(nsIContent* aParent, nsIAtom* aTag, nsIContent** aResult) { *aResult = nsnull; PRInt32 childCount; aParent->ChildCount(childCount); for (PRInt32 i = 0; i < childCount; i++) { nsCOMPtr child; aParent->ChildAt(i, *getter_AddRefs(child)); nsCOMPtr tag; child->GetTag(*getter_AddRefs(tag)); if (aTag == tag.get()) { *aResult = child; NS_ADDREF(*aResult); return; } } return; } NS_IMETHODIMP nsXULTreeFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState) { nsresult rv = nsBoxFrame::DoLayout(aBoxLayoutState); return rv; } NS_IMETHODIMP nsXULTreeFrame::EnsureRowIsVisible(PRInt32 aRowIndex) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; GetTreeBody(&XULTreeOuterGroup); if (!XULTreeOuterGroup) return NS_OK; XULTreeOuterGroup->EnsureRowIsVisible(aRowIndex); return NS_OK; } /* void scrollToIndex (in long rowIndex); */ NS_IMETHODIMP nsXULTreeFrame::ScrollToIndex(PRInt32 aRowIndex) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; GetTreeBody(&XULTreeOuterGroup); if (!XULTreeOuterGroup) return NS_OK; XULTreeOuterGroup->ScrollToIndex(aRowIndex); return NS_OK; } NS_IMETHODIMP nsXULTreeFrame::ScrollByLines(nsIPresContext* aPresContext, PRInt32 aNumLines) { PRInt32 scrollIndex, visibleRows; GetIndexOfFirstVisibleRow(&scrollIndex); GetNumberOfVisibleRows(&visibleRows); scrollIndex += aNumLines; if (scrollIndex < 0) scrollIndex = 0; else { PRInt32 numRows; GetRowCount(&numRows); PRInt32 lastPageTopRow = numRows - visibleRows; if (scrollIndex > lastPageTopRow) scrollIndex = lastPageTopRow; } ScrollToIndex(scrollIndex); // we have to do a sync update for mac because if we scroll too quickly // w/out going back to the main event loop we can easily scroll the wrong // bits and it looks like garbage (bug 63465). nsIFrame* frame = nsnull; if ( NS_SUCCEEDED(QueryInterface(NS_GET_IID(nsIFrame), (void **)&frame)) ) { nsIView* treeView = nsnull; frame->GetView(aPresContext, &treeView); if (!treeView) { nsIFrame* frameWithView; frame->GetParentWithView(aPresContext, &frameWithView); if (frameWithView) frameWithView->GetView(aPresContext, &treeView); else return NS_ERROR_FAILURE; } if (treeView) { nsCOMPtr vm; if (treeView->GetViewManager(*getter_AddRefs(vm)) && nsnull != vm) { // I'd use Composite here, but it doesn't always work. // vm->Composite(); vm->ForceUpdate(); } } } else return NS_ERROR_FAILURE; return NS_OK; } /* nsIDOMElement getNextItem (in nsIDOMElement startItem, in long delta); */ NS_IMETHODIMP nsXULTreeFrame::GetNextItem(nsIDOMElement *aStartItem, PRInt32 aDelta, nsIDOMElement **aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. nsCOMPtr start(do_QueryInterface(aStartItem)); nsCOMPtr row; GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row)); nsCOMPtr result; treeOuterGroup->FindNextRowContent(aDelta, row, nsnull, getter_AddRefs(result)); if (!result) return NS_OK; nsCOMPtr parent; result->GetParent(*getter_AddRefs(parent)); if (!parent) return NS_OK; nsCOMPtr item(do_QueryInterface(parent)); *aResult = item; NS_IF_ADDREF(*aResult); return NS_OK; } /* nsIDOMElement getPreviousItem (in nsIDOMElement startItem, in long delta); */ NS_IMETHODIMP nsXULTreeFrame::GetPreviousItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. nsCOMPtr start(do_QueryInterface(aStartItem)); nsCOMPtr row; GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row)); nsCOMPtr result; treeOuterGroup->FindPreviousRowContent(aDelta, row, nsnull, getter_AddRefs(result)); if (!result) return NS_OK; nsCOMPtr parent; result->GetParent(*getter_AddRefs(parent)); if (!parent) return NS_OK; nsCOMPtr item(do_QueryInterface(parent)); *aResult = item; NS_IF_ADDREF(*aResult); return NS_OK; } /* nsIDOMElement getItemAtIndex (in long index); */ NS_IMETHODIMP nsXULTreeFrame::GetItemAtIndex(PRInt32 aIndex, nsIDOMElement **aResult) { *aResult = nsnull; // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. nsCOMPtr result; treeOuterGroup->FindRowContentAtIndex(aIndex, nsnull, getter_AddRefs(result)); if (!result) return NS_OK; nsCOMPtr parent; result->GetParent(*getter_AddRefs(parent)); if (!parent) return NS_OK; nsCOMPtr item(do_QueryInterface(parent)); *aResult = item; NS_IF_ADDREF(*aResult); return NS_OK; } /* long getIndexOfItem (in nsIDOMElement item); */ NS_IMETHODIMP nsXULTreeFrame::GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aElement, PRInt32* aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. nsCOMPtr content(do_QueryInterface(aElement)); nsCOMPtr root; treeOuterGroup->GetContent(getter_AddRefs(root)); return treeOuterGroup->IndexOfItem(root, content, PR_FALSE, PR_TRUE, aResult); } /* void getNumberOfVisibleRows (); */ NS_IMETHODIMP nsXULTreeFrame::GetNumberOfVisibleRows(PRInt32 *aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; GetTreeBody(&XULTreeOuterGroup); if (!XULTreeOuterGroup) return NS_OK; return XULTreeOuterGroup->GetNumberOfVisibleRows(aResult); } /* void getIndexOfFirstVisibleRow (); */ NS_IMETHODIMP nsXULTreeFrame::GetIndexOfFirstVisibleRow(PRInt32 *aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; GetTreeBody(&XULTreeOuterGroup); if (!XULTreeOuterGroup) return NS_OK; return XULTreeOuterGroup->GetIndexOfFirstVisibleRow(aResult); } NS_IMETHODIMP nsXULTreeFrame::GetRowCount(PRInt32 *aResult) { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; GetTreeBody(&XULTreeOuterGroup); // initialize out param *aResult = 0; if (!XULTreeOuterGroup) return NS_OK; return XULTreeOuterGroup->GetRowCount(aResult); } NS_IMETHODIMP nsXULTreeFrame::BeginBatch() { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. return treeOuterGroup->BeginBatch(); } NS_IMETHODIMP nsXULTreeFrame::EndBatch() { // Get our treechildren child frame. nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (!treeOuterGroup) return NS_OK; // No tree body. Just bail. return treeOuterGroup->EndBatch(); } void nsXULTreeFrame::GetTreeBody(nsXULTreeOuterGroupFrame** aResult) { nsCOMPtr child; PRInt32 count; mContent->ChildCount(count); for (PRInt32 i = 0; i < count; i++) { mContent->ChildAt(i, *getter_AddRefs(child)); if (child) { nsCOMPtr tag; child->GetTag(*getter_AddRefs(tag)); if (tag && tag.get() == nsXULAtoms::treechildren) { // This is our actual treechildren frame. nsIFrame* frame; mPresShell->GetPrimaryFrameFor(child, &frame); if (frame) { nsCOMPtr scroll(do_QueryInterface(frame)); if (scroll) { scroll->GetScrolledFrame(nsnull, frame); } *aResult = (nsXULTreeOuterGroupFrame*)frame; return; } } } } *aResult = nsnull; } NS_IMETHODIMP nsXULTreeFrame::AttributeChanged (nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, PRInt32 aHint) { if (aAttribute == nsXULAtoms::rows) { nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; GetTreeBody(&treeOuterGroup); if (treeOuterGroup) { nsCOMPtrchild; treeOuterGroup->GetContent(getter_AddRefs(child)); nsAutoString rows; mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::rows, rows); if (!rows.IsEmpty()) { PRInt32 dummy; PRInt32 count = rows.ToInteger(&dummy); float t2p; aPresContext->GetTwipsToPixels(&t2p); PRInt32 rowHeight = treeOuterGroup->GetRowHeightTwips(); rowHeight = NSTwipsToIntPixels(rowHeight, t2p); nsAutoString value; value.AppendInt(rowHeight*count); child->SetAttr(kNameSpaceID_None, nsXULAtoms::minheight, value, PR_FALSE); nsBoxLayoutState state(aPresContext); treeOuterGroup->MarkDirty(state); } } return NS_OK; } else return nsBoxFrame::AttributeChanged(aPresContext, aChild, aNameSpaceID, aAttribute, aModType, aHint); }