blob: ff704231b3b1d33763c36b08b8a3f91954056c1b [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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();
}