//////////////////////////////////////////////////////////////////////////////// // // 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.managers.layoutClasses { import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.utils.Dictionary; import mx.core.IChildList; import mx.core.IRawChildrenContainer; import mx.managers.ILayoutManagerClient; [ExcludeClass] /** * @private * The PriorityQueue class provides a general purpose priority queue. * It is used internally by the LayoutManager. */ public class PriorityQueue { include "../../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function PriorityQueue() { super(); } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private */ private var priorityBins:Array = []; /** * @private * The smallest occupied index in arrayOfDictionaries. */ private var minPriority:int = 0; /** * @private * The largest occupied index in arrayOfDictionaries. */ private var maxPriority:int = -1; //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @private */ public function addObject(obj:Object, priority:int):void { // Update our min and max priorities. if (maxPriority < minPriority) { minPriority = maxPriority = priority; } else { if (priority < minPriority) minPriority = priority; if (priority > maxPriority) maxPriority = priority; } var bin:PriorityBin = priorityBins[priority]; if (!bin) { // If no hash exists for the specified priority, create one. bin = new PriorityBin(); priorityBins[priority] = bin; bin.items[obj] = true; bin.length++; } else { // If we don't already hold the obj in the specified hash, add it // and update our item count. if (bin.items[obj] == null) { bin.items[obj] = true; bin.length++; } } } /** * @private */ public function removeLargest():Object { var obj:Object = null; if (minPriority <= maxPriority) { var bin:PriorityBin = priorityBins[maxPriority]; while (!bin || bin.length == 0) { maxPriority--; if (maxPriority < minPriority) return null; bin = priorityBins[maxPriority]; } // Remove the item with largest priority from our priority queue. // Must use a for loop here since we're removing a specific item // from a 'Dictionary' (no means of directly indexing). for (var key:Object in bin.items ) { obj = key; removeChild(ILayoutManagerClient(key), maxPriority); break; } // Update maxPriority if applicable. while (!bin || bin.length == 0) { maxPriority--; if (maxPriority < minPriority) break; bin = priorityBins[maxPriority]; } } return obj; } /** * @private */ public function removeLargestChild(client:ILayoutManagerClient ):Object { var max:int = maxPriority; var min:int = client.nestLevel; while (min <= max) { var bin:PriorityBin = priorityBins[max]; if (bin && bin.length > 0) { if (max == client.nestLevel) { // If the current level we're searching matches that of our // client, no need to search the entire list, just check to see // if the client exists in the queue (it would be the only item // at that nestLevel). if (bin.items[client]) { removeChild(ILayoutManagerClient(client), max); return client; } } else { for (var key:Object in bin.items ) { if ((key is DisplayObject) && contains(DisplayObject(client), DisplayObject(key))) { removeChild(ILayoutManagerClient(key), max); return key; } } } max--; } else { if (max == maxPriority) maxPriority--; max--; if (max < min) break; } } return null; } /** * @private */ public function removeSmallest():Object { var obj:Object = null; if (minPriority <= maxPriority) { var bin:PriorityBin = priorityBins[minPriority]; while (!bin || bin.length == 0) { minPriority++; if (minPriority > maxPriority) return null; bin = priorityBins[minPriority]; } // Remove the item with smallest priority from our priority queue. // Must use a for loop here since we're removing a specific item // from a 'Dictionary' (no means of directly indexing). for (var key:Object in bin.items ) { obj = key; removeChild(ILayoutManagerClient(key), minPriority); break; } // Update minPriority if applicable. while (!bin || bin.length == 0) { minPriority++; if (minPriority > maxPriority) break; bin = priorityBins[minPriority]; } } return obj; } /** * @private */ public function removeSmallestChild(client:ILayoutManagerClient ):Object { var min:int = client.nestLevel; while (min <= maxPriority) { var bin:PriorityBin = priorityBins[min]; if (bin && bin.length > 0) { if (min == client.nestLevel) { // If the current level we're searching matches that of our // client, no need to search the entire list, just check to see // if the client exists in the queue (it would be the only item // at that nestLevel). if (bin.items[client]) { removeChild(ILayoutManagerClient(client), min); return client; } } else { for (var key:Object in bin.items) { if ((key is DisplayObject) && contains(DisplayObject(client), DisplayObject(key))) { removeChild(ILayoutManagerClient(key), min); return key; } } } min++; } else { if (min == minPriority) minPriority++; min++; if (min > maxPriority) break; } } return null; } /** * @private */ public function removeChild(client:ILayoutManagerClient, level:int=-1):Object { var priority:int = (level >= 0) ? level : client.nestLevel; var bin:PriorityBin = priorityBins[priority]; if (bin && bin.items[client] != null) { delete bin.items[client]; bin.length--; return client; } return null; } /** * @private */ public function removeAll():void { priorityBins.length = 0; minPriority = 0; maxPriority = -1; } /** * @private */ public function isEmpty():Boolean { return minPriority > maxPriority; } /** * @private */ private function contains(parent:DisplayObject, child:DisplayObject):Boolean { if (parent is IRawChildrenContainer) { var rawChildren:IChildList = IRawChildrenContainer(parent).rawChildren; return rawChildren.contains(child); } else if (parent is DisplayObjectContainer) { return DisplayObjectContainer(parent).contains(child); } return parent == child; } } } import flash.utils.Dictionary; /** * Represents one priority bucket of entries. * @private */ class PriorityBin { public var length:int; public var items:Dictionary = new Dictionary(); }