This is an automated email from the ASF dual-hosted git repository. piotrz pushed a commit to branch release/0.9.6 in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
commit 070f3c48991a79cb0494548f05250b8b87849c9e Author: Alex Harui <[email protected]> AuthorDate: Thu Sep 5 10:35:09 2019 -0700 virtual layout in ADG. Should fix #468 (cherry picked from commit 8ab1d813ee2f72bab957f9485e56ad89dcf6e1ab) --- .../MXRoyale/src/main/resources/defaults.css | 9 +- .../MXRoyale/src/main/royale/MXRoyaleClasses.as | 3 + .../AdvancedDataGridListArea.as | 72 ++++ ...actoryForICollectionViewAdvancedDataGridData.as | 106 ++++-- .../beads/layouts/AdvancedDataGridLayout.as | 145 ++++++++ .../AdvancedDataGridVirtualListVerticalLayout.as | 374 +++++++++++++++++++++ 6 files changed, 683 insertions(+), 26 deletions(-) diff --git a/frameworks/projects/MXRoyale/src/main/resources/defaults.css b/frameworks/projects/MXRoyale/src/main/resources/defaults.css index f11aae0..b66359c 100644 --- a/frameworks/projects/MXRoyale/src/main/resources/defaults.css +++ b/frameworks/projects/MXRoyale/src/main/resources/defaults.css @@ -81,9 +81,12 @@ AdvancedDataGrid IDataGridPresentationModel: ClassReference("org.apache.royale.html.beads.models.DataGridPresentationModel"); IBeadView: ClassReference("mx.controls.beads.AdvancedDataGridView"); IBeadModel: ClassReference("mx.controls.beads.models.DataGridICollectionViewModel"); - IBeadLayout: ClassReference("mx.controls.beads.layouts.DataGridLayout"); + IBeadLayout: ClassReference("mx.controls.beads.layouts.AdvancedDataGridLayout"); IDataProviderNotifier: ClassReference("mx.controls.beads.DataProviderChangeNotifier"); columnClass: ClassReference("mx.controls.advancedDataGridClasses.AdvancedDataGridColumnList"); + columnContainerClass: ClassReference("org.apache.royale.html.DataGridButtonBar"); + columnLayoutClass: ClassReference("org.apache.royale.html.beads.layouts.ButtonBarLayout"); + listAreaClass: ClassReference("mx.controls.advancedDataGridClasses.AdvancedDataGridListArea"); background-color: #FFFFFF; border: 1px solid #222222; @@ -94,9 +97,9 @@ AdvancedDataGrid adg|AdvancedDataGridColumnList { IBeadModel: ClassReference("mx.controls.beads.models.SingleSelectionICollectionViewModel"); IDataProviderItemRendererMapper: ClassReference("mx.controls.advancedDataGridClasses.DataItemRendererFactoryForICollectionViewAdvancedDataGridData"); - IBeadView: ClassReference("org.apache.royale.html.beads.ListView"); + IBeadView: ClassReference("org.apache.royale.html.beads.VirtualListView"); IBeadController: ClassReference("mx.controls.advancedDataGridClasses.AdvancedDataGridSingleSelectionMouseController"); - IBeadLayout: ClassReference("org.apache.royale.html.beads.layouts.VerticalLayout"); + IBeadLayout: ClassReference("mx.controls.beads.layouts.AdvancedDataGridVirtualListVerticalLayout"); IItemRendererClassFactory: ClassReference("org.apache.royale.core.ItemRendererClassFactory"); IItemRenderer: ClassReference("mx.controls.advancedDataGridClasses.AdvancedDataGridItemRenderer"); IViewport: ClassReference("org.apache.royale.html.supportClasses.Viewport"); diff --git a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as index 089aec6..9619309 100644 --- a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as +++ b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as @@ -159,10 +159,13 @@ internal class MXRoyaleClasses import mx.events.ProgressEvent; ProgressEvent; import mx.controls.advancedDataGridClasses.MXAdvancedDataGridItemRenderer; MXAdvancedDataGridItemRenderer; import mx.controls.advancedDataGridClasses.AdvancedDataGridColumnList; AdvancedDataGridColumnList; + import mx.controls.advancedDataGridClasses.AdvancedDataGridListArea; AdvancedDataGridListArea; import mx.controls.advancedDataGridClasses.AdvancedDataGridSingleSelectionMouseController; AdvancedDataGridSingleSelectionMouseController; import mx.controls.beads.AdvancedDataGridView; AdvancedDataGridView; import mx.controls.beads.DataGridView; DataGridView; + import mx.controls.beads.layouts.AdvancedDataGridLayout; AdvancedDataGridLayout; import mx.controls.beads.layouts.DataGridLayout; DataGridLayout; + import mx.controls.beads.layouts.AdvancedDataGridVirtualListVerticalLayout; AdvancedDataGridVirtualListVerticalLayout; import mx.formatters.Formatter; Formatter; import mx.formatters.IFormatter; IFormatter; import mx.formatters.NumberBase; NumberBase; diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/AdvancedDataGridListArea.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/AdvancedDataGridListArea.as new file mode 100644 index 0000000..4604f8d --- /dev/null +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/AdvancedDataGridListArea.as @@ -0,0 +1,72 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (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.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.controls.advancedDataGridClasses +{ + +/* import flash.display.DisplayObject; +import flash.events.Event; + */ +import mx.controls.AdvancedDataGrid; + +COMPILE::JS +{ +import org.apache.royale.core.WrappedHTMLElement; +} +import org.apache.royale.html.beads.DataGridListArea; + + +/** + * The AdvancedDataGridColumnList class represnts a column in an AdvancedDataGrid control. + * There is one AdvancedDataGridColumnList per displayable column, even if a column + * is hidden or off-screen. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Royale 0.9.3 + * @royalesuppresspublicvarwarning + */ +public class AdvancedDataGridListArea extends DataGridListArea +{ + public function AdvancedDataGridListArea() + { + super(); + typeNames += " AdvancedDataGridListArea"; + + } + + COMPILE::JS + override public function internalChildren():Array + { + var arr:Array = super.internalChildren(); + // remove scrolling divs from the list + // in theory, the only thing that calls this + // is HorizontalLayout + var children:Array = []; + for each (var child:WrappedHTMLElement in children) + { + if (child.royale_wrapper) + children.push(child); + } + return children; + } +} + +} diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/DataItemRendererFactoryForICollectionViewAdvancedDataGridData.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/DataItemRendererFactoryForICollectionViewAdvancedDataGridData.as index e749ac2..d56315a 100644 --- a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/DataItemRendererFactoryForICollectionViewAdvancedDataGridData.as +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/advancedDataGridClasses/DataItemRendererFactoryForICollectionViewAdvancedDataGridData.as @@ -20,6 +20,7 @@ package mx.controls.advancedDataGridClasses { import mx.collections.ICollectionView; import mx.collections.IViewCursor; + import mx.collections.CursorBookmark; import mx.controls.advancedDataGridClasses.AdvancedDataGridColumnList; import mx.core.IUIComponent; @@ -35,6 +36,7 @@ package mx.controls.advancedDataGridClasses import org.apache.royale.core.IListPresentationModel; import org.apache.royale.core.ISelectableItemRenderer; import org.apache.royale.core.IStrand; + import org.apache.royale.core.IStrandWithModelView; import org.apache.royale.core.IUIBase; import org.apache.royale.core.SimpleCSSStyles; import org.apache.royale.core.UIBase; @@ -45,7 +47,9 @@ package mx.controls.advancedDataGridClasses import org.apache.royale.events.IEventDispatcher; import org.apache.royale.events.ItemRendererEvent; import org.apache.royale.html.List; - import org.apache.royale.html.beads.DataItemRendererFactoryForCollectionView; + import org.apache.royale.html.beads.IListView; + import org.apache.royale.html.beads.VirtualDataItemRendererFactoryForArrayData; + import org.apache.royale.html.supportClasses.DataItemRenderer; import org.apache.royale.html.supportClasses.TreeListData; [Event(name="itemRendererCreated",type="org.apache.royale.events.ItemRendererEvent")] @@ -62,7 +66,7 @@ package mx.controls.advancedDataGridClasses * @playerversion AIR 2.6 * @productversion Royale 0.0 */ - public class DataItemRendererFactoryForICollectionViewAdvancedDataGridData extends DataItemRendererFactoryForCollectionView + public class DataItemRendererFactoryForICollectionViewAdvancedDataGridData extends VirtualDataItemRendererFactoryForArrayData { /** * Constructor. @@ -109,30 +113,23 @@ package mx.controls.advancedDataGridClasses if (!dp) return; - // listen for individual items being added in the future. - var dped:IEventDispatcher = dp as IEventDispatcher; - dped.addEventListener(CollectionEvent.ITEM_ADDED, itemAddedHandler); - dped.addEventListener(CollectionEvent.ITEM_REMOVED, itemRemovedHandler); - dped.addEventListener(CollectionEvent.ITEM_UPDATED, itemUpdatedHandler); - - dataGroup.removeAllItemRenderers(); + cursor = dp.createCursor(); + currentIndex = 0; - var presentationModel:IListPresentationModel = _strand.getBeadByType(IListPresentationModel) as IListPresentationModel; - labelField = dataProviderModel.labelField; - - var n:int = dp.length; - var cursor:IViewCursor = dp.createCursor(); - for (var i:int = 0; i < n; i++) - { - var ir:ISelectableItemRenderer = itemRendererFactory.createItemRenderer(dataGroup) as ISelectableItemRenderer; - var item:Object = cursor.current; - cursor.moveNext(); - fillRenderer(i, item, ir, presentationModel); - } + // listen for individual items being added in the future. + //var dped:IEventDispatcher = dp as IEventDispatcher; + //dped.addEventListener(CollectionEvent.ITEM_ADDED, itemAddedHandler); + //dped.addEventListener(CollectionEvent.ITEM_REMOVED, itemRemovedHandler); + //dped.addEventListener(CollectionEvent.ITEM_UPDATED, itemUpdatedHandler); + //dataGroup.removeAllItemRenderers(); + IEventDispatcher(_strand).dispatchEvent(new Event("itemsCreated")); + IEventDispatcher(_strand).dispatchEvent(new Event("layoutNeeded")); } + private var cursor:IViewCursor; + private var currentIndex:int; /** * Sets the itemRenderer's data with additional tree-related data. @@ -142,7 +139,7 @@ package mx.controls.advancedDataGridClasses * @playerversion AIR 2.6 * @productversion Royale 0.0 */ - override protected function setData(ir:ISelectableItemRenderer, data:Object, index:int):void + protected function setData(ir:ISelectableItemRenderer, data:Object, index:int):void { if (!(_strand as AdvancedDataGridColumnList).adg) return; @@ -162,7 +159,70 @@ package mx.controls.advancedDataGridClasses if (firstColumn && (_strand as AdvancedDataGridColumnList).adg.groupLabelField) ir.labelField = (_strand as AdvancedDataGridColumnList).adg.groupLabelField; - super.setData(ir, data, index); + ir.data = data; + ir.index = index; } + + /** + * Get an item renderer for a given index. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9.0 + * @royaleignorecoercion org.apache.royale.core.IStrandWithModelView + * @royaleignorecoercion org.apache.royale.html.beads.IListView + */ + override public function getItemRendererForIndex(index:int, elementIndex:int):ISelectableItemRenderer + { + var ir:ISelectableItemRenderer = rendererMap[index]; + if (ir) return ir; + + var dp:ICollectionView = dataProviderModel.dataProvider as ICollectionView; + + ir = itemRendererFactory.createItemRenderer(dataGroup) as ISelectableItemRenderer; + var dataItemRenderer:DataItemRenderer = ir as DataItemRenderer; + + var view:IListView = (_strand as IStrandWithModelView).view as IListView; + var dataGroup:IItemRendererParent = view.dataGroup; + dataGroup.addItemRendererAt(ir, elementIndex); + ir.labelField = labelField; + if (dataItemRenderer) + { + dataItemRenderer.dataField = dataField; + } + rendererMap[index] = ir; + + var presentationModel:IListPresentationModel = _strand.getBeadByType(IListPresentationModel) as IListPresentationModel; + if (presentationModel) { + var style:SimpleCSSStyles = new SimpleCSSStyles(); + style.marginBottom = presentationModel.separatorThickness; + UIBase(ir).style = style; + UIBase(ir).height = presentationModel.rowHeight; + UIBase(ir).percentWidth = 100; + } + var delta:int = index - currentIndex; + if (delta == -1) + { + cursor.movePrevious(); + } + else if (delta == 1) + { + cursor.moveNext(); + } + else if (delta != 0) + { + cursor.seek(CursorBookmark.CURRENT, delta); + } + currentIndex = index; + + var item:Object = cursor.current; + setData(ir, item, index); + + var newEvent:ItemRendererEvent = new ItemRendererEvent(ItemRendererEvent.CREATED); + newEvent.itemRenderer = ir; + dispatchEvent(newEvent); + return ir; + } } } diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridLayout.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridLayout.as new file mode 100644 index 0000000..37216e4 --- /dev/null +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridLayout.as @@ -0,0 +1,145 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (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.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// +package mx.controls.beads.layouts +{ + import mx.controls.dataGridClasses.DataGridColumn; + + import org.apache.royale.core.IBorderPaddingMarginValuesImpl; + import org.apache.royale.core.IDataGridModel; + import org.apache.royale.core.IDataProviderModel; + import org.apache.royale.core.IListPresentationModel; + import org.apache.royale.core.IStrand; + import org.apache.royale.core.IStrandWithPresentationModel; + import org.apache.royale.core.IUIBase; + import org.apache.royale.core.UIBase; + import org.apache.royale.core.ValuesManager; + import org.apache.royale.core.layout.EdgeData; + import org.apache.royale.events.Event; + import org.apache.royale.html.beads.IDataGridView; + import org.apache.royale.html.beads.models.ButtonBarModel; + + + /** + * The DataGridLayout class. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.0 + */ + public class AdvancedDataGridLayout extends DataGridLayout + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.0 + */ + public function AdvancedDataGridLayout() + { + } + + protected function scrollHandler(e:Event):void + { + layout(); + } + + COMPILE::JS + protected var topSpacer:HTMLDivElement; + + COMPILE::JS + protected var bottomSpacer:HTMLDivElement; + + COMPILE::JS + private var listening:Boolean; + + /** + * @copy org.apache.royale.core.IBeadLayout#layout + * @royaleignorecoercion org.apache.royale.core.IBorderPaddingMarginValuesImpl + * @royaleignorecoercion org.apache.royale.core.IDataGridModel + * @royaleignorecoercion org.apache.royale.core.IUIBase + * @royaleignorecoercion org.apache.royale.core.UIBase + * @royaleignorecoercion org.apache.royale.html.beads.IDataGridView + * @royaleignorecoercion org.apache.royale.html.beads.models.ButtonBarModel + * @royaleignorecoercion org.apache.royale.html.supportClasses.IDataGridColumn + */ + override public function layout():Boolean + { + var presentationModel:IListPresentationModel = (uiHost as IStrandWithPresentationModel).presentationModel as IListPresentationModel; + var retval:Boolean = super.layout(); + COMPILE::JS + { + if (!listening) + (uiHost.view as IDataGridView).listArea.element.addEventListener("scroll", scrollHandler); + listening = true; + } + if (!uiHost.isHeightSizedToContent()) + { + var header:IUIBase = (uiHost.view as IDataGridView).header; + var bbmodel:ButtonBarModel = header.getBeadByType(ButtonBarModel) as ButtonBarModel; + // do the proportional sizing of columns + var borderMetrics:EdgeData = (ValuesManager.valuesImpl as IBorderPaddingMarginValuesImpl).getBorderMetrics(_strand as IUIBase); + var useWidth:Number = uiHost.width - (borderMetrics.left + borderMetrics.right); + var useHeight:Number = uiHost.height - (borderMetrics.top + borderMetrics.bottom); + var displayedColumns:Array = (uiHost.view as IDataGridView).columnLists; + var n:int = displayedColumns.length; + var listArea:IUIBase = (uiHost.view as IDataGridView).listArea; + COMPILE::JS + { + var topSpacerHeight:Number = Math.floor(listArea.element.scrollTop / presentationModel.rowHeight) + * presentationModel.rowHeight; + } + for (var i:int = 0; i < n; i++) + { + var columnList:UIBase = displayedColumns[i] as UIBase; + columnList.height = useHeight; + COMPILE::JS + { + columnList.element.style.position = "absolute"; + columnList.element.style.top = (topSpacerHeight + 1).toString() + 'px'; + columnList.dispatchEvent(new Event("layoutNeeded")); + } + } + var model:IDataGridModel = uiHost.model as IDataGridModel; + if (model.dataProvider && model.dataProvider.length) + { + var totalHeight:Number = model.dataProvider.length * presentationModel.rowHeight; + COMPILE::JS + { + if (!topSpacer) + { + topSpacer = document.createElement("div") as HTMLDivElement; + listArea.element.insertBefore(topSpacer, (listArea as UIBase).internalChildren()[0]); + } + topSpacer.style.height = topSpacerHeight.toString() + "px"; + if (!bottomSpacer) + { + bottomSpacer = document.createElement("div") as HTMLDivElement; + listArea.element.appendChild(bottomSpacer); + } + bottomSpacer.style.height = (totalHeight - useHeight - topSpacerHeight).toString() + "px"; + } + } + } + return retval; + } + } +} diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridVirtualListVerticalLayout.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridVirtualListVerticalLayout.as new file mode 100644 index 0000000..33d72d6 --- /dev/null +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/layouts/AdvancedDataGridVirtualListVerticalLayout.as @@ -0,0 +1,374 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (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.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// +package mx.controls.beads.layouts +{ + import org.apache.royale.core.IBorderPaddingMarginValuesImpl; + import org.apache.royale.core.IDataProviderModel; + import org.apache.royale.core.IDataProviderVirtualItemRendererMapper; + import org.apache.royale.core.ILayoutView; + import org.apache.royale.core.IListPresentationModel; + import org.apache.royale.core.IScrollingViewport; + import org.apache.royale.core.ISelectableItemRenderer; + import org.apache.royale.core.IStrand; + import org.apache.royale.core.IStrandWithPresentationModel; + import org.apache.royale.core.IUIBase; + import org.apache.royale.core.ValuesManager; + import org.apache.royale.core.layout.EdgeData; + import org.apache.royale.events.Event; + import org.apache.royale.html.beads.IDataGridView; + import org.apache.royale.html.beads.layouts.VirtualListVerticalLayout; + import org.apache.royale.html.beads.models.ButtonBarModel; + import org.apache.royale.html.beads.VirtualDataContainerView; + + + COMPILE::SWF { + import org.apache.royale.geom.Size; + } + + /** + * The AdvancedDataGridVirtualListVerticalLayout class. It works a bit differently + * from other VirtualLayouts for JS because the div padding is applied to the container + * of these column lists. The lists don't scroll, they only update the renderers + * for the viewport. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.0 + */ + public class AdvancedDataGridVirtualListVerticalLayout extends org.apache.royale.html.beads.layouts.VirtualListVerticalLayout + { + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.0 + */ + public function AdvancedDataGridVirtualListVerticalLayout() + { + } + + override public function set strand(value:IStrand):void + { + super.strand = value; + dataProviderModel.addEventListener("dataProviderChanged", dataProviderChangeHandler); + } + + private function dataProviderChangeHandler(event:Event):void + { + var factory:IDataProviderVirtualItemRendererMapper = host.getBeadByType(IDataProviderVirtualItemRendererMapper) as IDataProviderVirtualItemRendererMapper; + while (visibleIndexes.length) + { + var index:int = visibleIndexes.pop(); + factory.freeItemRendererForIndex(index); + } + } + + private var inLayout:Boolean; + + /** + * Layout children vertically + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.0 + * @royaleignorecoercion Array + * @royaleignorecoercion org.apache.royale.core.ILayoutHost + * @royaleignorecoercion org.apache.royale.core.WrappedHTMLElement + * @royaleignorecoercion org.apache.royale.core.IListPresentationModel + * @royaleignorecoercion org.apache.royale.core.IStrandWithPresentationModel + */ + override public function layout():Boolean + { + if (inLayout) return true; + inLayout = true; + + COMPILE::SWF + { + // the strategy for virtualization in SWF is based on the + // fact that we can completely control the scrolling metrics + // instead of trying to rely on the browsers built-in scrolling. + // This code puts enough renderers on the screen and then dictates + // the scrolling metrics. + var contentView:ILayoutView = layoutView; + + var maxWidth:Number = 0; + var maxHeight:Number = 0; + var dp:Array = dataProviderModel.dataProvider as Array; + if (!dp) + { + inLayout = false; + return true; + } + var presentationModel:IListPresentationModel = (host as IStrandWithPresentationModel).presentationModel as IListPresentationModel; + var hostWidthSizedToContent:Boolean = host.isWidthSizedToContent(); + var hostHeightSizedToContent:Boolean = host.isHeightSizedToContent(); + var hostWidth:Number = host.width; + var hostHeight:Number = host.height; + + var data:Object; + var canAdjust:Boolean = false; + + var paddingMetrics:EdgeData = (ValuesManager.valuesImpl as IBorderPaddingMarginValuesImpl).getPaddingMetrics(host); + var borderMetrics:EdgeData = (ValuesManager.valuesImpl as IBorderPaddingMarginValuesImpl).getBorderMetrics(host); + + // adjust the host's usable size by the metrics. If hostSizedToContent, then the + // resulting adjusted value may be less than zero. + hostWidth -= paddingMetrics.left + paddingMetrics.right + borderMetrics.left + borderMetrics.right; + hostHeight -= paddingMetrics.top + paddingMetrics.bottom + borderMetrics.top + borderMetrics.bottom; + + var xpos:Number = borderMetrics.left + paddingMetrics.left; + var ypos:Number = borderMetrics.top + paddingMetrics.top; + + var viewport:IScrollingViewport = host.getBeadByType(IScrollingViewport) as IScrollingViewport; + viewport.addEventListener("verticalScrollPositionChanged", scrollHandler); + var viewportTop:Number = getVerticalScrollPosition(); + var viewportHeight:Number = hostHeight; + var startIndex:int = Math.floor(viewportTop / presentationModel.rowHeight); + var factory:IDataProviderVirtualItemRendererMapper = host.getBeadByType(IDataProviderVirtualItemRendererMapper) as IDataProviderVirtualItemRendererMapper; + var endIndex:int = Math.ceil((viewportTop + viewportHeight) / presentationModel.rowHeight); + var freeIndex:int; + var firstIndex:int; + var lastIndex:int; + + if (visibleIndexes.length) + { + if (startIndex < visibleIndexes[0]) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.pop(); + while (freeIndex >= endIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.pop(); + } + if (visibleIndexes.length) + endIndex = visibleIndexes[visibleIndexes.length - 1]; + } + else if (startIndex > visibleIndexes[0]) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.shift(); + while (freeIndex < startIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.shift(); + } + } + else + { + // see if rows got added or removed because height changed + lastIndex = visibleIndexes[visibleIndexes.length - 1]; + if (lastIndex > endIndex) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.pop(); + while (freeIndex > endIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.pop(); + } + inLayout = false; + return true; // we should be all done if we shrunk + } + } + firstIndex = visibleIndexes[0]; + lastIndex = visibleIndexes[visibleIndexes.length - 1]; + } + else + { + firstIndex = dp.length; + lastIndex = 0; + } + for (var i:int = startIndex; i < endIndex; i++) + { + if (i >= dp.length) continue; // no more renderers needed + + var ir:ISelectableItemRenderer; + if (i < firstIndex) + { + ir = factory.getItemRendererForIndex(i, i - startIndex); + sizeAndPositionRenderer(ir, xpos, ypos + (presentationModel.rowHeight * i), hostWidth, hostHeight); + visibleIndexes.push(i); + } + else if (i > lastIndex) + { + ir = factory.getItemRendererForIndex(i, i - startIndex); + sizeAndPositionRenderer(ir, xpos, ypos + (presentationModel.rowHeight * i), hostWidth, hostHeight); + visibleIndexes.push(i); + } + } + visibleIndexes = visibleIndexes.sort(numberSort); + + var view:VirtualDataContainerView = host.getBeadByType(VirtualDataContainerView) as VirtualDataContainerView; + view.lastContentSize = new Size(hostWidth, dp.length * presentationModel.rowHeight); + + inLayout = false; + return true; + } + COMPILE::JS + { + // the strategy for virtualization in JS is to leverage the built-in scrollbars + // by creating a topSpacer and bottomSpacer that take up the area that is offscreen + // so the scrollbars have the right metrics, then create enough renderers to + // show in the visible area. This code does not recycle renderers, but the + // factory can. This code does try to keep renderers on the DOM that aren't + // going off-screen + var contentView:ILayoutView = layoutView; + var dp:Array = dataProviderModel.dataProvider as Array; + if (!dp) + { + inLayout = false; + return true; + } + var presentationModel:IListPresentationModel = (host as IStrandWithPresentationModel).presentationModel as IListPresentationModel; + var totalHeight:Number = presentationModel.rowHeight * dp.length; + var viewportTop:Number = getVerticalScrollPosition(); + // correct overscroll on Safari? + var top:String = host.element.style.top; + var c:int = top.indexOf("px"); + if (c > 0) + { + var topValue:Number = parseFloat(top.substring(0, c)); + if (topValue < 0) + { + trace(host.element.style.top); + host.element.style.top = "1px"; + } + } + // end correct overscroll on Safari + var viewportHeight:Number = contentView.element.clientHeight; + var startIndex:int = Math.floor(viewportTop / presentationModel.rowHeight); + var factory:IDataProviderVirtualItemRendererMapper = host.getBeadByType(IDataProviderVirtualItemRendererMapper) as IDataProviderVirtualItemRendererMapper; + var endIndex:int = Math.ceil((viewportTop + viewportHeight) / presentationModel.rowHeight); + var freeIndex:int; + var firstIndex:int; + var lastIndex:int; + if (visibleIndexes.length) + { + if (startIndex < visibleIndexes[0]) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.pop(); + while (freeIndex >= endIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.pop(); + } + if (visibleIndexes.length) + endIndex = visibleIndexes[visibleIndexes.length - 1]; + } + else if (startIndex > visibleIndexes[0]) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.shift(); + while (freeIndex < startIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.shift(); + } + } + else + { + // see if rows got added or removed because height changed + lastIndex = visibleIndexes[visibleIndexes.length - 1]; + if (lastIndex > endIndex) + { + // see if we can re-use any renderers + freeIndex = visibleIndexes.pop(); + while (freeIndex > endIndex) + { + factory.freeItemRendererForIndex(freeIndex); + if (visibleIndexes.length == 0) + break; + freeIndex = visibleIndexes.pop(); + } + inLayout = false; + return true; // we should be all done if we shrunk + } + } + firstIndex = visibleIndexes[0]; + lastIndex = visibleIndexes[visibleIndexes.length - 1]; + } + else + { + firstIndex = dp.length; + lastIndex = 0; + } + for (var i:int = startIndex; i < endIndex; i++) + { + if (i >= dp.length) continue; // no more renderers needed + + var ir:ISelectableItemRenderer; + if (i < firstIndex) + { + // the base class adds 1 because the div/scroll padding is in the + // same list/datagroup, but for ADG, the padding is outside of the lists + ir = factory.getItemRendererForIndex(i, i - startIndex); + ir.element.style.display = "block"; + visibleIndexes.push(i); + } + else if (i > lastIndex) + { + ir = factory.getItemRendererForIndex(i, i - startIndex); + ir.element.style.display = "block"; + visibleIndexes.push(i); + } + } + visibleIndexes = visibleIndexes.sort(numberSort); + inLayout = false; + return true; + } + } + + /** + * @royaleignorecoercion HTMLDivElement + */ + private function getVerticalScrollPosition():Number + { + COMPILE::SWF + { + return 0; // to do + } + COMPILE::JS + { + return Math.max((host.element.parentNode as HTMLDivElement).scrollTop, 0); + } + } + + override protected function scrollHandler(e:Event):void + { + // don't scroll. The container of these column lists does the scrolling + } + + } +}
