#
# Copyright (c) 2002, 2003, 2004 Art Haas
#
# This file is part of PythonCAD.
#
# PythonCAD is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PythonCAD is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# The Layer class
#

import warnings
import sys
import types

import point
import segment
import circle
import arc
import hcline
import vcline
import acline
import cline
import ccircle
import segjoint
import leader
import polyline
import text
import dimension
import dimtrees
import tolerance
import entity
import logger

class Layer(entity.Entity):
    """The Layer class.

A Layer object holds all the various entities that can be
in a drawing. Each layer can have sublayers, and there is
no limit to the depth of the sublayering.

A Layer object has several attributes:

name: The Layer's name
parent: The parent Layer of the Layer
scale: The scale factor for object contained in the Layer

A Layer object has the following methods:

{get/set}Name(): Get/Set the Layer's name.
{get/set}Parent(): Get/Set the Layer's parent.
getEntities(): Return all of a type of entity in the Layer.
{add/del}Child(): Add/Remove a new child Layer to the Layer.
{add/del}Object(): Store/Remove a Point, Segment, etc. in the Layer.
findObject(): Return an object in the layer equivalent to a test object.
getObject(): Return an object with a specified ID
mapPoint(): See if a non-Point object in the layer crosses some location.
{get/set}Visibility(): Get/Set the visibility of the Layer.
getBoundary(): Find the maximum and minimum coordinates of the Layer.
objsInRegion(): Return all the objects in the Layer that can be seen
                within some view.
update(): Check that all objects in the layer are stored properly.
    """

    messages = {
        'attribute_changed' : True,
        'added_sublayer' : True,
        'deleted_sublayer' : True,
        }
    def __init__(self, name=None, **kw):
        """Initializee a Layer.

Layer([name)

Argument name is optional. The name should be a unicode string
if specified, otherwise a default name of 'Layer' is given.
        """
        _n = name
        if _n is None:
            _n = u'Layer'
        if not isinstance(_n, types.StringTypes):
            raise TypeError, "Invalid layer name: " + str(name)
        if isinstance(name, str):
            _n = unicode(name)
        entity.Entity.__init__(self, **kw)
        self.__name = _n
        self.__points = point.PointQuadtree()
        self.__segments = segment.SegmentQuadtree()
        self.__circles = circle.CircleQuadtree()
        self.__arcs = arc.ArcQuadtree()
        self.__hclines = hcline.HCLineQuadtree()
        self.__vclines = vcline.VCLineQuadtree()
        self.__aclines = acline.ACLineQuadtree()
        self.__clines = cline.CLineQuadtree()
        self.__ccircles = ccircle.CCircleQuadtree()
        self.__chamfers = [] # should be Quadtree
        self.__fillets = [] # should be Quadtree
        self.__leaders = leader.LeaderQuadtree()
        self.__polylines = polyline.PolylineQuadtree()
        self.__textblocks = [] # should be Quadtree
        self.__ldims = dimtrees.LDimQuadtree()
        self.__hdims = dimtrees.HDimQuadtree()
        self.__vdims = dimtrees.VDimQuadtree()
        self.__rdims = dimtrees.RDimQuadtree()
        self.__adims = dimtrees.ADimQuadtree()
        self.__scale = 1.0
        self.__parent_layer = None
        self.__sublayers = None
        #
        # self.__objects keeps a reference to all objects stored in the layer
        #
        self.__objects = {}
        self.__objids = {}
        self.__logs = {}

    def __str__(self):
        _p = self.getParent()
        if _p is None:
            _s = "Layer: %s [No Parent]" % self.__name
        else:
            _s = "Layer: %s; Parent: %s" % (self.__name, _p.getName())
        return _s

    def __contains__(self, obj):
        """Find an object in the Layer.

This method permits the use of 'in' for test conditions.

if obj in layer:
    ....

This function tests for Point, Segment, Circle, etc. It returns
True if there is an equivalent object held in the Layer. Otherwise
the function returns False.
        """
        _seen = False
        if id(obj) in self.__objects:
            _seen = True
        if not _seen:
            if isinstance(obj, point.Point):
                _x, _y = obj.getCoords()
                _seen = (self.__points.find(_x, _y) is not None)
            elif isinstance(obj, segment.Segment):
                _p1, _p2 = obj.getEndpoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _seen = (self.__segments.find(_x1, _y1, _x2, _y2) is not None)
            elif isinstance(obj, arc.Arc):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _sa = obj.getStartAngle()
                _ea = obj.getEndAngle()
                _seen = (self.__arcs.find(_x, _y, _r, _sa, _ea) is not None)
            elif isinstance(obj, circle.Circle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _seen = (self.__circles.find(_x, _y, _r) is not None)
            elif isinstance(obj, hcline.HCLine):
                _y = obj.getLocation().y
                _seen = (self.__hclines.find(_y) is not None)
            elif isinstance(obj, vcline.VCLine):
                _x = obj.getLocation().x
                _seen = (self.__vclines.find(_x) is not None)
            elif isinstance(obj, acline.ACLine):
                _x, _y = obj.getLocation().getCoords()
                _angle = obj.getAngle()
                _seen = (self.__aclines.find(_x, _y, _angle) is not None)
            elif isinstance(obj, cline.CLine):
                _p1, _p2 = obj.getKeypoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _seen = (self.__clines.find(_x1, _y1, _x2, _y2) is not None)
            elif isinstance(obj, ccircle.CCircle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _seen = (self.__ccircles.find(_x, _y, _r) is not None)
            elif isinstance(obj, segjoint.Fillet):
                _seen = obj in self.__fillets
            elif isinstance(obj, segjoint.Chamfer):
                _seen = obj in self.__chamfers
            elif isinstance(obj, leader.Leader):
                _p1, _p2, _p3 = obj.getPoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _x3, _y3 = _p3.getCoords()
                _seen = (self.__leaders.find(_x1, _y1, _x2, _y2,
                                             _x3, _y3) is not None)
            elif isinstance(obj, polyline.Polyline):
                _coords = []
                for _pt in obj.getPoints():
                    _coords.extend(_pt.getCoords())
                _seen = (self.__polylines.find(_coords) is not None)
            elif isinstance(obj, text.TextBlock):
                _seen = obj in self.__textblocks
            elif isinstance(obj, dimension.HorizontalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (self.__hdims.find(_l1, _p1, _l2, _p2) is not None)
            elif isinstance(obj, dimension.VerticalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (self.__vdims.find(_l1, _p1, _l2, _p2) is not None)
            elif isinstance(obj, dimension.LinearDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (self.__ldims.find(_l1, _p1, _l2, _p2) is not None)
            elif isinstance(obj, dimension.RadialDimension):
                _l1 = obj.getDimLayer()
                _c1 = obj.getDimCircles()
                _seen = (self.__rdims.find(_l1, _c1) is not None)
            elif isinstance(obj, dimension.AngularDimension):
                _vl, _l1, _l2 = obj.getDimLayers()
                _vp, _p1, _p2 = obj.getDimPoints()
                _dim = self.__adims.find(_vl, _vp, _l1, _p1, _l2, _p2)
                _seen = _dim is not None
            else:
                raise TypeError, "Invalid type for in operation: " + `obj`
        return _seen

    def clear(self):
        """Remove all the entities stored in this layer

clear()
        """
        if self.isLocked():
            raise RuntimeError, "Clearing layer not allowed - layer locked."
        for _obj in self.__adims.getObjects():
            self.delObject(_obj)
        for _obj in self.__rdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__vdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__hdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__ldims.getObjects():
            self.delObject(_obj)
        for _obj in self.__textblocks:
            self.delObject(_obj)
        for _obj in self.__polylines.getObjects():
            self.delObject(_obj)
        for _obj in self.__leaders.getObjects():
            self.delObject(_obj)
        for _obj in self.__chamfers:
            self.delObject(_obj)
        for _obj in self.__fillets:
            self.delObject(_obj)
        for _obj in self.__ccircles.getObjects():
            self.delObject(_obj)
        for _obj in self.__clines.getObjects():
            self.delObject(_obj)
        for _obj in self.__aclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__vclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__hclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__arcs.getObjects():
            self.delObject(_obj)
        for _obj in self.__circles.getObjects():
            self.delObject(_obj)
        for _obj in self.__segments.getObjects():
            self.delObject(_obj)
        for _obj in self.__points.getObjects():
            self.delObject(_obj)
        self.setScale(1.0)

    def free(self):
        """Disconnect a layer from its parent.

free()
        """
        warnings.warn("free() is deprecated - use setParent(None)",
                      DeprecationWarning, stacklevel=2)
        self.setParent(None)

    def getName(self):
        """Return the name of the Layer.

getName()
        """
        return self.__name

    def setName(self, name):
        """Set the name of the Layer.

setName(name)

The new must be a string, and cannot be None.
        """
        _n = name
        if _n is None:
            raise ValueError, "Layers must have a name."
        if not isinstance(_n, unicode):
            if isinstance(_n, str):
                _n = unicode(_n)
            else:
                raise TypeError, "Invalid name: " + `_n`
        _on = self.__name
        if _on != _n:
            self.__name = _n
            self.sendMessage('attribute_changed', 'name', _on)
            self.modified()

    name = property(getName, setName, None, "Layer name.")


    def addObject(self, obj):
        """Add an object to this Layer.

addObject(obj)

The object should be a Point, Segment, Arc, Circle,
HCLine, VCLine, ACLine, CLine, CCircle, TextBlock, Chamfer,
Fillet, Leader, Polyline, or Dimension. Anything else raises
a TypeError exception.
        """
        if self.isLocked():
            raise RuntimeError, "Adding entity not allowed - layer locked."
        if id(obj) in self.__objects:
            return
        if isinstance(obj, point.Point):
            _res = self._addPoint(obj)
        elif isinstance(obj, segment.Segment):
            _res = self._addSegment(obj)
        elif isinstance(obj, arc.Arc):
            _res = self._addArc(obj)
        elif isinstance(obj, circle.Circle):
            _res = self._addCircle(obj)
        elif isinstance(obj, hcline.HCLine):
            _res = self._addHCLine(obj)
        elif isinstance(obj, vcline.VCLine):
            _res = self._addVCLine(obj)
        elif isinstance(obj, acline.ACLine):
            _res = self._addACLine(obj)
        elif isinstance(obj, ccircle.CCircle):
            _res = self._addCCircle(obj)
        elif isinstance(obj, cline.CLine):
            _res = self._addCLine(obj)
        elif isinstance(obj, segjoint.Chamfer):
            _res = self._addChamfer(obj)
        elif isinstance(obj, segjoint.Fillet):
            _res = self._addFillet(obj)
        elif isinstance(obj, leader.Leader):
            _res = self._addLeader(obj)
        elif isinstance(obj, polyline.Polyline):
            _res = self._addPolyline(obj)
        elif isinstance(obj, text.TextBlock):
            _res = self._addTextBlock(obj)
        elif isinstance(obj, dimension.AngularDimension):
            _res = self._addAngularDimension(obj)
        elif isinstance(obj, dimension.RadialDimension):
            _res = self._addRadialDimension(obj)
        elif isinstance(obj, dimension.HorizontalDimension):
            _res = self._addHorizontalDimension(obj)
        elif isinstance(obj, dimension.VerticalDimension):
            _res = self._addVerticalDimension(obj)
        elif isinstance(obj, dimension.LinearDimension):
            _res = self._addLinearDimension(obj)
        else:
            raise TypeError, "Invalid object for storage: " + `obj`
        if _res:
            #
            # call setParent() before connecting to layer log (if
            # it exists) so that the log will not recieve a 'modified'
            # message ...
            #
            obj.setParent(self)
            self.__objects[id(obj)] = obj
            _oid = obj.getID()
            self.__objids[_oid] = obj
            _log = obj.getLog()
            if _log is not None: # make this an error?
                # print "obj has log ..."
                _oldlog = self.__logs.get(_oid)
                if _oldlog is not None: # re-attach old log
                    # print "old log exists ..."
                    _log.transferData(_oldlog)
                    del self.__logs[_oid]
            _log = self.getLog()
            if _log is not None: # make this an error?
                obj.connect('modified', _log, LayerLog.modObj)
            _parent = self.getParent()
            if _parent is not None:
                _parent.sendMessage('added_object', self, obj)

    def _addPoint(self, p):
        """Add a Point object to the Layer.

_addPoint(p)

This method is private to the Layer object.
        """
        _flag = False
        _x, _y = p.getCoords()
        if self.__points.find(_x, _y) is None:
            self.__points.addObject(p)
            if p.getLog() is None:
                _log = point.PointLog(p)
                p.setLog(_log)
            _flag = True
        return _flag

    def _addSegment(self, s):
        """Add a Segment object to the Layer.

_addSegment(s)

The Segment object "s" is added to the Layer if there is not
already a Segment in the layer between the same locations.
The Segment endpoints p1 and p2 _must_ be already stored in
this layer, otherwise a ValueError is raised.

This method is private to the Layer object.
        """
        _flag = False
        _p1, _p2 = s.getEndpoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "Segment p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "Segment p2 Point not found in Layer."
        _x1, _y1 = _p1.getCoords()
        _x2, _y2 = _p2.getCoords()
        if self.__segments.find(_x1, _y1, _x2, _y2) is None:
            self.__segments.addObject(s)
            if s.getLog() is None:
                _log = segment.SegmentLog(s)
                s.setLog(_log)
            _flag = True
        else:
            _p1.freeUser(s)
            _p2.freeUser(s)
        return _flag

    def _addCircle(self, c):
        """Add a Circle object to the Layer.

_addCircle(c)

The Circle object "c" is added to the Layer if there is not
already a Circle at that location with the same radius. The
Circle center must already be stored in the Layer, otherwise
a ValueError is raised.

This method is private to the layer object.
        """
        _flag = False
        _cp = c.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "Circle center Point not found in Layer."
        _x, _y = _cp.getCoords()
        _r = c.getRadius()
        if self.__circles.find(_x, _y, _r) is None:
            self.__circles.addObject(c)
            if c.getLog() is None:
                _log = circle.CircleLog(c)
                c.setLog(_log)
            _flag = True
        else:
            _cp.freeUser(c)
        return _flag

    def _addArc(self, a):
        """Add an Arc object to the Layer.

_addArc(a)

The Arc object "a" is added to the Layer if there is not
already a Arc at that location with the same radius, start
angle, and eng_angle. The Arc center must already be stored
in the Layer, otherwise a ValueError is raised.

This method is private to the Layer object.
        """
        _flag = False
        _cp = a.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "Arc center Point not found in Layer."
        _x, _y = _cp.getCoords()
        _r = a.getRadius()
        _sa = a.getStartAngle()
        _ea = a.getEndAngle()
        if self.__arcs.find(_x, _y, _r, _sa, _ea) is None:
            self.__arcs.addObject(a)
            if a.getLog() is None:
                _log = arc.ArcLog(a)
                a.setLog(_log)
            _flag = True
            for _ex, _ey in a.getEndpoints():
                _lp = self.__points.find(_ex, _ey)
                if _lp is None:
                    _lp = point.Point(_ex, _ey)
                    self.addObject(_lp)
                _lp.storeUser(a)
        else:
            _cp.freeUser(a)
            for _ex, _ey in a.getEndpoints():
                _lp = self.__points.find(_ex, _ey)
                if _lp is not None:
                    _lp.freeUser(a)
        return _flag

    def _addHCLine(self, hcl):
        """Add an HCLine object to the Layer.

_addHCLine(hcl)

The HCLine object "hcl" is added to the Layer if there is not
already a HCLine at that location. The HCLine location point
must already be stored in the Layer, otherwise a ValueError is
raised.

This method is private to the Layer object.
        """
        _flag = False
        _lp = hcl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "HCLine location Point not found in Layer."
        if self.__hclines.find(_lp.y) is None:
            self.__hclines.addObject(hcl)
            if hcl.getLog() is None:
                _log = hcline.HCLineLog(hcl)
                hcl.setLog(_log)
            _flag = True
        else:
            _lp.freeUser(hcl)
        return _flag

    def _addVCLine(self, vcl):
        """Add an VCLine object to the Layer.

_addVCLine(vcl)

The VCLine object "vcl" is added to the Layer if there is not
already a VCLine at that location. The VCLine location point
must already be stored in the Layer, otherwise a ValueError is
raised.

This method is private to the Layer object.
        """
        _flag = False
        _lp = vcl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "VCLine location Point not found in Layer."
        if self.__vclines.find(_lp.x) is None:
            self.__vclines.addObject(vcl)
            if vcl.getLog() is None:
                _log = vcline.VCLineLog(vcl)
                vcl.setLog(_log)
            _flag = True
        else:
            _lp.freeUser(vcl)
        return _flag

    def _addACLine(self, acl):
        """Add an ACLine object to the Layer.

_addACLine(acl)

The ACLine object "acl" is added to the Layer if there is not
already a ACLine at that location. The ACLine location point
must already be stored in the Layer, otherwise a ValueError is
raised.

This method is private to the Layer object.
        """
        _flag = False
        _lp = acl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "ACLine location Point not found in Layer."
        _x, _y = _lp.getCoords()
        _angle = acl.getAngle()
        if self.__aclines.find(_x, _y, _angle) is None:
            self.__aclines.addObject(acl)
            if acl.getLog() is None:
                _log = acline.ACLineLog(acl)
                acl.setLog(_log)
            _flag = True
        else:
            _lp.freeUser(acl)
        return _flag

    def _addCCircle(self, cc):
        """Add an CCircle object to the Layer.

_addCCircle(cc)

The CCircle object "cc" is added to the Layer if there is not
already a CCircle at that location and with the same radius.
The CCircle center must already be stored in the Layer, otherwise
a ValueError is raised.

This method is private to the Layer object.
        """
        _flag = False
        _cp = cc.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "CCircle center Point not found in Layer."
        _x, _y = _cp.getCoords()
        _r = cc.getRadius()
        if self.__circles.find(_x, _y, _r) is None:
            self.__ccircles.addObject(cc)
            if cc.getLog() is None:
                _log = ccircle.CCircleLog(cc)
                cc.setLog(_log)
            _flag = True
        else:
            _cp.freeUser(cc)
        return _flag

    def _addCLine(self, cl):
        """Add an CLine object to the Layer.

_addCLine(cl)

The CLine object "cl" is added to the Layer if there is not
already a CLine at that location. The CLine location point
must already be stored in the Layer, otherwise a ValueError is
raised.

This method is private to the Layer object.
        """
        _flag = False
        _p1, _p2 = cl.getKeypoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "CLine p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "CLine p2 Point not found in Layer."
        _x1, _y1 = _p1.getCoords()
        _x2, _y2 = _p2.getCoords()
        if self.__clines.find(_x1, _y1, _x2, _y2) is None:
            self.__clines.addObject(cl)
            if cl.getLog() is None:
                _log = cline.CLineLog(cl)
                cl.setLog(_log)
            _flag = True
        else:
            _p1.freeUser(cl)
            _p2.freeUser(cl)
        return _flag

    def _addChamfer(self, ch):
        """Add a Chamfer object to the Layer.

_addChamfer(ch)

The Chamfer object "ch" is added to the Layer if there is not
already a Chamfer found joining the two Segments. Both Segment
objects in the chamfer must also be stored in this Layer.

This method is private to the Layer object.
        """
        _flag = False
        _s1, _s2 = ch.getSegments()
        if ch in self.__chamfers:
            _s1.freeUser(ch)
            _s2.freeUser(ch)
        else:
            if id(_s1) not in self.__objects:
                raise ValueError, "Chamfer s1 Segment not found in Layer."
            if id(_s2) not in self.__objects:
                raise ValueError, "Chamfer s2 Segment not found in Layer."
            _new_chamfer = True
            for _ch in self.__chamfers:
                if _ch == ch:
                    _new_chamfer = False
                    break
            if _new_chamfer:
                self.__chamfers.append(ch)
                if ch.getLog() is None:
                    _log = segjoint.ChamferLog(ch)
                    ch.setLog(_log)
                _flag = True
            else:
                _s1.freeUser(ch)
                _s2.freeUser(ch)
        return _flag

    def _addFillet(self, f):
        """Add a Fillet object to the Layer.

_addFillet(f)

The Fillet object "f" is added to the Layer if there is not
already a Fillet found joining the two Segments. Both Segment
objects in the fillet must also be stored in this Layer.

This method is private to the Layer object.
        """
        _flag = False
        _s1, _s2 = f.getSegments()
        if f in self.__fillets:
            _s1.freeUser(f)
            _s2.freeUser(f)
        else:
            if id(_s1) not in self.__objects:
                raise ValueError, "Fillet s1 Segment not found in Layer."
            if id(_s2) not in self.__objects:
                raise ValueError, "Fillet s2 Segment not found in Layer."
            _new_fillet = True
            for _f in self.__fillets:
                if _f == f:
                    _new_fillet = False
                    break
            if _new_fillet:
                self.__fillets.append(f)
                if f.getLog() is None:
                    _log = segjoint.FilletLog(f)
                    f.setLog(_log)
                _flag = True
            else:
                _s1.freeUser(f)
                _s2.freeUser(f)
        return _flag

    def _addLeader(self, l):
        """Add a Leader object to the Layer.

_addLeader(l)

The Leader object "l" is added to the Layer if there is not
already a Leader in the layer between the same locations.
The Leader endpoints p1, p2, and p3 _must_ be already stored in
this layer, otherwise a ValueError is raised.

This method is private to the Layer object.
        """
        _flag = False
        _p1, _p2, _p3 = l.getPoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "Leader p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "Leader p2 Point not found in Layer."
        if id(_p3) not in self.__objects:
            raise ValueError, "Leader p3 Point not found in Layer."
        _x1, _y1 = _p1.getCoords()
        _x2, _y2 = _p2.getCoords()
        _x3, _y3 = _p3.getCoords()
        if self.__leaders.find(_x1, _y1, _x2, _y2, _x3, _y3) is None:
            self.__leaders.addObject(l)
            if l.getLog() is None:
                _log = leader.LeaderLog(l)
                l.setLog(_log)
            _flag = True
        else:
            _p1.freeUser(l)
            _p2.freeUser(l)
            _p3.freeUser(l)
        return _flag

    def _addPolyline(self, pl):
        """Add a Polyline object to the Layer.

_addPolyline(pl)

The Polyline object "pl" is added to the Layer if there is not
already a Polyline in the layer at the same locations. The Polyline
points _must_ be already stored in this layer, otherwise a ValueError
is raised.

This method is private to the Layer object.
        """
        _flag = False
        _coords = []
        _pts = pl.getPoints()
        for _pt in _pts:
            if id(_pt) not in self.__objects:
                raise ValueError, "Polyline point not in layer: " + str(_pt)
            _coords.append(_pt.getCoords())
        if self.__polylines.find(_coords) is None:
            self.__polylines.addObject(pl)
            if pl.getLog() is None:
                _log = polyline.PolylineLog(pl)
                pl.setLog(_log)
            _flag = True
        else:
            for _pt in _pts:
                _pt.freeUser(pl)
        return _flag

    def _addTextBlock(self, tb):
        """Add a TextBlock object to the Layer.

_addTextBlock(tb)

The TextBlock object "tb" is added to the layer if there is not
already a TextBlock in the layer at the same location and with the
same text.
        """
        _flag = False
        if tb not in self.__textblocks:
            self.__textblocks.append(tb)
            _flag = True
        return _flag

    def _addAngularDimension(self, adim):
        """Add an AngularDimension object to the Layer.

_addAngularDimension(adim)

This method is private to the Layer object.
        """
        _flag = False
        _p1, _p2, _p3 = adim.getDimPoints()
        _l1, _l2, _l3 = adim.getDimLayers()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "Dimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "Dimension Point p2 not found in layer!"
        _lp = _l3.findObject(_p3)
        if _lp is not _p3:
            raise ValueError, "Dimension Point p3 not found in layer!"
        if self.__adims.find(_l1, _p1, _l2, _p2, _l3, _p3) is None:
            self.__adims.addObject(adim)
            _flag = True
        else:
            _p1.freeUser(adim)
            _p2.freeUser(adim)
            _p3.freeUser(adim)
        return _flag

    def _addRadialDimension(self, rdim):
        """Add a RadialDimension object to the Layer.

_addRadialDimension(rdim)

This method is private to the Layer object.
        """
        _flag = False
        _dc = rdim.getDimCircle()
        _dl = rdim.getDimLayer()
        _lc = _dl.findObject(_dc)
        if _lc is not _dc:
            raise ValueError, "RadialDimension circular object not found in layer"
        if self.__rdims.find(_dl, _dc) is None:
            self.__rdims.addObject(rdim)
            _flag = True
        else:
            _dc.freeUser(rdim)
        return _flag

    def _addHorizontalDimension(self, hdim):
        """Add a HorizontalDimension object to the Layer.

_addHorizontalDimension(hdim)

This method is private to the Layer object.
        """
        _flag = False
        _l1, _l2 = hdim.getDimLayers()
        _p1, _p2 = hdim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "HorizontalDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "HorizontalDimension Point p2 not found in layer"
        if self.__hdims.find(_l1, _p1, _l1, _p2) is None:
            self.__hdims.addObject(hdim)
            _flag = True
        else:
            _p1.freeUser(hdim)
            _p2.freeUser(hdim)
        return _flag

    def _addVerticalDimension(self, vdim):
        """Add a VerticalDimension object to the Layer.

_addVerticalDimension(vdim)

This method is private to the Layer object.
        """
        _flag = False
        _l1, _l2 = vdim.getDimLayers()
        _p1, _p2 = vdim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "VerticalDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "VerticalDimension Point p2 not found in layer"
        if self.__vdims.find(_l1, _p1, _l1, _p2) is None:
            self.__vdims.addObject(vdim)
            _flag = True
        else:
            _p1.freeUser(vdim)
            _p2.freeUser(vdim)
        return _flag

    def _addLinearDimension(self, ldim):
        """Add a LinearDimension object to the Layer.

_addLinearDimension(ldim)

This method is private to the Layer object.
        """
        _flag = False
        _l1, _l2 = ldim.getDimLayers()
        _p1, _p2 = ldim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "LinearDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "LinearDimension Point p2 not found in layer"
        if self.__ldims.find(_l1, _p1, _l1, _p2) is None:
            self.__ldims.addObject(ldim)
            _flag = True
        else:
            _p1.freeUser(ldim)
            _p2.freeUser(ldim)
        return _flag

    def delObject(self, obj):
        """Remove an object from this Layer.

delObject(obj)

The object should be a Point, Segment, Arc, Circle,
HCLine, VCLine, ACLine, CLine, CCircle, Chamfer,
Fillet, Leader, or Dimension. Anything else raises
a TypeError exception.
        """
        if self.isLocked():
            raise RuntimeError, "Deleting entity not allowed - layer locked."
        if id(obj) not in self.__objects:
            raise ValueError, "Object not found in layer: " + `obj`
        if isinstance(obj, point.Point):
            self._delPoint(obj)
        elif isinstance(obj, segment.Segment):
            self._delSegment(obj)
        elif isinstance(obj, arc.Arc):
            self._delArc(obj)
        elif isinstance(obj, circle.Circle):
            self._delCircle(obj)
        elif isinstance(obj, hcline.HCLine):
            self._delHCLine(obj)
        elif isinstance(obj, vcline.VCLine):
            self._delVCLine(obj)
        elif isinstance(obj, acline.ACLine):
            self._delACLine(obj)
        elif isinstance(obj, cline.CLine):
            self._delCLine(obj)
        elif isinstance(obj, ccircle.CCircle):
            self._delCCircle(obj)
        elif isinstance(obj, segjoint.Chamfer):
            self._delChamfer(obj)
        elif isinstance(obj, segjoint.Fillet):
            self._delFillet(obj)
        elif isinstance(obj, leader.Leader):
            self._delLeader(obj)
        elif isinstance(obj, polyline.Polyline):
            self._delPolyline(obj)
        elif isinstance(obj, text.TextBlock):
            self._delTextBlock(obj)
        elif isinstance(obj, dimension.AngularDimension):
            self._delAngularDimension(obj)
        elif isinstance(obj, dimension.RadialDimension):
            self._delRadialDimension(obj)
        elif isinstance(obj, dimension.HorizontalDimension):
            self._delHorizontalDimension(obj)
        elif isinstance(obj, dimension.VerticalDimension):
            self._delVerticalDimension(obj)
        elif isinstance(obj, dimension.LinearDimension):
            self._delLinearDimension(obj)
        else:
            raise TypeError, "Invalid object for removal: " + `obj`
        _parent = self.getParent()
        if _parent is not None:
            _parent.sendMessage('deleted_object', self, obj)

    def _freeObj(self, obj):
        #
        # disconnect object before calling setParent() so that
        # the layer log will not recieve a 'modified' message
        # from the object ...
        #
        del self.__objects[id(obj)]
        _oid = obj.getID()
        del self.__objids[_oid]
        _log = obj.getLog()
        if _log is not None: # store the object's log
            _log.detatch()
            self.__logs[_oid] = _log
            obj.setLog(None)
        _log = self.getLog()        
        if _log is not None:
            obj.disconnect(_log)
        obj.setParent(None)
        
    def _delPoint(self, p):
        """Delete a Point from the Layer.

_delPoint(p)

This method is private to the Layer object.
        """
        _delete = True
        _users = p.getUsers()
        for _uref in _users:
            _user = _uref()
            if _user is not None:
                if not isinstance(_user, dimension.Dimension):
                    _delete = False
                    break
        if _delete:
            _extdims = {}
            for _uref in _users:
                _user = _uref()
                if _user is not None:
                    _uid = id(_user)
                    if isinstance(_user, dimension.Dimension):
                        if _uid not in self.__objects:
                            _extdims[_uid] = _user
                    else:
                        if _uid not in self.__objects:
                            print "point bound to non-layer object: " + `_user`
                            _delete = False
                            break
            if _delete:
                for _uref in _users:
                    _user = _uref()
                    if _user is not None:
                        if id(_user) not in _extdims:
                            self.delObject(_user)
                if len(_extdims):
                    _parent = self.getParent()
                    _top = self
                    while _parent is not None:
                        _top = _parent
                        _parent = _top.getParent()
                    _layers = []
                    _layers.append(_top)
                    while len(_layers):
                        _layer = _layers.pop(0)
                        _dimids = _extdims.keys()
                        for _dimid in _dimids:
                            _dim = _extdims[_dimid]
                            if _dim in _layer:
                                del _extdims[_dimid]
                                _layer.delObject(_dim)
                        if len(_extdims):
                            _layers.extend(_layer.getSublayers())
                self.__points.delObject(p)
                self._freeObj(p)

    def _delSegment(self, s):
        """Delete a Segment from the Layer.

_delSegment(s)

This method is private to the Layer object.
        """
        for _uref in s.getUsers(): # chamfers, fillets, or hatching
            _user = _uref()
            if _user is not None:
                self.delObject(_user) # restore other segments?
        _p1, _p2 = s.getEndpoints()
        assert id(_p1) in self.__objects, "Segment p1 Point not in objects"
        _p1.freeUser(s)
        assert id(_p2) in self.__objects, "Segment p2 Point not in objects"
        _p2.freeUser(s)
        self.__segments.delObject(s)
        self._freeObj(s)
        if not self.inUndo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2

    def _delCircle(self, c):
        """Delete a Circle from the Layer.

_delCircle(c)

This method is private to the Layer object.
        """
        assert not isinstance(c, arc.Arc), "Arc in _delCircle()"
        _extdims = {}
        for _uref in c.getUsers(): # dimensions or hatching
            _user = _uref()
            if _user is not None:
                _uid = id(_user)
                if isinstance(_user, dimension.RadialDimension):
                    if _uid not in self.__objects:
                        _extdims[_uid] = _user
                    else:
                        self.delObject(_user)
        if len(_extdims):
            _parent = self.getParent()
            _top = self
            while _parent is not None:
                _top = _parent
                _parent = _top.getParent()
            _layers = []
            _layers.append(_top)
            while len(_layers):
                _layer = _layers.pop(0)
                _dimids = _extdims.keys()
                for _dimid in _dimids:
                    _dim = _extdims[_dimid]
                    if _dim in _layer:
                        del _extdims[_dimid]
                        _layer.delObject(_dim)
                if len(_extdims):
                    _layers.extend(_layer.getSublayers())
        _cp = c.getCenter()
        assert id(_cp) in self.__objects, "Circle center point not in objects"
        _cp.freeUser(c)
        self.__circles.delObject(c)
        self._freeObj(c)
        if not self.inUndo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delArc(self, a):
        """Delete an Arc from the Layer.

_delArc(a)

This method is private to the Layer object.
        """
        _extdims = {}
        for _uref in a.getUsers(): # dimensions or hatching
            _user = _uref()
            if _user is not None:
                _uid = id(_user)
                if isinstance(_user, dimension.RadialDimension):
                    if _uid not in self.__objects:
                        _extdims[_uid] = _user
                    else:
                        self.delObject(_user)
        if len(_extdims):
            _parent = self.getParent()
            _top = self
            while _parent is not None:
                _top = _parent
                _parent = _top.getParent()
            _layers = []
            _layers.append(_top)
            while len(_layers):
                _layer = _layers.pop(0)
                _dimids = _extdims.keys()
                for _dimid in _dimids:
                    _dim = _extdims[_dimid]
                    if _dim in _layer:
                        del _extdims[_dimid]
                        _layer.delObject(_dim)
                if len(_extdims):
                    _layers.extend(_layer.getSublayers())
        _cp = a.getCenter()
        assert id(_cp) in self.__objects, "Arc center point not in objects"
        _cp.freeUser(a)
        self.__arcs.delObject(a)
        self._freeObj(a)
        for _ep in a.getEndpoints():
            _p = self.find('point', _ep[0], _ep[1])
            assert _p is not None, "Arc endpoint not found in layer"
            assert id(_p) in self.__objects, "Arc endpoint not in objects"
            _p.freeUser(a)
            if not self.inUndo():
                self.delObject(_p) # remove possibly unused point _p
        if not self.inUndo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delHCLine(self, hcl):
        """Remove a HCLine object from the Layer.

_delHCLine(hcl)

This method is private to the Layer object.
        """
        _lp = hcl.getLocation()
        assert id(_lp) in self.__objects, "HCLine point not in objects"
        _lp.freeUser(hcl)
        self.__hclines.delObject(hcl)
        self._freeObj(hcl)
        if not self.inUndo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delVCLine(self, vcl):
        """Remove a VCLine object from the Layer.

_delVCLine(vcl)

This method is private to the Layer object.
        """
        _lp = vcl.getLocation()
        assert id(_lp) in self.__objects, "VCLine point not in objects"
        _lp.freeUser(vcl)
        self.__vclines.delObject(vcl)
        self._freeObj(vcl)
        if not self.inUndo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delACLine(self, acl):
        """Remove an ACLine object from the Layer.

_delACLine(acl)

This method is private to the Layer object.
        """
        _lp = acl.getLocation()
        assert id(_lp) in self.__objects, "ACLine point not in objects"
        _lp.freeUser(acl)
        self.__aclines.delObject(acl)
        self._freeObj(acl)
        if not self.inUndo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delCLine(self, cl):
        """Delete a CLine from the Layer.

_delCLine(cl)

This method is private to the Layer object.
        """
        _p1, _p2 = cl.getKeypoints()
        assert id(_p1) in self.__objects, "CLine point p1 not in objects"
        _p1.freeUser(cl)
        assert id(_p2) in self.__objects, "CLine point p2 not in objects"
        _p2.freeUser(cl)
        self.__clines.delObject(cl)
        self._freeObj(cl)
        if not self.inUndo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2

    def _delCCircle(self, cc):
        """Delete a CCircle from the Layer.

_delCCircle(cc)

This method is private to the Layer object.
        """
        _cp = cc.getCenter()
        assert id(_cp) in self.__objects, "CCircle center point not in objects"
        _cp.freeUser(cc)
        self.__ccircles.delObject(cc)
        self._freeObj(cc)
        if not self.inUndo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delChamfer(self, ch):
        """Remove a Chamfer from the Layer.

_delChamfer(ch)

This method is private to the Layer.
        """
        _chamfers = self.__chamfers
        _idx = None
        for _i in range(len(_chamfers)):
            if ch is _chamfers[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost chamfer from list"
        for _uref in ch.getUsers(): # could be hatching ...
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _s1, _s2 = ch.getSegments()
        assert id(_s1) in self.__objects, "Chamfer s1 segment not in objects"
        _s1.freeUser(ch)
        assert id(_s2) in self.__objects, "Chamfer s2 segment not in objects"
        _s2.freeUser(ch)
        del _chamfers[_idx] # restore the things the chamfer connects?
        self._freeObj(ch)

    def _delFillet(self, f):
        """Remove a Fillet from the Layer.

_delFillet(f)

This method is private to the Layer.
        """
        _fillets = self.__fillets
        _idx = None
        for _i in range(len(_fillets)):
            if f is _fillets[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost fillet from list"
        for _uref in f.getUsers(): # could be hatching ...
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _s1, _s2 = f.getSegments()
        assert id(_s1) in self.__objects, "Fillet s1 segment not in objects"
        _s1.freeUser(f)
        assert id(_s2) in self.__objects, "Fillet s2 segment not in objects"
        _s2.freeUser(f)
        del _fillets[_idx] # restore the things the fillet connects?
        self._freeObj(f)

    def _delLeader(self, l):
        """Delete a Leader from the Layer.

_delLeader(l)

This method is private to the Layer object.
        """
        _p1, _p2, _p3 = l.getPoints()
        assert id(_p1) in self.__objects, "Leader p1 Point not in objects"
        _p1.freeUser(l)
        assert id(_p2) in self.__objects, "Leader p2 Point not in objects"
        _p2.freeUser(l)
        assert id(_p3) in self.__objects, "Leader p3 Point not in objects"
        _p3.freeUser(l)
        self.__leaders.delObject(l)
        self._freeObj(l)
        if not self.inUndo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2
            self.delObject(_p3) # remove possibly unused point _p3

    def _delPolyline(self, pl):
        """Delete a Polyline from the Layer.

_delPolyline(pl)

This method is private to the Layer object.
        """
        for _uref in pl.getUsers(): # could be hatching
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _pts = pl.getPoints()
        for _pt in _pts:
            assert id(_pt) in self.__objects, "Polyline point not in objects"
            _pt.freeUser(pl)
        self.__polylines.delObject(pl)
        self._freeObj(pl)
        if not self.inUndo():
            for _pt in _pts:
                self.delObject(_pt) # remove possibly unused point _pt

    def _delTextBlock(self, tb):
        """Delete a TextBlock from the Layer.

_delTextBlock(tb)

This method is private to the Layer object.
        """
        _tbs = self.__textblocks
        _idx = None
        for _i in range(len(_tbs)):
            if tb is _tbs[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost textblock in list"
        del _tbs[_idx]
        self._freeObj(tb)

    def _delAngularDimension(self, adim):
        """Delete an AngularDimension from the Layer.

_delAngularDimension(adim)

This method is private to the Layer object.
        """
        _l1, _l2, _l3 = adim.getDimLayers()
        _p1, _p2, _p3 = adim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "ADim p1 not in objects"
        _p1.freeUser(adim)
        if _l2 is self:
            assert id(_p2) in self.__objects, "ADim p2 not in objects"
        _p2.freeUser(adim)
        if _l3 is self:
            assert id(_p3) in self.__objects, "ADim p3 not in objects"
        _p3.freeUser(adim)
        self.__adims.delObject(adim)
        self._freeObj(adim)

    def _delRadialDimension(self, rdim):
        """Delete a RadialDimension from the Layer.

_delRadialDimension(rdim)

This method is private to the Layer object.
        """
        _layer = rdim.getDimLayer()
        _circ = rdim.getDimCircle()
        if _layer is self:
            assert id(_circ) in self.__objects, "RDim circle not in objects"
        _circ.freeUser(rdim)
        self.__rdims.delObject(rdim)
        self._freeObj(rdim)

    def _delHorizontalDimension(self, hdim):
        """Delete an HorizontalDimension from the Layer.

_delHorizontalDimension(hdim)

This method is private to the Layer object.
        """
        _l1, _l2 = hdim.getDimLayers()
        _p1, _p2 = hdim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "HDim P1 not in objects"
        _p1.freeUser(hdim)
        if _l2 is self:
            assert id(_p2) in self.__objects, "HDim P2 not in objects"
        _p2.freeUser(hdim)
        self.__hdims.delObject(hdim)
        self._freeObj(hdim)

    def _delVerticalDimension(self, vdim):
        """Delete an VerticalDimension from the Layer.

_delVerticalDimension(vdim)

This method is private to the Layer object.
        """
        _l1, _l2 = vdim.getDimLayers()
        _p1, _p2 = vdim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "VDim P1 not in objects"
        _p1.freeUser(vdim)
        if _l2 is self:
            assert id(_p2) in self.__objects, "VDim P2 not in objects"
        _p2.freeUser(vdim)
        self.__vdims.delObject(vdim)
        self._freeObj(vdim)

    def _delLinearDimension(self, ldim):
        """Delete an LinearDimension from the Layer.

_delLinearDimension(ldim)

This method is private to the Layer object.
        """
        _l1, _l2 = ldim.getDimLayers()
        _p1, _p2 = ldim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "LDim P1 not in objects"
        _p1.freeUser(ldim)
        if _l2 is self:
            assert id(_p2) in self.__objects, "LDim P2 not in objects"
        _p2.freeUser(ldim)
        self.__ldims.delObject(ldim)
        self._freeObj(ldim)

    def getObject(self, eid):
        """Return an object of with a specified entity ID.

getObject(eid)

Argument eid is an entity ID.
        """
        return self.__objids.get(eid)

    def hasObject(self, eid):
        """

hasObject(eid)

Argument eid is an entity ID.
        """
        return eid in self.__objids

    def findObject(self, obj):
        """Return an object in the layer that is equivalent to a test object.

findObject(obj)

This method returns None if a suitable object is not found.
        """
        _retobj = None
        if id(obj) in self.__objects:
            _retobj = obj
        else:
            _objlist = None
            if isinstance(obj, point.Point):
                _x, _y = obj.getCoords()
                _retobj = self.__points.find(_x, _y)
            elif isinstance(obj, segment.Segment):
                _p1, _p2 = obj.getEndpoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _retobj = self.__segments.find(_x1, _y1, _x2, _y2)
            elif isinstance(obj, arc.Arc):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _sa = obj.getStartAngle()
                _ea = obj.getEndAngle()
                _retobj = self.__arcs.find(_x, _y, _r, _sa, _ea)
            elif isinstance(obj, circle.Circle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _retobj = self.__circles.find(_x, _y, _r)
            elif isinstance(obj, hcline.HCLine):
                _y = obj.getLocation().y
                _retobj = self.__hclines.find(_y)
            elif isinstance(obj, vcline.VCLine):
                _x = obj.getLocation().x
                _retobj = self.__vclines.find(_x)
            elif isinstance(obj, acline.ACLine):
                _x, _y = obj.getLocation().getCoords()
                _angle = obj.getAngle()
                _retobj = self.__aclines.find(_x, _y, _angle)
            elif isinstance(obj, cline.CLine):
                _p1, _p2 = obj.getKeypoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _retobj = self.__clines.find(_x1, _y1, _x2, _y2)
            elif isinstance(obj, ccircle.CCircle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _retobj = self.__ccircles.find(_x, _y, _r)
            elif isinstance(obj, segjoint.Fillet):
                _objlist = self.__fillets
            elif isinstance(obj, segjoint.Chamfer):
                _objlist = self.__chamfers
            elif isinstance(obj, leader.Leader):
                _p1, _p2, _p3 = obj.getPoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _x3, _y3 = _p3.getCoords()
                _retobj = self.__leaders.find(_x1, _y1, _x2, _y2, _x3, _y3)
            elif isinstance(obj, polyline.Polyline):
                _coords = []
                for _pt in obj.getPoints():
                    _coords.append(_pt.getCoords())
                _retobj = self.__polylines.find(_coords)
            elif isinstance(obj, text.TextBlock):
                _objlist = self.__textblocks
            elif isinstance(obj, dimension.HorizontalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _retobj = self.__hdims.find(_l1, _p1, _l2, _p2)
            elif isinstance(obj, dimension.VerticalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _retobj = self.__hdims.find(_l1, _p1, _l2, _p2)
            elif isinstance(obj, dimension.LinearDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _retobj = self.__hdims.find(_l1, _p1, _l2, _p2)
            elif isinstance(obj, dimension.RadialDimension):
                _l1 = obj.getDimLayer()
                _c1 = obj.getDimCircle()
                _retobj = self.__rdims.find(_l1, _c1)
            elif isinstance(obj, dimension.AngularDimension):
                _vl, _l1, _l2 = obj.getDimLayers()
                _vp, _p1, _p2 = obj.getDimPoints()
                _retobj = self.__hdims.find(_vl, _vp, _l1, _p1, _l2, _p2)
            else:
                raise TypeError, "Invalid type for in operation: " + `obj`
            if _objlist is not None:
                _seen = True
                try:
                    _idx = _objlist.index(obj)
                except ValueError:
                    _seen = False
                if _seen:
                    _retobj = _objlist[_idx]
        return _retobj

    def find(self, typestr, *args):
        """Find an existing entity in the drawing.

find(typestr, *args)

typestr: A string giving the type of entity to find
*args: A variable number of arguments used for searching
        """
        if not isinstance(typestr, str):
            raise TypeError, "Invalid type string: " + str(typestr)
        _obj = None
        if typestr == 'point':
            _obj = self.__points.find(*args)
        elif typestr == 'segment':
            _obj = self.__segments.find(*args)
        elif typestr == 'circle':
            _obj = self.__circles.find(*args)
        elif typestr == 'arc':
            _obj = self.__arcs.find(*args)
        elif typestr == 'hcline':
            _obj = self.__hclines.find(*args)
        elif typestr == 'vcline':
            _obj = self.__vclines.find(*args)
        elif typestr == 'acline':
            _obj = self.__aclines.find(*args)
        elif typestr == 'cline':
            _obj = self.__clines.find(*args)
        elif typestr == 'ccircle':
            _obj = self.__ccircles.find(*args)
        elif typestr == 'leader':
            _obj = self.__leaders.find(*args)
        elif typestr == 'polyline':
            _obj = self.__polylines.find(*args)
        elif typestr == 'ldim':
            _obj = self.__ldims.find(*args)
        elif typestr == 'hdim':
            _obj = self.__hdims.find(*args)
        elif typestr == 'vdim':
            _obj = self.__vdims.find(*args)
        elif typestr == 'rdim':
            _obj = self.__rdims.find(*args)
        elif typestr == 'adim':
            _obj = self.__adims.find(*args)
        else:
            raise ValueError, "Unexpected type string '%s'" % typestr
        return _obj

    def mapPoint(self, p, tol=tolerance.TOL, count=2):
        """Find a Point in the layer

mapPoint(p [,tol, count])

There is a single required argument:

p: Either a Point object or a tuple of two-floats

There are two optional arguments:

tol: A float equal or greater than 0 for distance tolerance comparisons.
count: An integer value indicating the largest number of objects to
       return. By default this value is 2.

Setting "count" to None or a negative value will result in the maximum
number of objects being unlimited.

This method tests the objects in the Layer to see if the
Point can can be mapped on to any of them. The returned list
consists of tuples in the form:

(obj, pt)

Where "obj" is the object the point was mapped to and "pt"
is the projected point on the object.
        """
        _hits = []
        _p = p
        if not isinstance(_p, point.Point):
            _p = point.Point(p)
        _t = tolerance.toltest(tol)
        _count = count
        if _count is None:
            _count = sys.maxint
        else:
            if not isinstance(_count, int):
                _count = int(count)
            if _count < 0:
                _count = sys.maxint
        if _count < 1: # bail out, but why set count to this value?
            return _hits
        _x, _y = _p.getCoords()
        _xmin = _x - _t
        _xmax = _x + _t
        _ymin = _y - _t
        _ymax = _y + _t
        #
        # scan for non-point objects first, then look at points,
        # because there will not be any way the same object can
        # be found in differnt trees/lists
        #
        for _obj in self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _lp = self.__points.find(_px, _py)
                if _lp is None:
                    _lp = point.Point(_px, _py)
                _hits.append((_obj, _lp))
                if len(_hits) == _count:
                    return _hits
        #
        # scan for point, but do not append any object that
        # has already been added to the hit list
        #
        _objs = {}
        for _obj, _pt in _hits:
            _objs[id(_obj)] = True
        _lp = self.find('point', _x, _y, _t)
        if _lp is not None:
            assert id(_lp) in self.__objects, "Point not in objects"
            for _uref in _lp.getUsers():
                _user = _uref()
                if _user is not None:
                    _uid = id(_user)
                    if _uid not in _objs:
                        _objs[_uid] = True
                        _hits.append((_user, _lp))
                        if len(_hits) == _count:
                                break
        return _hits

    def getLayerEntities(self, entity):
        """Get all of a particular type of entity in the Layer.

getLayerEntities(entity)

The argument "entity" should be one of the following:
point, segment, circle, arc, hcline, vcline, acline,
cline, ccircle, chamfer, fillet, leader, polyline,
textblock, linear_dimension, horizontal_dimenions,
vertical_dimension, radial_dimension, or angular_dimension.
        """
        if not isinstance(entity, str):
            raise TypeError, "Invalid entity type %s" % type(entity)
        if entity == "point":
            _objs = self.__points.getObjects()
        elif entity == "segment":
            _objs = self.__segments.getObjects()
        elif entity == "circle":
            _objs = self.__circles.getObjects()
        elif entity == "arc":
            _objs = self.__arcs.getObjects()
        elif entity == "hcline":
            _objs = self.__hclines.getObjects()
        elif entity == "vcline":
            _objs = self.__vclines.getObjects()
        elif entity == "acline":
            _objs = self.__aclines.getObjects()
        elif entity == "cline":
            _objs = self.__clines.getObjects()
        elif entity == "ccircle":
            _objs = self.__ccircles.getObjects()
        elif entity == "chamfer":
            _objs = self.__chamfers[:]
        elif entity == "fillet":
            _objs = self.__fillets[:]
        elif entity == "leader":
            _objs = self.__leaders.getObjects()
        elif entity == "polyline":
            _objs = self.__polylines.getObjects()
        elif entity == "text":
            _objs = self.__textblocks[:]
        elif entity == "linear_dimension":
            _objs = self.__ldims.getObjects()
        elif entity == "horizontal_dimension":
            _objs = self.__hdims.getObjects()
        elif entity == "vertical_dimension":
            _objs = self.__vdims.getObjects()
        elif entity == "radial_dimension":
            _objs = self.__rdims.getObjects()
        elif entity == "angular_dimension":
            _objs = self.__adims.getObjects()
        else:
            raise ValueError, "Invalid layer entity '%s'" % entity
        return _objs

    def addChild(self, child):
        """Add a child Layer to a Layer.

addChild(child)

There is no limit to the number of children for a Layer.
        """
        warnings.warn("addChild() is deprecated - use setParentLayer()",
                      DeprecationWarning, stacklevel=2)
        if not isinstance(child, Layer):
            raise TypeError, "Invalid child Layer: " + `child`
        child.setParent(self)

    def delChild(self, child):
        """Remove a child Layer from the Layer.

delChild(child)

The child layer will not be removed if it has children
of its own.
        """
        warnings.warn("delChild() is deprecated - use setParentLayer(None)",
                      DeprecationWarning, stacklevel=2)
        if not child.hasChildren():
            child.setParent(None)

    def canParent(self, obj):
        """Test if an Entity can be the parent of another Entity.

canParent(obj)

This method overrides the Entity::canParent() method. A layer can
be the parent of any object contained within itself.
        """
        return isinstance(obj, (point.Point, segment.Segment,
                                circle.Circle, arc.Arc,
                                leader.Leader, polyline.Polyline,
                                hcline.HCLine, vcline.VCLine,
                                acline.ACLine, cline.CLine, segjoint.SegJoint,
                                ccircle.CCircle, dimension.Dimension,
                                text.TextBlock))


    def setParentLayer(self, parent):
        """Store the parent layer of a layer within itself.

setParentLayer(layer)

Argument 'layer' must be either another Layer or None.
        """
        if parent is not None and not isinstance(parent, Layer):
            raise TypeError, "Invalid layer: " + `parent`
        _p = self.__parent_layer
        if _p is not parent:
            if _p is not None:
                _p.delSublayer(self)
            if parent is not None:
                parent.addSublayer(self)
            self.__parent_layer = parent
            self.sendMessage('reparented', _p)
            self.modified()

    def getParentLayer(self):
        return self.__parent_layer

    def addSublayer(self, l):
        if l is not None and not isinstance(l, Layer):
            raise TypeError, "Invalid layer: " + `l`
        if self.__sublayers is None:
            self.__sublayers = []
        if l in self.__sublayers:
            raise ValueError, "Layer already a sublayer: " + `l`
        self.__sublayers.append(l)
        self.sendMessage('added_sublayer', l)
        self.modified()

    def delSublayer(self, l):
        if l is not None and not isinstance(l, Layer):
            raise TypeError, "Invalid layer: " + `l`
        if self.__sublayers is None:
            raise ValueError, "Layer has no sublayers: " + `self`
        if l not in self.__sublayers:
            raise ValueError, "Layer not a sublayer: " + `l`
        self.__sublayers.remove(l)
        if len(self.__sublayers) == 0:
            self.__sublayers = None
        self.sendMessage('deleted_sublayer', l)
        self.modified()

    def hasSublayers(self):
        return self.__sublayers is not None and len(self.__sublayers) > 0

    def getSublayers(self):
        if self.__sublayers is not None:
            return self.__sublayers[:]
        return []

    def getVisibility(self):
        """Return the visibility value of the Layer.

getVisibility()
        """
        warnings.warn("getVisiblity() is deprecated - use isVisible()",
                      DeprecationWarning, stacklevel=2)
        return self.isVisible()

    def setVisibility(self, val):
        """Set the visibility of the Layer.

setVisibility(val)

The argument "val" should be either "True" or "False".
        """
        warnings.warn("setVisiblity() is deprecated - use hide() or show()",
                      DeprecationWarning, stacklevel=2)
        if val is True:
            self.show()
        elif val is False:
            self.hide()
        else:
            raise ValueError, "Invalid visiblity value: " + str(val)

    visibility = property(getVisibility, setVisibility, None, "Visibility.")

    def getScale(self):
        """Return the scale factor of the Layer.

getScale()
        """
        return self.__scale

    def setScale(self, scale):
        """Set the scale factor for the Layer.

setScale(scale)

The scale factor must be a positive float value greater than 0.0
        """
        _s = scale
        if not isinstance(_s, float):
            _s = float(scale)
        if _s < 1e-10:
            raise ValueError, "Invalid scale factor: %g" % _s
        _os = self.__scale
        if abs(_os - _s) > 1e-10:
            self.__scale = _s
            self.sendMessage('attribute_changed', 'scale', _os)
            self.modified()

    scale = property(getScale, setScale, None, "Layer scale factor.")

    def getBoundary(self):
        """Return the maximum and minimum values of the object in the Layer.

getBoundary()

The function returns a tuple holding four float values:

(xmin, ymin, xmax, _ymax)

A default value of (-1.0, -1.0, 1.0, 1.0) is returned for a Layer
containing no objects.
        """
        _xmin = None
        _ymin = None
        _xmax = None
        _ymax = None
        for _obj in self.__points.getObjects():
            _x, _y = _obj.getCoords()
            if _xmin is None or _x < _xmin:
                _xmin = _x
            if _ymin is None or _y < _ymin:
                _ymin = _y
            if _xmax is None or _x > _xmax:
                _xmax = _x
            if _ymax is None or _y > _ymax:
                _ymax = _y
        for _obj in self.__arcs.getObjects():
            _axmin, _aymin, _axmax, _aymax = _obj.getBounds()
            if _xmin is None or _axmin < _xmin:
                _xmin = _axmin
            if _ymin is None or _aymin < _ymin:
                _ymin = _aymin
            if _xmax is None or _axmax > _xmax:
                _xmax = _axmax
            if _ymax is None or _aymax > _ymax:
                _ymax = _aymax
        for _obj in self.__circles.getObjects() + self.__ccircles.getObjects():
            _x, _y = _obj.getCenter().getCoords()
            _r = _obj.getRadius()
            _val = _x - _r
            if _xmin is None or _val < _xmin:
                _xmin = _val
            _val = _y - _r
            if _ymin is None or _val < _ymin:
                _ymin = _val
            _val = _x + _r
            if _xmax is None or _val > _xmax:
                _xmax = _val
            _val = _y + _r
            if _ymax is None or _val > _ymax:
                _ymax = _val
        _dims = (self.__ldims.getObjects() +
                 self.__hdims.getObjects() +
                 self.__vdims.getObjects() +
                 self.__rdims.getObjects() +
                 self.__adims.getObjects())
        for _obj in _dims:
            _dxmin, _dymin, _dxmax, _dymax = _obj.getBounds()
            if _xmin is None or _dxmin < _xmin:
                _xmin = _dxmin
            if _ymin is None or _dymin < _ymin:
                _ymin = _dymin
            if _xmax is None or _dxmax > _xmax:
                _xmax = _dxmax
            if _ymax is None or _dymax > _ymax:
                _ymax = _dymax
        for _textblock in self.__textblocks:
            _x, _y = _textblock.getLocation() # need to get boundary of text
            if _xmin is None or _x < _xmin:
                _xmin = _x
            if _ymin is None or _y < _ymin:
                _ymin = _y
            if _xmax is None or _x > _xmax:
                _xmax = _x
            if _ymax is None or _y > _ymax:
                _ymax = _y
        if _xmin is None: _xmin = -1.0
        if _ymin is None: _ymin = -1.0
        if _xmax is None: _xmax = 1.0
        if _ymax is None: _ymax = 1.0
        return _xmin, _ymin, _xmax, _ymax

    def objsInRegion(self, xmin, ymin, xmax, ymax, fully=False):
        """Return a all the objects in the Layer visible within the bounds.

objsInRegion(xmin, ymin, xmax, ymax[, fully])

The function has four required arguments:

xmin: The minimum x-value of the region
ymin: The minimum y-value of the region
xmax: The maximum x-value of the region
ymax: The maximum y-value of the region

There is a single optional argument:

fully: A True/False value indicating if the object must be
       entirely within the region [fully=True], or can
       merely pass through [fully=False]. The default value
       is False.

The function returns a list of objects.
        """
        _xmin = xmin
        if not isinstance(_xmin, float):
            _xmin = float(xmin)
        _ymin = ymin
        if not isinstance(_ymin, float):
            _ymin = float(ymin)
        _xmax = xmax
        if not isinstance(_xmax, float):
            _xmax = float(xmax)
        if xmax < xmin:
            raise ValueError, "Value error: xmax < xmin"
        _ymax = ymax
        if not isinstance(_ymax, float):
            _ymax = float(ymax)
        if _ymax < _ymin:
            raise ValueError, "Value error: ymax < ymin"
        if fully is not True and fully is not False:
            raise ValueError, "Invalid flag: " + `fully`
        _objs = []
        _objs.extend(self.__points.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax))
        for _obj in self.__chamfers:
            if _obj.inRegion(_xmin, _ymin, _xmax, _ymax):
                _objs.append(_obj)
        _objs.extend(self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        for _obj in self.__fillets:
            if _obj.inRegion(_xmin, _ymin, _xmax, _ymax):
                _objs.append(_obj)
        _objs.extend(self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax))
        for _obj in self.__textblocks:
            _x, _y = _obj.getLocation()
            if _xmin < _x < _xmax and _ymin < _y < _ymax:
                _objs.append(_obj)
        return _objs

    def sendsMessage(self, m):
        if m in Layer.messages:
            return True
        return entity.Entity.sendsMessage(self, m)

    def update(self):
        """Check that the objects in this layer are stored correctly.

update()

This function checks that the objects held in this layer are kept
in the proper order. Also, any duplicated objects that may have
be created due to modifying entities in the layer are removed.
        """
        warnings.warn("update() is deprecated - not needed anymore",
                      DeprecationWarning, stacklevel=2)

#
# Layer history class
#

class LayerLog(logger.Logger):
    def __init__(self, l):
        if not isinstance(l, Layer):
            raise TypeError, "Invalid layer: " + `l`
        logger.Logger.__init__(self)
        self.__layer = l
        l.connect('attribute_changed', self, LayerLog.attrChanged)
        l.connect('added_child', self, LayerLog.addChild)
        l.connect('removed_child', self, LayerLog.delChild)

    def addChild(self, l, *args):
        if len(args):
            _obj = args[0]
            self.saveUndoData('add', _obj.getValues())
            # print _obj.getValues()

    def delChild(self, l, *args):
        if len(args):
            _obj = args[0]
            self.saveUndoData('del', _obj.getValues())
            # print _obj.getValues()

    def modObj(self, obj, *args):
        # print "LayerLog::modObj() ..."
        # print args
        _id = obj.getID()
        self.saveUndoData('mod', _id)
        _parent = self.__layer.getParent()
        if _parent is not None:
            if _parent.inAction():
                self.__layer.modified()
            else:
                _parent.startAction()
                try:
                    self.__layer.modified()
                finally:
                    _parent.endAction()
        else:
            self.__layer.modified()

    def attrChanged(self, l, *args):
        _alen = len(args)
        if len(args) < 2:
            raise ValueError, "Invalid argument count: %d" % _alen
        _attr = args[0]
        if not isinstance(_attr, str):
            raise TypeError, "Unexpected attribute string: " + str(_attr)
        _v = args[1]
        if _attr == 'name':
            if not isinstance(_v, unicode):
                raise TypeError, "Invalid name: " + `_v`
        elif _attr == 'scale':
            if not isinstance(_v, float):
                _v = float(args[1])
        else:
            raise ValueError, "Unexpected attribute: %s" % _attr
        self.saveUndoData('attr_changed', _attr, _v)

    def execute(self, undo, *args):
        # print "LayerLog::execute() ..."
        # print args
        if undo is not True and undo is not False:
            raise ValueError, "Invalid undo value: " + str(undo)
        _alen = len(args)
        if len(args) == 0:
            raise ValueError, "No arguments to execute()"
        _l = self.__layer
        _op = args[0]
        if _op == 'attr_changed':
            if len(args) < 3:
                raise ValueError, "Invalid argument count: %d" % _alen
            _attr = args[1]
            _val = args[2]
            if _attr == 'name':
                _sv = _l.getName()
            elif _attr == 'scale':
                _sv = _l.getScale()
            else:
                raise ValueError, "Unexpected attribute: %s" % _attr
            if undo:
                self.saveRedoData(_op, _attr, _sv)
            else:
                self.saveUndoData(_op, _attr, _sv)
            self.ignore('attribute_changed')
            try:
                if _attr == 'name':
                    _l.setName(_val)
                elif _attr == 'scale':
                    _l.setScale(_val)
                else:
                    raise ValueError, "Unexpected attribute: %s" % _attr
            finally:
                self.receive('attribute_changed')
        elif _op == 'add':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _vals = args[1]
            if not isinstance(_vals, tuple):
                raise TypeError, "Invalid tuple: " + str(_vals)
            self.ignore('modified')
            try:
                if undo:
                    self.saveRedoData(_op, _vals)
                    self.ignore('removed_child')
                    try:
                        self._delObject(True, _vals)
                    finally:
                        self.receive('removed_child')
                else:
                    _obj = self._makeObject(_vals)
                    self.ignore('added_child')
                    try:
                        _l.addObject(_obj)
                        self.saveUndoData(_op, _obj.getValues())
                    finally:
                        self.receive('added_child')
            finally:
                self.receive('modified')
        elif _op == 'del':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _vals = args[1]
            if not isinstance(_vals, tuple):
                raise TypeError, "Invalid tuple: " + str(_vals)
            self.ignore('modified')
            try:
                if undo:
                    _obj = self._makeObject(_vals)
                    self.ignore('added_child')
                    try:
                        _l.addObject(_obj)
                        self.saveRedoData(_op, _obj.getValues())
                    finally:
                        self.receive('added_child')
                else:
                    self.saveUndoData(_op, _vals)
                    self.ignore('removed_child')
                    try:
                        self._delObject(False, _vals)
                    finally:
                        self.receive('removed_child')
            finally:
                self.receive('modified')
        elif _op == 'mod':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _id = args[1]
            _obj = _l.getObject(_id)
            if _obj is None:
                raise ValueError, "Lost object for layer 'mod': id=%d" % _id
            if undo:
                self.ignore('modified')                    
                try:                    
                    _obj.undo()
                    self.saveRedoData(_op, _id)
                finally:
                    self.receive('modified')
            else:
                _obj.redo()
        else:
            raise ValueError, "Unexpected operation: %s" % _op

    def _makeObject(self, values):
        _type = values[0]
        _id, _pid = values[1]
        _vlen = len(values)
        _l = self.__layer
        _obj = None
        if _type == 'point':
            if _vlen != 4:
                raise ValueError, "Unexpected point value length: %d" % _vlen
            _x, _y = values[2:]
            _obj = point.Point(_x, _y, id=_id)
        elif _type == 'segment':
            if _vlen != 5:
                raise ValueError, "Unexpected segment value length: %d" % _vlen
            _gdata, _p1id, _p2id = values[2:]
            _glen = len(_gdata)
            if _glen != 4:
                raise ValueError, "Unexpected graphic data length: %d" % _glen
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Segment P1 point missing; id=%d" % _p1id
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Segment P2 point missing; id=%d" % _p2id
            _obj = segment.Segment(_p1, _p2, id=_id) # fixme - use _gdata
        elif _type == 'circle':
            if _vlen != 5:
                raise ValueError, "Unexpected circle value length: %d" % _vlen
            _gdata, _cid, _r = values[2:]
            _glen = len(_gdata)
            if _glen != 4:
                raise ValueError, "Unexpected graphic data length: %d" % _glen
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "Circle center missing: id=%d" % _cid
            _obj = circle.Circle(_cp, _r, id=_id) # fixme - use _gdata
        elif _type == 'arc':
            if _vlen != 7:
                raise ValueError, "Unexpected arc value length: %d" % _vlen
            _gdata, _cid, _r, _sa, _ea = values[2:]
            _glen = len(_gdata)
            if _glen != 4:
                raise ValueError, "Unexpected graphic data length: %d" % _glen
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "Arc center missing: id=%d" % _cid
            _obj = arc.Arc(_cp, _r, _sa, _ea, id=_id) # fixme - use _gdata
        elif _type == 'ellipse':
            raise TypeError, "Ellipse not yet handled ..."
        elif _type == 'leader':
            if _vlen != 7:
                raise ValueError, "Unexpected arc value length: %d" % _vlen
            _gdata, _p1id, _p2id, _p3id, _size = values[2:]
            _glen = len(_gdata)
            if _glen != 4:
                raise ValueError, "Unexpected graphic data length: %d" % _glen
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Leader P1 point missing: id=%d" % _p1id
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Leader P2 point missing: id=%d" % _p2id
            _p3 = _l.getObject(_p3id)
            if _p3 is None or not isinstance(_p3, point.Point):
                raise ValueError, "Leader P3 point missing: id=%d" % _p3id
            _obj = leader.Leader(_p1, _p2, _p3, _size, id=_id) # fixme - use _gdata
        elif _type == 'polyline':
            if _vlen != 4:
                raise ValueError, "Unexpected circle value length: %d" % _vlen
            _gdata, _pids = values[2:]
            _glen = len(_gdata)
            if _glen != 4:
                raise ValueError, "Unexpected graphic data length: %d" % _glen
            _pts = []
            for _pid in _pids:
                _p = _l.getObject(_pid)
                if _p is None or not isinstance(_p, point.Point):
                    raise ValueError, "Polyline point missing: id=%d" % _pid
                _pts.append(_p)
            _obj = polyline.Polyline(_pts, id=_id) # fixme - use _gdata
        elif _type == 'hcline':
            if _vlen != 3:
                raise ValueError, "Unexpected hcline value length: %d" % _vlen
            _pid = values[2]
            _p = _l.getObject(_pid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "HCLine point missing: id=%d" % _pid
            _obj = hcline.HCLine(_p, id=_id)
        elif _type == 'vcline':
            if _vlen != 3:
                raise ValueError, "Unexpected vcline value length: %d" % _vlen
            _pid = values[2]
            _p = _l.getObject(_pid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "VCLine point missing: id=%d" % _pid
            _obj = vcline.VCLine(_p, id=_id)
        elif _type == 'acline':
            if _vlen != 4:
                raise ValueError, "Unexpected acline value length: %d" % _vlen
            _pid, _angle = values[2:]
            _p = _l.getObject(_pid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "ACLine point missing: id=%d" % _pid
            _obj = acline.ACLine(_p, _angle, id=_id)
        elif _type == 'cline':
            if _vlen != 4:
                raise ValueError, "Unexpected cline value length: %d" % _vlen
            _p1id, _p2id = values[2:]
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "CLine P1 point missing: id=%d" % _p1id
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "CLine P2 point missing: id=%d" % _p2id
            _obj = cline.CLine(_p1, _p2, id=_id)
        elif _type == 'ccircle':
            if _vlen != 4:
                raise ValueError, "Unexpected ccircle value length: %d" % _vlen
            _cid, _r = values[2:]
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "CCircle center missing: id=%d" % _cid
            _obj = ccircle.CCircle(_cp, _r, id=_id)
        elif _type == 'fillet' or _type == 'chamfer':
            raise TypeError, "Chamfer/Fillet not yet handled ..."
        elif _type == 'ldim' or _type == 'hdim' or _type == 'vdim':
            if _vlen != 9:
                raise ValueError, "Unexpected value length: %d" % _vlen
            _pdict, _l1id, _p1id, _l2id, _p2id, _x, _y = values[2:]
            _l1 = _p1 = _l2 = _p2 = None
            _lid = _l.getID()
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _l1id == _lid:
                _l1 = _l
            else:
                _l1 = _img.getObject(_l1id)
                if _l1 is None or not isinstance(_l1, Layer):
                    raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id
            _p1 = _l1.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Dimension P1 point missing: id=%d" % _p1id
            if _l2id == _lid:
                _l2 = _l
            else:
                _l2 = _img.getObject(_l2id)
                if _l2 is None or not isinstance(_l2, Layer):
                    raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id
            _p2 = _l2.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Dimension P2 point missing: id=%d" % _p2id
            _ds = None
            _dsname = _pdict.get('dsname')
            if _dsname is not None:
                _ds = _img.getDimStyle(name=_dsname)
            if _ds is None:
                _ds = _img.getOption('DIM_STYLE')
            if _type == 'ldim':
                _objtype = dimension.LinearDimension
            elif _type == 'hdim':
                _objtype = dimension.HorizontalDimension
            elif _type == 'vdim':
                _objtype = dimension.VerticalDimension
            else:
                raise ValueError, "Unexpected type: %s" % _type
            #
            # fixme - need to adjust values differing from the
            # style values ...
            #
            _obj = _objtype(_l1, _p1, _l2, _p2, _x, _y, _ds, id=_id)
        elif _type == 'rdim':
            if _vlen != 7:
                raise ValueError, "Unexpected value length: %d" % _vlen
            _pdict, _clid, _cid, _x, _y = values[2:]
            _cl = _c = None
            _lid = _l.getID()
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _clid == _lid:
                _cl = _l
            else:
                _cl = _img.getObject(_clid)
                if _cl is None or not isinstance(_cl, Layer):
                    raise ValueError, "Dimension Layer missing: id=%d" % _clid
            _c = _cl.getObject(_cid)
            if _c is None or not isinstance(_c, (circle.Circle, arc.Arc)):
                raise ValueError, "Dimension Circle/Arc missing: id=%d" % _cid
            _ds = None
            _dsname = _pdict.get('dsname')
            if _dsname is not None:
                _ds = _img.getDimStyle(name=_dsname)
            if _ds is None:
                _ds = _img.getOption('DIM_STYLE')
            _obj = dimension.RadialDimension(_cl, _c, _x, _y, _ds, id=_id)
        elif _type == 'adim':
            if _vlen != 11:
                raise ValueError, "Unexpected value length: %d" % _vlen
            _pdict, _vlid, _vpid, _l1id, _p1id, _l2id, _p2id, _x, _y = values[2:]
            _vl = _vp = _l1 = _p1 = _l2 = _p2 = None
            _lid = _l.getID()
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _vlid == _lid:
                _vl = _l
            else:
                _vl = _img.getObject(_vlid)
                if _vl is None or not isinstance(_vl, Layer):
                    raise ValueError, "Dimension vertex layer missing: id=%d" % _vlid
            _vp = _vl.getObject(_vpid)
            if _vp is None or not isinstance(_vp, point.Point):
                raise ValueError, "Dimension vertex point missing: id=%d" % _vpid
            if _l1id == _lid:
                _l1 = _l
            else:
                _l1 = _img.getObject(_l1id)
                if _l1 is None or not isinstance(_l1, Layer):
                    raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id
            _p1 = _l1.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Dimension P1 point missing: id=%d" % _p1id
            if _l2id == _lid:
                _l2 = _l
            else:
                _l2 = _img.getObject(_l2id)
                if _l2 is None or not isinstance(_l2, Layer):
                    raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id
            _p2 = _l2.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Dimension P2 point missing: id=%d" % _p2id
            _ds = None
            _dsname = _pdict.get('dsname')
            if _dsname is not None:
                _ds = _img.getDimStyle(name=_dsname)
            if _ds is None:
                _ds = _img.getOption('DIM_STYLE')
            _obj = dimension.AngularDimension(_vl, _vp, _l1, _p1, _l2, _p2, _x, _y, _ds, id=_id)
        else:
            raise TypeError, "unexpected type: %s" % _type
        return _obj

    def _delObject(self, mute, values):
        # print "_delObject() ..."
        _op = values[0]
        # print "op: " + str(_op)
        _id, _pid = values[1]
        # print "id: %d" % _id
        # print "pid: %d" % _pid
        _l = self.__layer
        _obj = _l.getObject(_id)
        if _obj is None:
            raise ValueError, "Missed object: %d, %s" % (_id, str(values))
        _l.startUndo(mute)
        try:
            _l.delObject(_obj)
        finally:
            _l.endUndo()
