New Features: In Tab-View mode, Ctrl-number will take the user to
    the numbered tab view.  Modified files now show an '*' astrisk in
    the view title.  Debugger framework can now support PHP debugging.
    Not important for python development, but at least that means the
    debugger framework is more generalized.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
	
		
			
				
	
	
		
			876 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			876 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#----------------------------------------------------------------------------
 | 
						|
# Name:         AbstractEditor.py
 | 
						|
# Purpose:      Non-text editor for DataModel and Process
 | 
						|
#
 | 
						|
# Author:       Peter Yared, Morgan Hua
 | 
						|
#
 | 
						|
# Created:      7/28/04
 | 
						|
# CVS-ID:       $Id$
 | 
						|
# Copyright:    (c) 2004-2005 ActiveGrid, Inc.
 | 
						|
# License:      wxWindows License
 | 
						|
#----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
import wx
 | 
						|
import wx.lib.docview
 | 
						|
import wx.lib.ogl as ogl
 | 
						|
import PropertyService
 | 
						|
_ = wx.GetTranslation
 | 
						|
 | 
						|
 | 
						|
SELECT_BRUSH = wx.Brush("BLUE", wx.SOLID)
 | 
						|
SHAPE_BRUSH = wx.Brush("WHEAT", wx.SOLID)
 | 
						|
LINE_BRUSH = wx.BLACK_BRUSH
 | 
						|
INACTIVE_SELECT_BRUSH = wx.Brush("LIGHT BLUE", wx.SOLID)
 | 
						|
 | 
						|
NORMALFONT = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 | 
						|
SLANTFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), wx.SLANT, NORMALFONT.GetWeight())
 | 
						|
BOLDFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), NORMALFONT.GetStyle(), wx.BOLD)
 | 
						|
 | 
						|
DEFAULT_BACKGROUND_COLOR = wx.Colour(0xEE, 0xEE, 0xEE)
 | 
						|
HEADER_BRUSH = wx.Brush(wx.Colour(0xDB, 0xEB, 0xFF), wx.SOLID)
 | 
						|
BODY_BRUSH = wx.Brush(wx.WHITE, wx.SOLID)
 | 
						|
 | 
						|
 | 
						|
PARKING_VERTICAL = 1
 | 
						|
PARKING_HORIZONTAL = 2
 | 
						|
PARKING_OFFSET = 30    # space between shapes
 | 
						|
 | 
						|
FORCE_REDRAW_METHOD = "ForceRedraw"
 | 
						|
 | 
						|
def GetRawModel(model):
 | 
						|
    if hasattr(model, "GetRawModel"):
 | 
						|
        rawModel = model.GetRawModel()
 | 
						|
    else:
 | 
						|
        rawModel = model
 | 
						|
    return rawModel
 | 
						|
 | 
						|
 | 
						|
def GetLabel(model):
 | 
						|
    model = GetRawModel(model)
 | 
						|
    if hasattr(model, "__xmlname__"):
 | 
						|
        label = model.__xmlname__
 | 
						|
        try:
 | 
						|
            if (len(label) > 0):
 | 
						|
                label = label[0].upper() + label[1:]
 | 
						|
            if (hasattr(model, "complexType")):
 | 
						|
                label += ': %s/%s' % (model.complexType.name, model.name)
 | 
						|
            else:
 | 
						|
                if model.name:
 | 
						|
                    label += ': %s' % model.name
 | 
						|
                elif model.ref:
 | 
						|
                    label += ': %s' % model.ref
 | 
						|
        except AttributeError:
 | 
						|
            pass
 | 
						|
    else:
 | 
						|
        label = str(model)
 | 
						|
    return label
 | 
						|
 | 
						|
 | 
						|
class CanvasView(wx.lib.docview.View):
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Overridden methods
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
    def __init__(self, brush=SHAPE_BRUSH, background=DEFAULT_BACKGROUND_COLOR):
 | 
						|
        wx.lib.docview.View.__init__(self)
 | 
						|
        self._brush = brush
 | 
						|
        self._backgroundColor = background
 | 
						|
        self._canvas = None
 | 
						|
        self._pt1 = None
 | 
						|
        self._pt2 = None
 | 
						|
        self._needEraseLasso = False
 | 
						|
        self._propShape = None
 | 
						|
        self._maxWidth = 2000
 | 
						|
        self._maxHeight = 16000
 | 
						|
        self._valetParking = False
 | 
						|
 | 
						|
 | 
						|
    def OnDraw(self, dc):
 | 
						|
        """ for Print Preview and Print """
 | 
						|
        dc.BeginDrawing()
 | 
						|
        self._canvas.Redraw(dc)
 | 
						|
        dc.EndDrawing()
 | 
						|
        
 | 
						|
 | 
						|
    def OnCreate(self, doc, flags):
 | 
						|
        frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
 | 
						|
        frame.Show()
 | 
						|
        sizer = wx.BoxSizer()
 | 
						|
        self._CreateCanvas(frame)
 | 
						|
        sizer.Add(self._canvas, 1, wx.EXPAND, 0)
 | 
						|
        frame.SetSizer(sizer)
 | 
						|
        frame.Layout()        
 | 
						|
        self.Activate()
 | 
						|
        wx.EVT_RIGHT_DOWN(self._canvas, self.OnRightClick)
 | 
						|
        return True
 | 
						|
        
 | 
						|
 | 
						|
    def OnActivateView(self, activate, activeView, deactiveView):
 | 
						|
        if activate and self._canvas:
 | 
						|
            # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
 | 
						|
            if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
 | 
						|
                self.SetFocus()
 | 
						|
            else:
 | 
						|
                wx.CallAfter(self.SetFocus)
 | 
						|
 | 
						|
 | 
						|
    def SetFocus(self):
 | 
						|
        if self._canvas:
 | 
						|
            self._canvas.SetFocus()
 | 
						|
 | 
						|
 | 
						|
    def OnFocus(self, event):
 | 
						|
        self.FocusColorPropertyShape(True)
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def FocusOnClick(self, event):
 | 
						|
        self.SetFocus()
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def OnKillFocus(self, event):
 | 
						|
        self.FocusColorPropertyShape(False)
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def HasFocus(self):
 | 
						|
        winWithFocus = wx.Window.FindFocus()
 | 
						|
        if not winWithFocus:
 | 
						|
            return False
 | 
						|
        while winWithFocus:
 | 
						|
            if winWithFocus == self._canvas:
 | 
						|
                return True
 | 
						|
            winWithFocus = winWithFocus.GetParent()
 | 
						|
        return False
 | 
						|
 | 
						|
 | 
						|
    def OnClose(self, deleteWindow = True):
 | 
						|
        statusC = wx.GetApp().CloseChildDocuments(self.GetDocument())
 | 
						|
        statusP = wx.lib.docview.View.OnClose(self, deleteWindow = deleteWindow)
 | 
						|
        if hasattr(self, "ClearOutline"):
 | 
						|
            wx.CallAfter(self.ClearOutline)  # need CallAfter because when closing the document, it is Activated and then Close, so need to match OnActivateView's CallAfter
 | 
						|
        if not (statusC and statusP):
 | 
						|
            return False
 | 
						|
        self.Activate(False)
 | 
						|
        if deleteWindow and self.GetFrame():
 | 
						|
            self.GetFrame().Destroy()
 | 
						|
        return True
 | 
						|
 | 
						|
 | 
						|
    def _CreateCanvas(self, parent):
 | 
						|
        self._canvas = ogl.ShapeCanvas(parent)
 | 
						|
        wx.EVT_LEFT_DOWN(self._canvas, self.OnLeftClick)
 | 
						|
        wx.EVT_LEFT_UP(self._canvas, self.OnLeftUp)
 | 
						|
        wx.EVT_MOTION(self._canvas, self.OnLeftDrag)
 | 
						|
        wx.EVT_LEFT_DCLICK(self._canvas, self.OnLeftDoubleClick)
 | 
						|
        wx.EVT_KEY_DOWN(self._canvas, self.OnKeyPressed)
 | 
						|
        
 | 
						|
        # need this otherwise mouse clicks don't set focus to this view
 | 
						|
        wx.EVT_LEFT_DOWN(self._canvas, self.FocusOnClick)
 | 
						|
        wx.EVT_LEFT_DCLICK(self._canvas, self.FocusOnClick)
 | 
						|
        wx.EVT_RIGHT_DOWN(self._canvas, self.FocusOnClick)
 | 
						|
        wx.EVT_RIGHT_DCLICK(self._canvas, self.FocusOnClick)
 | 
						|
        wx.EVT_MIDDLE_DOWN(self._canvas, self.FocusOnClick)
 | 
						|
        wx.EVT_MIDDLE_DCLICK(self._canvas, self.FocusOnClick)
 | 
						|
        
 | 
						|
        wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus)
 | 
						|
        wx.EVT_SET_FOCUS(self._canvas, self.OnFocus)
 | 
						|
 | 
						|
        self._canvas.SetScrollbars(20, 20, self._maxWidth / 20, self._maxHeight / 20)
 | 
						|
        
 | 
						|
        self._canvas.SetBackgroundColour(self._backgroundColor)
 | 
						|
        self._diagram = ogl.Diagram()
 | 
						|
        self._canvas.SetDiagram(self._diagram)
 | 
						|
        self._diagram.SetCanvas(self._canvas)
 | 
						|
        self._canvas.SetFont(NORMALFONT)
 | 
						|
 | 
						|
 | 
						|
    def OnClear(self, event):
 | 
						|
        """ Deletion of selected objects from view.
 | 
						|
        *Must Override*
 | 
						|
        """
 | 
						|
        self.SetPropertyModel(None)
 | 
						|
                  
 | 
						|
 | 
						|
    def SetLastRightClick(self, x, y):
 | 
						|
        self._lastRightClick = (x,y)
 | 
						|
        
 | 
						|
 | 
						|
    def GetLastRightClick(self):
 | 
						|
        if hasattr(self, "_lastRightClick"):
 | 
						|
            return self._lastRightClick
 | 
						|
        return (-1,-1)
 | 
						|
        
 | 
						|
 | 
						|
    def OnKeyPressed(self, event):
 | 
						|
        key = event.KeyCode()
 | 
						|
        if key == wx.WXK_DELETE:
 | 
						|
            self.OnClear(event)
 | 
						|
        else:
 | 
						|
            event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def OnRightClick(self, event):
 | 
						|
        """ force selection underneath right click position. """
 | 
						|
        self.Activate()
 | 
						|
        self._canvas.SetFocus()
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
        x, y = event.GetLogicalPosition(dc)  # this takes into account scrollbar offset
 | 
						|
        self.SetLastRightClick(x, y)
 | 
						|
        shape = self._canvas.FindShape(x, y)[0]
 | 
						|
        
 | 
						|
        model = None
 | 
						|
        if not shape:
 | 
						|
            self.SetSelection(None)
 | 
						|
            self.SetPropertyShape(None)
 | 
						|
        elif hasattr(shape, "GetModel"):
 | 
						|
            self.BringToFront(shape)
 | 
						|
            self.SetPropertyShape(shape)
 | 
						|
            self.SetSelection(shape)
 | 
						|
            shape.Select(True, dc)
 | 
						|
            model = shape.GetModel()
 | 
						|
        elif shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):  # ComplexTypeHeader for ComplexTypeShape
 | 
						|
            self.BringToFront(shape)
 | 
						|
            self.SetPropertyShape(shape.GetParent())
 | 
						|
            self.SetSelection(shape.GetParent())
 | 
						|
            shape.GetParent().Select(True, dc)
 | 
						|
            model = shape.GetParent().GetModel()
 | 
						|
 | 
						|
        self.SetPropertyModel(model)
 | 
						|
        
 | 
						|
        return (shape, model)
 | 
						|
 | 
						|
 | 
						|
    def OnLeftClick(self, event):
 | 
						|
        self.Activate()
 | 
						|
        self._canvas.SetFocus()
 | 
						|
        
 | 
						|
        self.EraseRubberBand()
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
 | 
						|
        # keep track of mouse down for group select
 | 
						|
        self._pt1 = event.GetLogicalPosition(dc)  # this takes into account scrollbar offset
 | 
						|
        self._pt2 = None
 | 
						|
 | 
						|
        shape = self._canvas.FindShape(self._pt1[0], self._pt1[1])[0]
 | 
						|
        if shape:
 | 
						|
            self.BringToFront(shape)
 | 
						|
 | 
						|
            self._pt1 = None
 | 
						|
            event.Skip()  # pass on event to shape handler to take care of selection
 | 
						|
 | 
						|
            return
 | 
						|
        elif event.ControlDown() or event.ShiftDown():    # extend select, don't deselect
 | 
						|
            pass
 | 
						|
        else:
 | 
						|
            # click on empty part of canvas, deselect everything
 | 
						|
            forceRedrawShapes = []
 | 
						|
            needRefresh = False
 | 
						|
            for shape in self._diagram.GetShapeList():
 | 
						|
                if hasattr(shape, "GetModel"):
 | 
						|
                    if shape.Selected():
 | 
						|
                        needRefresh = True
 | 
						|
                        shape.Select(False, dc)
 | 
						|
                        if hasattr(shape, FORCE_REDRAW_METHOD):
 | 
						|
                            forceRedrawShapes.append(shape)
 | 
						|
            if needRefresh:
 | 
						|
                self._canvas.Redraw(dc)
 | 
						|
 | 
						|
            self.SetPropertyModel(None)
 | 
						|
 | 
						|
        if len(self.GetSelection()) == 0:
 | 
						|
            self.SetPropertyShape(None)
 | 
						|
 | 
						|
        for shape in forceRedrawShapes:
 | 
						|
            shape.ForceRedraw()
 | 
						|
 | 
						|
    def OnLeftDoubleClick(self, event):
 | 
						|
        propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
 | 
						|
        if propertyService:
 | 
						|
            propertyService.ShowWindow()
 | 
						|
 | 
						|
 | 
						|
    def OnLeftDrag(self, event):
 | 
						|
        # draw lasso for group select
 | 
						|
        if self._pt1 and event.LeftIsDown():   # we are in middle of lasso selection
 | 
						|
            self.EraseRubberBand()
 | 
						|
 | 
						|
            dc = wx.ClientDC(self._canvas)
 | 
						|
            self._canvas.PrepareDC(dc)
 | 
						|
            self._pt2 = event.GetLogicalPosition(dc)  # this takes into account scrollbar offset
 | 
						|
            self.DrawRubberBand()
 | 
						|
        else:
 | 
						|
            event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def OnLeftUp(self, event):
 | 
						|
        # do group select
 | 
						|
        if self._needEraseLasso:
 | 
						|
            self.EraseRubberBand()
 | 
						|
 | 
						|
            dc = wx.ClientDC(self._canvas)
 | 
						|
            self._canvas.PrepareDC(dc)
 | 
						|
            x1, y1 = self._pt1
 | 
						|
            x2, y2 = event.GetLogicalPosition(dc)  # this takes into account scrollbar offset
 | 
						|
 | 
						|
            tol = self._diagram.GetMouseTolerance()
 | 
						|
            if abs(x1 - x2) > tol or abs(y1 - y2) > tol:
 | 
						|
                # make sure x1 < x2 and y1 < y2 to make comparison test easier
 | 
						|
                if x1 > x2:
 | 
						|
                    temp = x1
 | 
						|
                    x1 = x2
 | 
						|
                    x2 = temp
 | 
						|
                if y1 > y2:
 | 
						|
                    temp = y1
 | 
						|
                    y1 = y2
 | 
						|
                    y2 = temp
 | 
						|
 | 
						|
                for shape in self._diagram.GetShapeList():
 | 
						|
                    if not shape.GetParent() and hasattr(shape, "GetModel"):  # if part of a composite, don't select it
 | 
						|
                        x, y = shape.GetX(), shape.GetY()
 | 
						|
                        width, height = shape.GetBoundingBoxMax()
 | 
						|
                        selected = x1 < x - width/2 and x2 > x + width/2 and y1 < y - height/2 and y2 > y + height/2
 | 
						|
                        if event.ControlDown() or event.ShiftDown():    # extend select, don't deselect
 | 
						|
                            if selected:
 | 
						|
                                shape.Select(selected, dc)
 | 
						|
                        else:   # select items in lasso and deselect items out of lasso
 | 
						|
                            shape.Select(selected, dc)
 | 
						|
                self._canvas.Redraw(dc)
 | 
						|
            else:
 | 
						|
                event.Skip()
 | 
						|
        else:
 | 
						|
            event.Skip()
 | 
						|
 | 
						|
 | 
						|
    def EraseRubberBand(self):
 | 
						|
        if self._needEraseLasso:
 | 
						|
            self._needEraseLasso = False
 | 
						|
 | 
						|
            dc = wx.ClientDC(self._canvas)
 | 
						|
            self._canvas.PrepareDC(dc)
 | 
						|
            dc.SetLogicalFunction(wx.XOR)
 | 
						|
            pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
 | 
						|
            dc.SetPen(pen)
 | 
						|
            brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
 | 
						|
            dc.SetBrush(brush)
 | 
						|
            dc.ResetBoundingBox()
 | 
						|
            dc.BeginDrawing()
 | 
						|
 | 
						|
            x1, y1 = self._pt1
 | 
						|
            x2, y2 = self._pt2
 | 
						|
 | 
						|
            # make sure x1 < x2 and y1 < y2
 | 
						|
            # this will make (x1, y1) = upper left corner
 | 
						|
            if x1 > x2:
 | 
						|
                temp = x1
 | 
						|
                x1 = x2
 | 
						|
                x2 = temp
 | 
						|
            if y1 > y2:
 | 
						|
                temp = y1
 | 
						|
                y1 = y2
 | 
						|
                y2 = temp
 | 
						|
 | 
						|
            # erase previous outline
 | 
						|
            dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
 | 
						|
            dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
 | 
						|
            dc.EndDrawing()
 | 
						|
 | 
						|
 | 
						|
    def DrawRubberBand(self):
 | 
						|
        self._needEraseLasso = True
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
        dc.SetLogicalFunction(wx.XOR)
 | 
						|
        pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
 | 
						|
        dc.SetPen(pen)
 | 
						|
        brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
 | 
						|
        dc.SetBrush(brush)
 | 
						|
        dc.ResetBoundingBox()
 | 
						|
        dc.BeginDrawing()
 | 
						|
 | 
						|
        x1, y1 = self._pt1
 | 
						|
        x2, y2 = self._pt2
 | 
						|
 | 
						|
        # make sure x1 < x2 and y1 < y2
 | 
						|
        # this will make (x1, y1) = upper left corner
 | 
						|
        if x1 > x2:
 | 
						|
            temp = x1
 | 
						|
            x1 = x2
 | 
						|
            x2 = temp
 | 
						|
        if y1 > y2:
 | 
						|
            temp = y1
 | 
						|
            y1 = y2
 | 
						|
            y2 = temp
 | 
						|
 | 
						|
        # draw outline
 | 
						|
        dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
 | 
						|
        dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
 | 
						|
        dc.EndDrawing()
 | 
						|
 | 
						|
 | 
						|
    def SetValetParking(self, enable=True):
 | 
						|
        """ If valet parking is enabled, remember last parking spot and try for a spot near it """
 | 
						|
        self._valetParking = enable
 | 
						|
        if enable:
 | 
						|
            self._valetPosition = None
 | 
						|
        
 | 
						|
 | 
						|
    def FindParkingSpot(self, width, height, parking=PARKING_HORIZONTAL, x=PARKING_OFFSET, y=PARKING_OFFSET):
 | 
						|
        """
 | 
						|
            Given a width and height, find a upper left corner where shape can be parked without overlapping other shape
 | 
						|
        """
 | 
						|
        if self._valetParking and self._valetPosition:
 | 
						|
            x, y = self._valetPosition
 | 
						|
        
 | 
						|
        max = 700  # max distance to the right where we'll place tables
 | 
						|
        noParkingSpot = True
 | 
						|
 | 
						|
        while noParkingSpot:
 | 
						|
            point = self.isSpotOccupied(x, y, width, height)
 | 
						|
            if point:
 | 
						|
                if parking == PARKING_HORIZONTAL:
 | 
						|
                    x = point[0] + PARKING_OFFSET
 | 
						|
                    if x > max:
 | 
						|
                        x = PARKING_OFFSET
 | 
						|
                        y = point[1] + PARKING_OFFSET
 | 
						|
                else:  # parking == PARKING_VERTICAL:
 | 
						|
                    y = point[1] + PARKING_OFFSET
 | 
						|
                    if y > max:
 | 
						|
                        y = PARKING_OFFSET
 | 
						|
                        x = point[0] + PARKING_OFFSET
 | 
						|
            else:
 | 
						|
                noParkingSpot = False
 | 
						|
 | 
						|
        if self._valetParking:
 | 
						|
            self._valetPosition = (x, y)
 | 
						|
            
 | 
						|
        return x, y
 | 
						|
 | 
						|
 | 
						|
    def isSpotOccupied(self, x, y, width, height):
 | 
						|
        """ returns None if at x,y,width,height no object occupies that rectangle,
 | 
						|
            otherwise returns lower right corner of object that occupies given x,y position
 | 
						|
        """
 | 
						|
        x2 = x + width
 | 
						|
        y2 = y + height
 | 
						|
 | 
						|
        for shape in self._diagram.GetShapeList():
 | 
						|
            if isinstance(shape, ogl.RectangleShape) or isinstance(shape, ogl.EllipseShape) or isinstance(shape, ogl.PolygonShape):
 | 
						|
                if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
 | 
						|
                    # skip, part of a composite shape
 | 
						|
                    continue
 | 
						|
 | 
						|
                if hasattr(shape, "GetModel"):
 | 
						|
                    other_x, other_y, other_width, other_height = shape.GetModel().getEditorBounds()
 | 
						|
                    other_x2 = other_x + other_width
 | 
						|
                    other_y2 = other_y + other_height
 | 
						|
                else:
 | 
						|
                    # shapes x,y are at the center of the shape, need to transform to upper left coordinate
 | 
						|
                    other_width, other_height = shape.GetBoundingBoxMax()
 | 
						|
                    other_x = shape.GetX() - other_width/2
 | 
						|
                    other_y = shape.GetY() - other_height/2
 | 
						|
 | 
						|
                other_x2 = other_x + other_width
 | 
						|
                other_y2 = other_y + other_height
 | 
						|
                # intersection check
 | 
						|
                if ((other_x2 < other_x or other_x2 > x) and
 | 
						|
                    (other_y2 < other_y or other_y2 > y) and
 | 
						|
                    (x2 < x or x2 > other_x) and
 | 
						|
                    (y2 < y or y2 > other_y)):
 | 
						|
                    return (other_x2, other_y2)
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Canvas methods
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
    def AddShape(self, shape, x = None, y = None, pen = None, brush = None, text = None, eventHandler = None, shown=True):
 | 
						|
        if isinstance(shape, ogl.CompositeShape):
 | 
						|
            dc = wx.ClientDC(self._canvas)
 | 
						|
            self._canvas.PrepareDC(dc)
 | 
						|
            shape.Move(dc, x, y)
 | 
						|
        else:
 | 
						|
            shape.SetDraggable(True, True)
 | 
						|
        shape.SetCanvas(self._canvas)
 | 
						|
 | 
						|
        if x:
 | 
						|
            shape.SetX(x)
 | 
						|
        if y:
 | 
						|
            shape.SetY(y)
 | 
						|
        shape.SetCentreResize(False)
 | 
						|
        if pen:
 | 
						|
            shape.SetPen(pen)
 | 
						|
        if brush:
 | 
						|
            shape.SetBrush(brush)
 | 
						|
        if text:
 | 
						|
            shape.AddText(text)
 | 
						|
        shape.SetShadowMode(ogl.SHADOW_NONE)
 | 
						|
        self._diagram.AddShape(shape)
 | 
						|
        shape.Show(shown)
 | 
						|
        if not eventHandler:
 | 
						|
            eventHandler = EditorCanvasShapeEvtHandler(self)
 | 
						|
        eventHandler.SetShape(shape)
 | 
						|
        eventHandler.SetPreviousHandler(shape.GetEventHandler())
 | 
						|
        shape.SetEventHandler(eventHandler)
 | 
						|
        return shape
 | 
						|
 | 
						|
 | 
						|
    def RemoveShape(self, model = None, shape = None):
 | 
						|
        if not model and not shape:
 | 
						|
            return
 | 
						|
 | 
						|
        if not shape:
 | 
						|
            shape = self.GetShape(model)
 | 
						|
 | 
						|
        if shape:
 | 
						|
            shape.Select(False)
 | 
						|
            for line in shape.GetLines():
 | 
						|
                shape.RemoveLine(line)
 | 
						|
                self._diagram.RemoveShape(line)
 | 
						|
                line.Delete()
 | 
						|
            for obj in self._diagram.GetShapeList():
 | 
						|
                for line in obj.GetLines():
 | 
						|
                    if self.IsShapeContained(shape, line.GetTo()) or self.IsShapeContained(shape, line.GetFrom()):
 | 
						|
                        obj.RemoveLine(line)
 | 
						|
                        self._diagram.RemoveShape(line)
 | 
						|
                        line.Delete()
 | 
						|
                    if line == shape:
 | 
						|
                        obj.RemoveLine(line)
 | 
						|
                        self._diagram.RemoveShape(line)
 | 
						|
                        line.Delete()
 | 
						|
                    
 | 
						|
            if self._canvas:
 | 
						|
                shape.RemoveFromCanvas(self._canvas)
 | 
						|
            self._diagram.RemoveShape(shape)
 | 
						|
            shape.Delete()
 | 
						|
 | 
						|
 | 
						|
    def IsShapeContained(self, parent, shape):
 | 
						|
        if parent == shape:
 | 
						|
            return True
 | 
						|
        elif shape.GetParent():
 | 
						|
            return self.IsShapeContained(parent, shape.GetParent())
 | 
						|
            
 | 
						|
        return False
 | 
						|
 | 
						|
 | 
						|
    def UpdateShape(self, model):
 | 
						|
        for shape in self._diagram.GetShapeList():
 | 
						|
            if hasattr(shape, "GetModel") and shape.GetModel() == model:
 | 
						|
                oldw, oldh = shape.GetBoundingBoxMax()
 | 
						|
                oldx = shape.GetX()
 | 
						|
                oldy = shape.GetY()
 | 
						|
 | 
						|
                x, y, w, h = model.getEditorBounds()
 | 
						|
                newX = x + w / 2
 | 
						|
                newY = y + h / 2
 | 
						|
                
 | 
						|
                if oldw != w or oldh != h or oldx != newX or oldy != newY:
 | 
						|
                    dc = wx.ClientDC(self._canvas)
 | 
						|
                    self._canvas.PrepareDC(dc)
 | 
						|
                    shape.SetSize(w, h, True)   # wxBug: SetSize must be before Move because links won't go to the right place
 | 
						|
                    shape.Move(dc, newX, newY)  # wxBug: Move must be after SetSize because links won't go to the right place
 | 
						|
                    shape.ResetControlPoints()
 | 
						|
                    self._canvas.Refresh()
 | 
						|
                    
 | 
						|
                break
 | 
						|
 | 
						|
 | 
						|
    def GetShape(self, model):
 | 
						|
        for shape in self._diagram.GetShapeList():
 | 
						|
            if hasattr(shape, "GetModel") and shape.GetModel() == model:
 | 
						|
                return shape
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
    def GetShapeCount(self):
 | 
						|
        return self._diagram.GetCount()
 | 
						|
 | 
						|
 | 
						|
    def GetSelection(self):
 | 
						|
        return filter(lambda shape: shape.Selected(), self._diagram.GetShapeList())
 | 
						|
 | 
						|
 | 
						|
    def SetSelection(self, models, extendSelect = False):
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
        update = False
 | 
						|
        if not isinstance(models, type([])) and not isinstance(models, type(())):
 | 
						|
            models = [models]
 | 
						|
        for shape in self._diagram.GetShapeList():
 | 
						|
            if hasattr(shape, "GetModel"):
 | 
						|
                if shape.Selected() and not shape.GetModel() in models:  # was selected, but not in new list, so deselect, unless extend select
 | 
						|
                    if not extendSelect:
 | 
						|
                        shape.Select(False, dc)
 | 
						|
                        update = True
 | 
						|
                elif not shape.Selected() and shape.GetModel() in models: # was not selected and in new list, so select
 | 
						|
                    shape.Select(True, dc)
 | 
						|
                    update = True
 | 
						|
                elif extendSelect and shape.Selected() and shape.GetModel() in models: # was selected, but extend select means to deselect
 | 
						|
                    shape.Select(False, dc)
 | 
						|
                    update = True
 | 
						|
        if update:
 | 
						|
            self._canvas.Redraw(dc)
 | 
						|
 | 
						|
 | 
						|
    def BringToFront(self, shape):
 | 
						|
        if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
 | 
						|
            self._diagram.RemoveShape(shape.GetParent())
 | 
						|
            self._diagram.AddShape(shape.GetParent())
 | 
						|
        else:
 | 
						|
            self._diagram.RemoveShape(shape)
 | 
						|
            self._diagram.AddShape(shape)
 | 
						|
 | 
						|
 | 
						|
    def SendToBack(self, shape):
 | 
						|
        if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
 | 
						|
            self._diagram.RemoveShape(shape.GetParent())
 | 
						|
            self._diagram.InsertShape(shape.GetParent())
 | 
						|
        else:
 | 
						|
            self._diagram.RemoveShape(shape)
 | 
						|
            self._diagram.InsertShape(shape)
 | 
						|
 | 
						|
 | 
						|
    def ScrollVisible(self, shape):
 | 
						|
        if not shape:
 | 
						|
            return
 | 
						|
            
 | 
						|
        xUnit, yUnit = self._canvas.GetScrollPixelsPerUnit()
 | 
						|
        scrollX, scrollY = self._canvas.GetViewStart()  # in scroll units
 | 
						|
        scrollW, scrollH = self._canvas.GetSize()  # in pixels
 | 
						|
        w, h = shape.GetBoundingBoxMax() # in pixels
 | 
						|
        x = shape.GetX() - w/2  # convert to upper left coordinate from center
 | 
						|
        y = shape.GetY() - h/2  # convert to upper left coordinate from center
 | 
						|
 | 
						|
        if x >= scrollX*xUnit and x <= scrollX*xUnit + scrollW:  # don't scroll if already visible
 | 
						|
            x = -1
 | 
						|
        else:
 | 
						|
            x = x/xUnit
 | 
						|
 | 
						|
        if y >= scrollY*yUnit and y <= scrollY*yUnit + scrollH:  # don't scroll if already visible
 | 
						|
            y = -1
 | 
						|
        else:
 | 
						|
            y = y/yUnit
 | 
						|
 | 
						|
        self._canvas.Scroll(x, y)  # in scroll units
 | 
						|
 | 
						|
 | 
						|
    def SetPropertyShape(self, shape):
 | 
						|
        # no need to highlight if no PropertyService is running
 | 
						|
        propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
 | 
						|
        if not propertyService:
 | 
						|
            return
 | 
						|
 | 
						|
        if shape == self._propShape:
 | 
						|
            return
 | 
						|
 | 
						|
        if hasattr(shape, "GetPropertyShape"):
 | 
						|
            shape = shape.GetPropertyShape()
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
        dc.BeginDrawing()
 | 
						|
 | 
						|
        # erase old selection if it still exists
 | 
						|
        if self._propShape and self._propShape in self._diagram.GetShapeList():
 | 
						|
            if hasattr(self._propShape, "DEFAULT_BRUSH"):
 | 
						|
                self._propShape.SetBrush(self._propShape.DEFAULT_BRUSH)
 | 
						|
            else:
 | 
						|
                self._propShape.SetBrush(self._brush)
 | 
						|
            if (self._propShape._textColourName in ["BLACK", "WHITE"]):  # Would use GetTextColour() but it is broken
 | 
						|
                self._propShape.SetTextColour("BLACK", 0)
 | 
						|
            self._propShape.Draw(dc)
 | 
						|
 | 
						|
        # set new selection
 | 
						|
        self._propShape = shape
 | 
						|
 | 
						|
        # draw new selection
 | 
						|
        if self._propShape and self._propShape in self._diagram.GetShapeList():
 | 
						|
            if self.HasFocus():
 | 
						|
                self._propShape.SetBrush(SELECT_BRUSH)
 | 
						|
            else:
 | 
						|
                self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
 | 
						|
            if (self._propShape._textColourName in ["BLACK", "WHITE"]):  # Would use GetTextColour() but it is broken
 | 
						|
                self._propShape.SetTextColour("WHITE", 0)
 | 
						|
            self._propShape.Draw(dc)
 | 
						|
 | 
						|
        dc.EndDrawing()
 | 
						|
 | 
						|
 | 
						|
    def FocusColorPropertyShape(self, gotFocus=False):
 | 
						|
        # no need to change highlight if no PropertyService is running
 | 
						|
        propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
 | 
						|
        if not propertyService:
 | 
						|
            return
 | 
						|
 | 
						|
        if not self._propShape:
 | 
						|
            return
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._canvas)
 | 
						|
        self._canvas.PrepareDC(dc)
 | 
						|
        dc.BeginDrawing()
 | 
						|
 | 
						|
        # draw deactivated selection
 | 
						|
        if self._propShape and self._propShape in self._diagram.GetShapeList():
 | 
						|
            if gotFocus:
 | 
						|
                self._propShape.SetBrush(SELECT_BRUSH)
 | 
						|
            else:
 | 
						|
                self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
 | 
						|
            if (self._propShape._textColourName in ["BLACK", "WHITE"]):  # Would use GetTextColour() but it is broken
 | 
						|
                self._propShape.SetTextColour("WHITE", 0)
 | 
						|
            self._propShape.Draw(dc)
 | 
						|
 | 
						|
            if hasattr(self._propShape, FORCE_REDRAW_METHOD):
 | 
						|
                self._propShape.ForceRedraw()
 | 
						|
 | 
						|
        dc.EndDrawing()
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Property Service methods
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
    def GetPropertyModel(self):
 | 
						|
        if hasattr(self, "_propModel"):
 | 
						|
            return self._propModel
 | 
						|
        return None
 | 
						|
        
 | 
						|
 | 
						|
    def SetPropertyModel(self, model):
 | 
						|
        # no need to set the model if no PropertyService is running
 | 
						|
        propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
 | 
						|
        if not propertyService:
 | 
						|
            return
 | 
						|
            
 | 
						|
        if hasattr(self, "_propModel") and model == self._propModel:
 | 
						|
            return
 | 
						|
            
 | 
						|
        self._propModel = model
 | 
						|
        propertyService.LoadProperties(self._propModel, self.GetDocument())
 | 
						|
 | 
						|
 | 
						|
class EditorCanvasShapeMixin:
 | 
						|
 | 
						|
    def GetModel(self):
 | 
						|
        return self._model
 | 
						|
 | 
						|
 | 
						|
    def SetModel(self, model):
 | 
						|
        self._model = model
 | 
						|
 | 
						|
 | 
						|
class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler):
 | 
						|
 | 
						|
    """ wxBug: Bug in OLG package.  With wxShape.SetShadowMode() turned on, when we set the size,
 | 
						|
        the width/height is larger by 6 pixels.  Need to subtract this value from width and height when we
 | 
						|
        resize the object.
 | 
						|
    """
 | 
						|
    SHIFT_KEY = 1
 | 
						|
    CONTROL_KEY = 2
 | 
						|
 | 
						|
    def __init__(self, view):
 | 
						|
        ogl.ShapeEvtHandler.__init__(self)
 | 
						|
        self._view = view
 | 
						|
 | 
						|
 | 
						|
    def OnLeftClick(self, x, y, keys = 0, attachment = 0):
 | 
						|
        shape = self.GetShape()
 | 
						|
        if hasattr(shape, "GetModel"):  # Workaround, on drag, we should deselect all other objects and select the clicked on object
 | 
						|
            model = shape.GetModel()
 | 
						|
        else:
 | 
						|
            shape = shape.GetParent()
 | 
						|
            if shape:
 | 
						|
                model = shape.GetModel()
 | 
						|
 | 
						|
        if model:
 | 
						|
            self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
 | 
						|
            self._view.SetPropertyShape(shape)
 | 
						|
            self._view.SetPropertyModel(model)
 | 
						|
 | 
						|
 | 
						|
    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
 | 
						|
        ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
 | 
						|
        shape = self.GetShape()
 | 
						|
        if hasattr(shape, "GetModel"):  # Workaround, on drag, we should deselect all other objects and select the clicked on object
 | 
						|
            model = shape.GetModel()
 | 
						|
        else:
 | 
						|
            parentShape = shape.GetParent()
 | 
						|
            if parentShape:
 | 
						|
                model = parentShape.GetModel()
 | 
						|
        self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
 | 
						|
 | 
						|
 | 
						|
    def OnMovePre(self, dc, x, y, oldX, oldY, display):
 | 
						|
        """ Prevent objects from being dragged outside of viewable area """
 | 
						|
        if (x < 0) or (y < 0) or (x > self._view._maxWidth) or (y > self._view._maxHeight):
 | 
						|
            return False
 | 
						|
 | 
						|
        return ogl.ShapeEvtHandler.OnMovePre(self, dc, x, y, oldX, oldY, display)
 | 
						|
 | 
						|
 | 
						|
    def OnMovePost(self, dc, x, y, oldX, oldY, display):
 | 
						|
        """ Update the model's record of where the shape should be.  Also enable redo/undo.  """
 | 
						|
        if x == oldX and y == oldY:
 | 
						|
            return
 | 
						|
        if not self._view.GetDocument():
 | 
						|
            return
 | 
						|
        shape = self.GetShape()
 | 
						|
        if isinstance(shape, EditorCanvasShapeMixin) and shape.Draggable():
 | 
						|
            model = shape.GetModel()
 | 
						|
            if hasattr(model, "getEditorBounds") and model.getEditorBounds():
 | 
						|
                x, y, w, h = model.getEditorBounds()
 | 
						|
                newX = shape.GetX() - shape.GetBoundingBoxMax()[0] / 2
 | 
						|
                newY = shape.GetY() - shape.GetBoundingBoxMax()[1] / 2
 | 
						|
                newWidth = shape.GetBoundingBoxMax()[0]
 | 
						|
                newHeight = shape.GetBoundingBoxMax()[1]
 | 
						|
                if shape._shadowMode != ogl.SHADOW_NONE:
 | 
						|
                    newWidth -= shape._shadowOffsetX
 | 
						|
                    newHeight -= shape._shadowOffsetY
 | 
						|
                newbounds = (newX, newY, newWidth, newHeight)
 | 
						|
    
 | 
						|
                if x != newX or y != newY or w != newWidth or h != newHeight:
 | 
						|
                    self._view.GetDocument().GetCommandProcessor().Submit(EditorCanvasUpdateShapeBoundariesCommand(self._view.GetDocument(), model, newbounds))
 | 
						|
 | 
						|
 | 
						|
    def Draw(self, dc):
 | 
						|
        pass
 | 
						|
 | 
						|
 | 
						|
class EditorCanvasUpdateShapeBoundariesCommand(wx.lib.docview.Command):
 | 
						|
 | 
						|
 | 
						|
    def __init__(self, canvasDocument, model, newbounds):
 | 
						|
        wx.lib.docview.Command.__init__(self, canUndo = True)
 | 
						|
        self._canvasDocument = canvasDocument
 | 
						|
        self._model = model
 | 
						|
        self._oldbounds = model.getEditorBounds()
 | 
						|
        self._newbounds = newbounds
 | 
						|
 | 
						|
 | 
						|
    def GetName(self):
 | 
						|
        name = self._canvasDocument.GetNameForObject(self._model)
 | 
						|
        if not name:
 | 
						|
            name = ""
 | 
						|
            print "ERROR: AbstractEditor.EditorCanvasUpdateShapeBoundariesCommand.GetName: unable to get name for ", self._model
 | 
						|
        return _("Move/Resize %s") % name
 | 
						|
 | 
						|
 | 
						|
    def Do(self):
 | 
						|
        return self._canvasDocument.UpdateEditorBoundaries(self._model, self._newbounds)
 | 
						|
 | 
						|
 | 
						|
    def Undo(self):
 | 
						|
        return self._canvasDocument.UpdateEditorBoundaries(self._model, self._oldbounds)
 | 
						|
 |