You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by pi...@apache.org on 2019/09/10 04:49:59 UTC

[royale-asjs] 02/04: virtual layout in ADG. Should fix #468

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 <ah...@apache.org>
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
+        }
+        
+	}
+}