C:/mesDocs/QT_confDbVis_canvas/visWindow.py

Go to the documentation of this file.
00001 import copy                     #copy module to deep and shallow copy objects
00002 from math import *              #Math module, sin, cos etc.
00003 
00004 # from wxPython.wx import *     #Widget library
00005 from qt import *
00006 from qtcanvas import *
00007 
00008 from cdbVisCore import *        #Constants
00009 from objectclasses import *     #data objects
00010 import pdb
00011 import random
00012 import math
00013 import gc
00014 import sys
00015 import inout
00016 import time
00017 import threading
00018 
00019 #########################################
00020 # GLOBALS                               #
00021 #########################################
00022 zoom_factor = 100               #global variable defining the current zoom
00023 activeItem = 0
00024 timer = None
00025 
00026 ##
00027 #  This class define the rectangle drawn when moving the mouse with de Shfit button pressed. It allows the user to select multiple devices"
00028 #       
00029 class mySelecter(QCanvasRectangle):
00030         def __init__(self, x,y,w=1,h=1,canvas=None):
00031                 QCanvasRectangle.__init__(self,x,y,w,h,canvas)
00032                 self.setPen( QPen(QColor(0,0,0),1,Qt.DotLine) )
00033         def boundingRect(self):
00034                 rect = QCanvasRectangle.boundingRect(self)
00035                 return QRect(rect.x()-5,rect.y()-5,rect.width()+5,rect.height()+5)
00036                 
00037 ##
00038 #  This class should provide a Message box telling the user that the application is busy.
00039 #               The waiter class also execute the function which is time consuming.
00040 #               This class is still not proprely used in the program
00041 class waiter(QDialog):
00042         def __init__(self,parent,fct):
00043                 QDialog.__init__(self,parent,"Waiter",0,0)
00044                 self.image1 = QPixmap()
00045                 self.image1.loadFromData(bigClock_data,"PNG")
00046                 self.setName("Please Wait")
00047                 self.setIcon(self.image1)
00048                 Form1Layout = QGridLayout(self,1,1,11,6,"Form1Layout")
00049                 self.textLabel1 = QLabel(self,"textLabel1")
00050                 Form1Layout.addWidget(self.textLabel1,0,0)
00051                 self.pixmapLabel3 = QLabel(self,"pixmapLabel3")
00052                 self.pixmapLabel3.setSizePolicy(QSizePolicy(0,0,0,0,self.pixmapLabel3.sizePolicy().hasHeightForWidth()))
00053                 self.pixmapLabel3.setPixmap(self.image1)
00054                 self.pixmapLabel3.setScaledContents(1)
00055                 Form1Layout.addWidget(self.pixmapLabel3,0,1)
00056                 
00057                 self.setCaption("Please wait ...")
00058                 self.textLabel1.setText("<h2>Processing ...</h2>")
00059                 self.resize(QSize(209,86).expandedTo(self.minimumSizeHint()))
00060                 self.clearWState(Qt.WState_Polished)            
00061                 self.fct=fct
00062 
00063         def execute(self):
00064                 self.fct() #exec(callback.fct)
00065 
00066 def GetZoomFactor():            #global method to get the current zoom from another module
00067         return zoom_factor
00068 def SetZoomFactor(value):       #global method to set the current zoom from another module
00069         global zoom_factor
00070         zoom_factor = value
00071         visWindow.main.myStatusbar.zoom.setText(str(int(zoom_factor))+" %")
00072 def setActiveItem(item):
00073         global activeItem
00074         if(item!=activeItem):
00075                 activeItem = item
00076 def GetActiveItem():
00077         return activeItem
00078         
00079 ##
00080 #   Return the distance between the point mp(x,y) and the line given by the two points  sp=(sx,sy) and ep=(ex,ey)
00081 #            this function is used wich link to select when the user click on the canvas.
00082 #       
00083 def distPoint2Line(sp,ep,mp):
00084         # METHOD 1 :
00085         # v = (ep.x()-sp.x(), ep.y()-sp.y());
00086         # w = (mp.x() - sp.x(), mp.y() - sp.y())
00087         # c1 = v[0]*w[0] + v[1]*w[1] #dotProduct(w,v);
00088         # c2 = v[0]*v[0] + v[1]*v[1] #dotProduct(v,v);
00089         # b = float(c1)/float(c2);
00090         # tmp = QPoint((v[0]*b)+sp.x(), (v[1]*b)+sp.y()); # ((v.x()*b)+sx, (v.y()*b)+sy)
00091         # dist1 = math.sqrt( (mp.x()-tmp.x())*(mp.x()-tmp.x()) + (mp.y()-tmp.y())*(mp.y()-tmp.y()) ) #distanceBetweenPoints(mp, tmp);
00092         
00093         #METHOD 2:
00094         x,y,sx,sy,ex,ey = mp.x(),mp.y(),sp.x(),sp.y(),ep.x(),ep.y()
00095         if sx == ex :
00096                 return abs(x-sx)
00097         # calculating the parameters of the characteristic equation :  a*x + b*y + c = 0  of the line that pass through the two points : sp and ep
00098         b = -1
00099         a =  (sy-ey)/float(sx-ex)
00100         c =  ey - a*ex
00101         return abs(a*x+b*y+c)/sqrt(float(a*a+b*b))
00102 
00103 #########################################
00104 # CLASS : visWindow                     #
00105 #########################################
00106 
00107 ##
00108 #  This class provides a frame/window in which the devices saved in the configuration database are
00109 #         visually displayed. Methods for the visualization window consists of display methods for the objects.
00110 # 
00111 #       This class inherits from the wxScrolledWindow class, which is a class for displaying information in a DC with scrollbars on the sides
00112 #       This class extends from the dbUpdate interface, onDbUpdate method must be implemented so that we know whenever a dbupdate occurs
00113 #     
00114 class visWindow(QCanvasView, dbUpdate): #(wxScrolledWindow, dbUpdate):
00115     contents = []
00116     ##
00117     #  Constructor.
00118     #           @parent - name of the parent to visWindow, in our window it is the main panel in cdbVis module
00119     #           @id     - id of this window, only used for event handling in main panel
00120     #           @main   - a reference to the main window where we have most of the communication through to the other objects and modules
00121     #         
00122     def __init__(self,main,canvas,parent,name="my CanvasView",flags=0):
00123         # wxScrolledWindow.__init__(self, parent, id, style = wxSUNKEN_BORDER) #Initializing the super class constructor with our data + set window style
00124         QCanvasView.__init__(self,canvas,parent,name,flags)
00125         canvas.resize(5000,5000) # Standard/default size of the visible visual window
00126         self.dirtyCanvas = QCanvas(200,200)
00127         self.main = main
00128         visWindow.main = main
00129         self.canvas = canvas
00130         self.maxWidth, self.maxHeight = 5000, 5000      # This is the size of the whole visual area, including what we must scroll to see
00131         self.centerX = self.maxWidth/2                  # Center in the x-direction
00132         self.centerY = self.maxHeight/2                 # Center in the y-direction
00133         self.scrollUnit = 1                             # Distance (in pixels) we will move in the given direction when clicking on the arrow on the scrollbar
00134 
00135         self.setSizePolicy(QSizePolicy(0,0,0,0,self.sizePolicy().hasHeightForWidth()))
00136         QScrollView.setDragAutoScroll(self,True)
00137         # self.viewport().setMouseTracking(TRUE) ???
00138         self.viewMode = VIEW_CIRCLE                     # Our own defined layout mode, make the nodes surround the "parent" node like a horse shoe
00139         self.xScale = 120                               # Distance in x-direction for layout of our nodes
00140         self.yScale =  80                               # Distance in y-direction for layout of our nodes
00141         self.radius = 200                               # Radius of the horseshoe/circle for the "child" nodes around a node
00142         self.__absY = {}                                # We divide the visual window in several Y-layers (from top to bottom), starting with layer 0 in the center. This variable keeps track of nr of objects in each "layer" at all times
00143  
00144 
00145         self.curTool = None                                     # Keeps track of the current tool we are using, we have two different ones, one for navigation/selection and one for creation
00146 #       self.SetCurrentTool(tool_SELECT)                        # Navigation mode is default
00147 
00148         self.selection = []                                     # Contains all the DrawingObject instances that are selected in our visual window
00149         self.dragMode  = drag_NONE                              # Current mouse-drag mode. Whether we are resizing, moving, selecting objects etc
00150 
00151         self._AdjustMenus()                                     # (Turning obsolete) Adjust popup menu to content and objects
00152 
00153         self.penColour  = Qt.black                              # Set current line colour, for drawing lines of objects
00154         self.fillColour = Qt.white                              # Set current fill colour, for drawing fill of objects
00155         self.lineSize   = 1                                     # Set current line size (width)
00156 
00157         self.zoom = 100                                         # Set current zoom; 100% is of course default
00158         self.Center()                                           # We center the scroll bars
00159 
00160         self.missing_parentnodes = []                           #In undo and redo, if a link is added back to the visual window before the node it was connected to, we add the names of the devices it was connected to in this list, so when we add the devices we first check this list if there are any links we should connect to
00161 
00162         self.prevseldragobj = None                              # For use with dragging a link to a new device, the previous device the link was dragged over is stored here, to cope with the line colouring of the selected device
00163         self.startpointsel = False                              # For use with dragging a link to a new device, the start point
00164 
00165         self.levelzoom = 0                                      # We start with zoom level 0, which is the view of the whole LHCb detector
00166         
00167         pic=QPixmap("lhcbdetector.png")
00168         self.label=QLabel(None)
00169         self.label.setPixmap(pic)
00170         self.label.setGeometry(0,0,670,365)
00171         
00172         self.mem_image = None                                   # We store the bitmap image of the loaded image of the LHCb detector, we do not load it on every paintevent as that would be terribly inefficient + flickering
00173         self.prevsystemover = ""                                # Name of the previous system we had our mouse cursor moved over in zoom level 0
00174         self.levelselections = {}                               # We store a "history" of devices as we go from level 0 and downwards, so that we can use the up arrow to go back again but also to fetch information about the level in other modules
00175         self.macroobjects = []                                  # Similar to the list storing the visual objects, this one stores generic objects in the different levels
00176         self.chamber_found_at_location = False                  # Variable to store whether we found a chamber at a given location in a quadrant or if it was not associated to any yet.
00177         
00178         self.autozoom = True # Whether contents should be zoomed to fit window or not
00179         self.vw_updated = True # Whether we just updated vw with new contents
00180         
00181         self.__moving=0
00182         self.__moving_start= 0
00183         self.pendingItem = 0
00184         self.activeItem = 0  # IS NOT USED : to Remove
00185         self.lastPos = 0
00186         self.minZ, self.maxZ = 0, 20
00187         
00188         self.inOutPutDialog = None
00189         i = 0
00190         self.linkConnect = QCanvasLine(self.canvas) 
00191         self.selecter = mySelecter(0,0,1,1,self.canvas)
00192         self.keptItems = []
00193 
00194 #     ####################################
00195 #     #           METHODS                #
00196 #     ####################################
00197     def ZoomIn(self,factor=-1,default=False):
00198         wm=QWMatrix()
00199         prevZoom = GetZoomFactor()/100
00200         prevw = self.width()/2
00201         prevh = self.height()/2
00202         if default:  # Set zoom to 100%
00203                 newZoom = 1.0
00204         else:
00205                 if factor == -1:
00206                         factor = 1.5
00207                 newZoom = factor*prevZoom
00208                 wm.scale( newZoom, newZoom)
00209         self.setWorldMatrix( wm )
00210         SetZoomFactor(newZoom*100)
00211         self.setContentsPos(newZoom*2500-prevw,newZoom*2500 - prevh)
00212         #self.setContentsPos(newZoom*self.contentsX()-prevw,newZoom*self.contentsX() - prevh)
00213 
00214     def ZoomOut(self,factor=-1,default=False):
00215         wm=QWMatrix()
00216         prevZoom = GetZoomFactor()/100
00217         prevw = self.width()/2
00218         prevh = self.height()/2
00219         if default:  # Set zoom to 100%
00220                 newZoom = 1.0
00221         else:
00222                 if factor == -1:
00223                         factor = 2/3.0
00224                 newZoom = factor*prevZoom
00225         wm.scale( newZoom, newZoom)
00226         self.setWorldMatrix( wm )
00227         SetZoomFactor(newZoom*100)
00228         self.setContentsPos(newZoom*2500-prevw,newZoom*2500 - prevh)
00229 
00230     def keep(self):
00231         if self.__moving:
00232                 self.keptItems = [self.__moving.GetObject()] #+self.__moving.GetPortList(True)+self.__moving.GetPortList(False)
00233                 print self.__moving.GetObject().GetName()
00234         
00235     def contentsContextMenuEvent(self,e):
00236         if self.selection:
00237                 contextMenu = QPopupMenu(self.main)
00238                 contextMenu.insertItem(QString(self.__moving.GetName()))
00239                 contextMenu.insertSeparator()
00240                 self.main.aModify.addTo(contextMenu)
00241                 if self.keptItems==[]:
00242                         self.main.aKeep.addTo(contextMenu)
00243                 contextMenu.insertSeparator()
00244                 self.main.aDelete.addTo(contextMenu)
00245                 contextMenu.exec_loop(e.globalPos())
00246         elif self.main.GetActiveLink():
00247                 contextMenu = QPopupMenu(self.main)
00248                 contextMenu.insertItem(QString("Link : "+self.main.GetActiveLink().GetObject().GetName()))
00249                 contextMenu.insertSeparator()
00250                 self.main.aModify.addTo(contextMenu)
00251                 contextMenu.insertSeparator()
00252                 self.main.aDelete.addTo(contextMenu)
00253                 contextMenu.exec_loop(e.globalPos())
00254 
00255     def noMoveEventAfter(self):
00256         for item in self.selection:
00257                 item.setActive(False)
00258         self.selection = [self.__moving]
00259         self.__moving.setActive(False)
00260                         
00261     def contentsMousePressEvent(self,e): # QMouseEvent e
00262         point = self.inverseWorldMatrix().map(e.pos())
00263         i=0
00264         self.__moving = None
00265         self.__moving_start=point
00266         links_selected = []
00267 
00268         ilist = self.canvas.collisions(point) #QCanvasItemList ilist
00269         # Preselection of the links on wich we might have clicked
00270         for each_item in ilist:
00271                 if isinstance(each_item,myLine):
00272                         links_selected.insert(0,each_item)
00273 
00274         for each_item in ilist:
00275                 #if each_item.rtti()==1001:
00276                 if isinstance(each_item,Box):  # I had problems while using rtti function on box
00277                         self.__moving=each_item
00278                         self.main.GetSelectWindow().UpdateInfo(each_item.GetObject())
00279 
00280                         if self.main.aCreateLinkMode.isOn(): # A remplacer avec la condition que je veux !! if mode creation connexion ON ?
00281                                 self.linkConnect.setPoints(point.x(),point.y(),point.x(),point.y())  
00282                                 self.linkConnect.setPen(QPen(Qt.blue,3))
00283                                 self.linkConnect.show()
00284 
00285                         if e.state()==Qt.ControlButton:
00286                                 if each_item in self.selection:
00287                                         self.selection.remove(each_item)
00288                                         each_item.setActive(False)
00289                                 else:
00290                                         self.selection.insert(0,each_item)
00291                                         each_item.setActive(True)
00292                         else:
00293                                 # ......................
00294                                 if each_item in self.selection:
00295                                         global timer
00296                                         timer = QTimer(self)
00297                                         self.connect(timer,SIGNAL("timeout()"),self.noMoveEventAfter)
00298                                         timer.start( 100, True )
00299                                 else:
00300                                         timer = None
00301                                         if isinstance(self.main.GetActiveDevice(),Box):
00302                                                 self.main.GetActiveDevice().setActive(False)
00303                                         self.selection = [each_item]
00304                                         each_item.setActive(True)
00305                                         self.main.SetActiveDevice(each_item)
00306                                         # deselect the active Link too:
00307                                         if self.main.GetActiveLink():
00308                                                 self.main.GetActiveLink().setActive(False)
00309                                         self.main.SetActiveLink(None)
00310                         self.canvas.update() #To redraw the activated device
00311                         return
00312 
00313         if e.state() == Qt.ShiftButton and not self.__moving:
00314                 self.selecter.setSize(1,1)
00315                 self.selecter.move(point.x(),point.y())
00316                 self.selecter.show()
00317                 return
00318 
00319         # deselect the active Link too:
00320         if self.main.GetActiveLink():
00321                 self.main.GetActiveLink().setActive(False)
00322         self.main.SetActiveLink(None)
00323         for item in self.selection:  
00324                 item.setActive(False)
00325         self.selection = []
00326         if self.__moving:
00327                 self.selection=[self.__moving]
00328                 self.__moving.setActive(True)
00329                 
00330         # Now we define wich link to select
00331         dist = 3
00332         link_selected=None
00333         for link in links_selected: #links_selected:
00334            if isinstance(link,QCanvasLine):
00335                 dl = distPoint2Line(link.startPoint(), link.endPoint(), point)
00336                 if dl < dist:
00337                         dl =dist
00338                         link_selected = link
00339         if link_selected:
00340                 self.main.panel.selectWindow.UpdateInfo(link_selected.object)
00341                 if isinstance(self.main.GetActiveLink(),myLine):
00342                         self.main.GetActiveLink().setActive(False)
00343                 self.main.SetActiveLink(link_selected)
00344                 link_selected.setActive(True)
00345                 print link_selected.GetName()
00346         self.__moving_start=point
00347         self.__moving=0
00348         
00349         self.canvas.update()  # To refresh the activated items
00350                 
00351     def contentsMouseDoubleClickEvent(self, event):
00352         point = self.inverseWorldMatrix().map(event.pos())
00353         ilist = self.canvas.collisions(point) #QCanvasItemList ilist
00354         tmp = False
00355         for each_item in ilist:
00356                 if not ( isinstance(each_item,QCanvasText) or isinstance(each_item,QCanvasLine) ):
00357                         tmp = True
00358                         break
00359         if tmp:
00360                 self.OnDeviceSelected(each_item.object)
00361                 #self.main.panel.selectWindow.UpdateInfo(device)
00362         if event.button()==2:
00363                 pdb.set_trace()
00364 
00365 
00366     def contentsMouseMoveEvent(self,e):
00367         point = self.inverseWorldMatrix().map(e.pos());
00368         global timer
00369         if timer:
00370                 timer.stop()
00371                 timer = None
00372                 print "timer stopeed"
00373         if self.selecter.isVisible():
00374                 self.selecter.setSize(point.x()-self.__moving_start.x(),point.y()-self.__moving_start.y())
00375         elif self.linkConnect.isVisible():
00376                 self.linkConnect.setPoints(self.linkConnect.startPoint().x(),self.linkConnect.startPoint().y(),point.x(),point.y())
00377                 self.canvas.update()
00378                 return
00379         elif self.selection:
00380             for item in self.selection:
00381                 item.moveBy(point.x() - self.__moving_start.x(),point.y() - self.__moving_start.y())
00382             self.__moving_start = point
00383         else:
00384                 self.setCursor(QCursor(Qt.PointingHandCursor))
00385                 #self.scrollBy((-point.x() + self.__moving_start.x()),(-point.y() + self.__moving_start.y()))
00386                 self.scrollBy(GetZoomFactor()/100*(-point.x() + self.__moving_start.x()),GetZoomFactor()/100*(-point.y() + self.__moving_start.y()))
00387         self.canvas.update()
00388     def contentsMouseReleaseEvent(self,e):
00389         self.unsetCursor()
00390         if self.selecter.isVisible():
00391                 for item in self.selecter.collisions(True):
00392                         if isinstance(item,Box):
00393                                 self.selection.append(item)
00394                                 item.setActive(True)
00395                 self.selecter.setVisible(False)
00396                 
00397         if self.linkConnect.isVisible():
00398                 point = self.inverseWorldMatrix().map(e.pos())
00399                 ilist = self.canvas.collisions(point)
00400                 for item in ilist: # We keep only Devices in the list
00401                         if isinstance(item,Box) and item.GetObject().GetName()!=self.__moving.GetObject().GetName(): 
00402                                 self.main.CreateLinkClick(self.__moving.GetObject(),item.GetObject())
00403                                 self.main.aCreateLinkMode.setOn(False)
00404                                 break;
00405                 self.linkConnect.setVisible(False)
00406         self.canvas.update()
00407 
00408 
00409     def EnableAutoZoom(self,enable=True):
00410                 if(OFF):
00411                         pass
00412                 self.autozoom = enable
00413 
00414     def ResetMacroObjects(self):
00415                 self.macroobjects = []
00416 
00417     ##
00418     #  Called on scrollevent, will redraw the visible regionarea in the zoomarea/miniaturearea window 
00419     def OnScroll(self,event=None):
00420         self.main.GetAreaWindow().DrawSystem()
00421         
00422     ##
00423     #  Get the size of the whole visual window, also what we don't see if we do not scroll
00424     def GetMaxSize(self):
00425         return self.maxWidth,self.maxHeight
00426 
00427     ##
00428     #  Returning value of the variable telling whether a chamber was found at a given location or not, MUON specific. 
00429     def IsChamberFoundAtLocation(self):
00430         return self.chamber_found_at_location
00431 
00432     ##
00433     #  Set the zoom factor, when changed by user or code. 
00434     #   
00435     #   @value - zoom value in percent.
00436     #   
00437     def SetZoomFactor(self,value):
00438         SetZoomFactor(value) # Set global zoomfactor variable
00439         self.zoom = value
00440 
00441          
00442     ##
00443     #  Return absolute number of objects in layer position.
00444     #             Absolut amount of objects on every 'layer' is saved to position the different objects in
00445     #             this layer proerly. Layers can be seen as horicontically divided reions of the screen.
00446     #             Layer 0 is in the middle, the positive axes goes downwards. The absoltue amount must be set
00447     #             before elements are positioned in this layer so that they are arranged properly.
00448     # 
00449     #       @position - id of Y layer
00450     # 
00451     #       !return - number of objects in given Y layer
00452     #         
00453     def GetAbsY(self, position):
00454         return self.__absY.get(position, 0) # return total amount, if nothing is saved, 0 is returned.
00455 
00456     ##
00457     #  Set absolute number of objects on layer position.
00458     #             See GetAbsY, too.
00459     # 
00460     #       @position - id of Y layer
00461     #       @value - number of objects in given layer
00462     #         
00463     def SetAbsY(self, position, value):
00464         self.__absY[position] = value
00465 
00466     ##
00467     #  Reset absolute number of all layers to 0.
00468     #             See GetAbsY, too
00469     #         
00470     def ResetAbsY(self):
00471         self.__absY.clear()
00472 
00473     ##
00474     #  Clear the frame and delete all visual objects on it
00475     #   
00476     def Clear(self):
00477         self.DoDeleteAll(refresh=True)
00478 
00479    
00480     ##
00481     #  If visual objects is stored with the undo/redo information, they can easily be added back to the visual window on undo/redo. This is for nodes only, as the links are to be connected to the nodes once they are added.
00482     # 
00483     #   @obj - object that will be added to the visual window
00484     #   @paintevent - whether we manually should trigger the paint event or not
00485     #   
00486     def AddToContents(self,obj,paintevent=True):
00487 
00488         #WAL_URG visWindow.contents.append(obj)
00489 
00490         if obj.GetType() == obj_NODE:
00491                 # Copy information of links connected to this node, deep copy, cause we are clearing the port list right after
00492                 tmp_portinlist = obj.GetPortList(port_IN)[:]
00493                 tmp_portoutlist = obj.GetPortList(port_OUT)[:]
00494 
00495                 obj.ClearPorts()
00496 
00497                 # 1. If only the node was undone/removed, and the links are still in the visual window (obsolete? since links cannot exist withour 2 parent nodes?)
00498 
00499                 # Then we add the links connected to the inports of this node, if any
00500                 for port in tmp_portinlist:
00501                         if port != None:
00502                                 tmp_link = self.FindByName(port.GetName())
00503                                 if tmp_link:
00504                                         self.CreateConnectedLink(tmp_link.GetObject())
00505 
00506                 # Then we add the links connected to the outports of this node, if any
00507                 for port in tmp_portoutlist:
00508                         if port != None:
00509                                 tmp_link = self.FindByName(port.GetName())
00510                                 if tmp_link:
00511                                         self.CreateConnectedLink(tmp_link.GetObject())
00512 
00513 
00514                 # 2. If we added a link to the visual window and the parent node was not here
00515                 i = 0
00516                 for itm in self.missing_parentnodes: #missing_parentnodes is a list of lists, each sublist containing to entries: [0]:link_name and [1]:node_name
00517                         if itm[1] == obj.GetName():
00518                                 tmp_link = self.FindByName(itm[0])
00519                                 if tmp_link:
00520                                         self.CreateConnectedLink(tmp_link.GetObject())
00521 
00522                                 self.missing_parentnodes.pop(i)
00523                         i += 1
00524 
00525         if paintevent:
00526                 self.paintevent(None)
00527         
00528     ##
00529     # 
00530     #   index = -1 for central device
00531     #   
00532     #   
00533     def AddNode(self,object,index=-1,portnumber=0,portIN=True):
00534         deviceInfo = object.GetObjectInfo(True)
00535         node = self.FindByName(deviceInfo[DEV_NAME])
00536         number_created = 0
00537         if not node:
00538                 node = self.CreateNode(0, 0, object,True)
00539                 number_created = 1
00540                 
00541         if index == -1:
00542                 node.move(2500,2500)
00543                 node.show()     
00544                 return (node, number_created)
00545                 
00546         if self.main.GetViewMode() == ID_PATHS_MODE:
00547                 node.move(2500,2500-40*index)
00548                 node.show()     
00549                 return (node, number_created)
00550                 
00551         parent_x, parent_y = 2500, 2500
00552         teta = pi/(portnumber+4)
00553         index += 2
00554         # x = parent_x - 300*math.cos(index*teta)
00555         # if portIN:
00556                 # y = parent_y - 200*math.sin(index*teta)  # put minus if input and plus if output 
00557         # else:
00558                 # y = parent_y + 200*math.sin(index*teta)
00559         cosinus, sinus = math.cos(index*teta),math.sin(index*teta)
00560         x_factor = 200*cosinus
00561         y_factor = 100*sinus
00562         x_delta = 0.1*x_factor
00563         y_delta = 0.1*y_factor
00564         x =  - x_factor + parent_x
00565         if portIN:
00566                 y = - y_factor + parent_y
00567         else:
00568                 y = y_factor + parent_y 
00569         node.move(x,y)
00570         node.show()
00571         while([elt.__class__ for elt in node.collisions(False)].count(QCanvasText)>1):
00572                 
00573                 x_factor += x_delta
00574                 y_factor += y_delta
00575 
00576                 x =  - x_factor + parent_x
00577                 if portIN:
00578                         y = - y_factor + parent_y
00579                         # node.move(x_factor - parent_x,y)
00580                 else:
00581                         y = y_factor + parent_y 
00582                         # node.move(x_factor - parent_x,y)
00583                 node.move(x,y)
00584         
00585         
00586         return (node, number_created)
00587 
00588     ##
00589     #  Focus on the center of the visualization window. The scroll bars are moved so that the
00590     #   center of the whole visual window is shown.     
00591     #   
00592     def Center(self):
00593         
00594         scroll_x = self.maxWidth/2 - self.width()/2
00595         scroll_y = self.maxHeight/2 - self.height()/2
00596         self.setContentsPos(scroll_x,scroll_y) #self.Scroll(scroll_x,scroll_y)
00597 
00598     ##
00599     #  Center the shown visual window so that the object in the parameter list is in center.
00600     #   The centering is done by scrolling the scrollbar to a position such that the object is in
00601     #   the center of the visual window.
00602     # 
00603     #   @obj - object which we will center to.
00604     #   
00605     def CenterToObject(self,obj):
00606         self.setContentsPos(GetZoomFactor()*25-self.width()/2,GetZoomFactor()*25-self.height()/2)
00607         return
00608         # Find size of object, to be changed as we will have to limit max-size, 
00609         # and also consider size of the name of the object
00610         pin = obj.GetPorts(port_IN)
00611         pout = obj.GetPorts(port_OUT)
00612         maxp = 0
00613         if pin > pout:
00614                 maxp = pin
00615         else:
00616                 maxp = pout
00617         if maxp < 5:
00618                 maxp = 5 #minimum size
00619         if maxp > 100:
00620                 maxp = 100 #maximum size
00621                         
00622         new_height = NODE_HEIGHT
00623         new_width = NODE_WIDTH * maxp
00624         if maxp >= 20:
00625                 new_height += maxp/20/10
00626 
00627 
00628         obj_pos = obj.GetPosition()
00629         
00630         #The object position is given using the objects position in the upper left corner.
00631         #The scroll scrolls to the position given in the upper right corner. Therefore we 
00632         #have to scroll right and down half the window size, and left and up half of the size of the object
00633         scroll_x = obj_pos.x() - (self.size().width()/2) + (obj.GetSize().width()/2)
00634         scroll_y = obj_pos.y() - (self.size().height()/2) + (obj.GetSize().height()/2)
00635         self.setContentsPos(scroll_x,scroll_y)
00636 
00637     ##
00638     #  Used only in the Zoom(...) to center to the same center of the visual window as in the previous zoom. 
00639     #   So that the objects after a zoomin event have the same relative distance between themselves and the center
00640     #   of the visual window
00641     #   
00642     def CenterToScreen(self):
00643 
00644         x, y = self.contentsX(), self.contentsY() #self.CalcUnscrolledPosition(0,0)
00645         x, y = x + self.GetSize().GetWidth()/2, y + self.GetSize().GetHeight()/2
00646 
00647         new_zoom = float(self.zoom)/100.0
00648         prev_zoom = float(self.centervalue)/100.0
00649         
00650         new_x = (float(x - self.maxWidth/2) / prev_zoom * new_zoom) + self.maxWidth/2
00651         new_y = (float(y - self.maxHeight/2) / prev_zoom * new_zoom) + self.maxHeight/2
00652 
00653         new_x,new_y = new_x - self.GetSize().width()/2, new_y - self.GetSize().height()/2
00654 
00655         new_x /= self.scrollUnit
00656         new_y /= self.scrollUnit
00657 
00658         self.setContentsPos(new_x,new_y) #self.Scroll(new_x,new_y)
00659    
00660 
00661     '''def DoScroll(self, x_upperleft,y_upperleft):
00662         """ Move the scrollbars (scroll), so that the x and y coordinates given
00663         in the parameter list is located at the upper left corner in the visible
00664         visual window.
00665 
00666         @x_upperleft - integer defining the x position in the upper left corner
00667         @y_upperleft - integer defining the y position in the upper left corner
00668         """
00669         
00670         x_upperleft /= self.scrollUnit
00671         y_upperleft /= self.scrollUnit
00672         self.setContentsPos(x_upperleft,y_upperleft) #self.Scroll(x_upperleft,y_upperleft)
00673 
00674     ##
00675     #  Scroll to position 0.
00676     #   
00677     def ScrollOutOfBounds(self):
00678 
00679         self.setContentsPos(0, 0)'''
00680 
00681     ##
00682     #  Select a device and show the links and devices connected to it.
00683     # 
00684     #             The method should be called to show a device and all links connected to it including the 
00685     #             nodes connected to these links. First, it finds all these connected elements by asking the 
00686     #             confDB instance, after that, it creates the visual objects and places them on the screen.
00687     # 
00688     #       @deviceobj - the device object that is selected, and that will be added to the visual window
00689     #       with its closest neighbors (direct neighbors)
00690     #       @clear - whether the windows should be cleared (all objects deleted)before adding the 
00691     #       new visual objects or not (for neighbour view True, for the other views False)
00692     #       @subsystemview - whether we add the visual objects in a subsystem view or not
00693     #       @treenumber_x - if this is the first visual object to be added in a tree, we need the x coordinate
00694     #       to place it away from other trees of visual objects.
00695     #       @treenumber_y - as with @treenumber_x, but for y coordinate
00696     #       @refresh - whether we should manually trigger a paint event or not
00697     # 
00698     #       !return -
00699     #         
00700     def OnDeviceSelected(self, deviceobj,clear=True,subsystemview=False,treenumber_x=0,treenumber_y=0,refresh=True):
00701         self.ZoomIn(-1,True)
00702         prev_zoom = 100
00703         ##tmp = waiter(None,"WAITING FOR ON DEVICE SLETCED",300,100)
00704         ##
00705         #  Return the number of linked nodes of the given linkList. This is a private
00706         #           method inside OnDeviceSelected(...) and hence not visible outside.
00707         # 
00708         #           @linkList - a list of link objects for a device
00709         # 
00710         #           !return - an integer telling the number of other devices this device is connected
00711         #           to in the given link list for a device
00712         #             
00713         def _CountNodes(linkList):
00714 
00715 
00716             nodes = {}
00717             for linkobj in linkList:
00718                 link = linkobj.GetObjectInfo(True) # Link already loaded with data, just retrieve it
00719                 node = link[DEV_SWITCH_FROM]    #device from
00720                 nodes[node] = node              
00721                 node = link[DEV_SWITCH_TO]      #device to
00722                 nodes[node] = node
00723             # Return all nodes (if no node is linked, there is still the node from 
00724             # which we are searching!)
00725             return max(len(nodes), 1)
00726         
00727         
00728                                 
00729         viewMode = self.main.GetViewMode()
00730         if (viewMode == ID_SUCCESSORS_MODE) or subsystemview: # neighbor or subsystem
00731             #remove all visible content in visual window
00732             if clear:
00733                     self.DoDeleteAll(refresh=False)
00734 
00735             # ADD kept object:
00736             if self.keptItems: # and not visWindow.contents:
00737                 # Move item :
00738                 for item in self.keptItems:
00739                         kept,node = self.AddNode(item, -1) #treenumber_x, treenumber_y,refresh=False)
00740                         kept.move(2400,2400) # Todo : place the item in an appropriat position
00741                         kept.show()
00742                 self.keptItems = []
00743                 
00744             # Get input links for our current Device
00745             inputLinks = deviceobj.GetLinks(False)      #Previous in path
00746             if inputLinks == False:
00747                         self.main.ShowError(str(deviceobj.GetErrorMessage()),ERR_ERROR)
00748                         # if prev_zoom != 100:
00749                                 # self.main.OnZoom(prev_zoom,False)
00750                         return ([],[])
00751 
00752             outputLinks = deviceobj.GetLinks(True)      #Next in path
00753             if outputLinks == False:
00754                         self.main.ShowError(str(deviceobj.GetErrorMessage()),ERR_ERROR)
00755                         # if prev_zoom != 100:
00756                                 # self.main.OnZoom(prev_zoom,False)
00757                         return ([],[])
00758 
00759             #if inputLinks == [] and outputLinks == [] and subsystemview:
00760             #   return ([],[])
00761          
00762             self.SetAbsY(0, 1) # set 1 object in layer 0
00763             origShape, newNodes = self.AddNode(deviceobj)#treenumber_x, treenumber_y,refresh=False) # add the first device
00764             origShape.SetExpanded(2) #Totally expanded
00765 
00766             # layer and position of the "parent" device
00767             ylayer_pos = origShape.GetLayer()
00768             node_pos = origShape.GetPosition()
00769             parent_x_pos_center = node_pos.x() + (origShape.GetSize().width()/2)
00770 
00771             #max ports
00772             #find whether maximum number of nodes are of in or out type, to correctly calculate the length in AddNode()
00773             if (deviceobj.GetPortsOut() > deviceobj.GetPortsIn()):
00774                     max_ports = deviceobj.GetPortsOut()
00775             else:
00776                     max_ports = deviceobj.GetPortsIn()
00777             
00778             if len(outputLinks) > 30 or len(inputLinks) > 30:   # we show a dialog containing the devices
00779                 if not self.inOutPutDialog:
00780                         self.inOutPutDialog = inout.Input_output(self.main,self)
00781                 self.inOutPutDialog.clear()
00782                 self.inOutPutDialog.setData(inputLinks,outputLinks,origShape)
00783                 for i in range(len(outputLinks)):
00784                         tmp_link = outputLinks[i].GetObjectInfo(True)
00785                         self.inOutPutDialog.insertOutput(tmp_link[DEV_SWITCH_TO],i)
00786 
00787                 j,factor = 1,1.0
00788                 for i in range(len(inputLinks)):
00789                         tmp_link = inputLinks[i].GetObjectInfo(True)
00790                         self.inOutPutDialog.insertInput(tmp_link[DEV_SWITCH_FROM],i)
00791                         
00792                 self.inOutPutDialog.show()
00793             else:
00794                 # Add each device in output links of the current device to the visual window, both the node and the link
00795                 position = 1
00796                 nr_out_added = 0
00797                 devices_on_output = {}
00798 
00799                 for i in range(len(outputLinks)):
00800                         tmp_link = outputLinks[i].GetObjectInfo(True)
00801                         tmp_devobj = Device(self.main.GetActiveSystem(),tmp_link[DEV_SWITCH_TO],False)
00802                         index,portnr = origShape.FindCorrespondingPortIndex(outputLinks[i].GetPortFrom(),outputLinks[i].GetPortTypeFrom(),port_OUT)
00803                         port_pos = origShape.GetPortPosition(index,port_OUT)
00804                         shape,newNodes = self.AddNode(tmp_devobj,index,len(outputLinks),False)
00805                         
00806                         self.CreateConnectedLink(outputLinks[i])
00807                 # Add each device in input links of the current device to the visual window, both the node and the link
00808                 position = 1
00809                 nr_in_added = 0
00810                 devices_on_input = {}
00811                 for i in range(len(inputLinks)):
00812                         tmp_link = inputLinks[i].GetObjectInfo(True)
00813                         tmp_devobj = Device(self.main.GetActiveSystem(),tmp_link[DEV_SWITCH_FROM],False)
00814                         #shape,newNodes = self.AddNode(tmp_devobj,position,-1,False,len(inputLinks),node_pos.x,node_pos.y,refresh=False) #-1 from parentnode (y layer -1)
00815                         index,portnr = origShape.FindCorrespondingPortIndex(inputLinks[i].GetPortTo(),inputLinks[i].GetPortTypeTo(),port_IN)
00816                         port_pos = origShape.GetPortPosition(index,port_IN)
00817                         print tmp_devobj.GetName(),"  ---> ",index,portnr,deviceobj.GetPortsIn()
00818                         shape,newNodes = self.AddNode(tmp_devobj,index,len(inputLinks),True)
00819 
00820                         self.CreateConnectedLink(inputLinks[i])
00821 
00822                 if not subsystemview:
00823                         self.Select(origShape,refresh=False)
00824                         self.CenterToObject(origShape)
00825 
00826         elif viewMode == ID_PATHS_MODE: # Path view
00827             #Prepare for path view; clear if needed
00828             if clear:
00829                     self.DoDeleteAll(refresh=False)
00830             self.Center()
00831             inputLinks,outputLinks = [],[]
00832             # do not set anything here yet, we will do that in the pathselect method when user chooses a path
00833         
00834         else: #dynamic link view
00835             if clear:
00836                     self.DoDeleteAll(refresh=False)
00837 
00838             self.SetAbsY(0, 1)
00839             origShape, newNodes = self.AddNode(deviceobj, 0, 0,refresh=False) # add current device to visual window
00840 
00841             if origShape != None: #it should have been added, this should never go wrong
00842                     self.ShowNeighbourLinks(origShape,origShape.GetObject(),refresh=False) #show neighbours of device
00843                     self.CenterToObject(origShape)
00844             else:
00845                     self.Center()
00846 
00847             if not subsystemview: # select current device
00848                     self.Select(origShape,refresh=False)
00849                     
00850             inputLinks,outputLinks = [],[]
00851         
00852         # if prev_zoom != 100:
00853                 # self.main.OnZoom(prev_zoom,False)
00854         
00855         if refresh:
00856                 self.canvas.update() #Refresh() # in case we need to trigger paint event manually
00857         return (inputLinks,outputLinks)
00858 
00859     ##
00860     #  Select a device and show a path this device participates in. The user chooses the path from
00861     #   a list in a pop-up window.
00862     #             
00863     #         This method should be called to show paths devices participate at. It first retrieves all
00864     #         the necessary information of the nodes and links in the path and after that it creates and
00865     #         positions the corresponding visual objects on the screen.
00866     # 
00867     #         @my_device - the current device to view paths for
00868     #         @pathNr - id number(integer) of the path to be selected in the pop-up path view window
00869     #   @paintevent - whether we should trigger paint event manually or not
00870     #         
00871     def OnPathSelected(self, my_device, pathNr,paintevent=True):
00872 
00873         path = my_device.GetSpecificPathInfo(pathNr) # get path information about the chosen path
00874         deviceInfo = my_device.GetObjectInfo(True)
00875 
00876         self.DoDeleteAll(refresh=False) # clear window
00877 
00878         #set up path visually
00879         pLen = len(path)-1
00880         pL = len(path)
00881         self.ResetAbsY()
00882         shapeBefore = None
00883 
00884         pathposition = 0.0
00885         index = 0
00886         for i in range(pL): #each node/device in path
00887 
00888             if path[i]['reversed'] == True:
00889                 device1 = path[i][DEV_SWITCH_TO]
00890                 device2 = path[i][DEV_SWITCH_FROM]
00891             else:
00892                 device1 = path[i][DEV_SWITCH_FROM]
00893                 device2 = path[i][DEV_SWITCH_TO]
00894 
00895                 
00896             tmp_device_1 = Device(deviceInfo[DEV_SYSTEM],device1,False)
00897             shape_1, newNodes_1 = self.AddNode(tmp_device_1, index) #0, pathposition) #(i - pL/2)+1,refresh=False)
00898             pathposition += 0.5; index += 1
00899             print tmp_device_1.GetName()
00900             
00901             tmp_device_2 = Device(deviceInfo[DEV_SYSTEM],device2,False)
00902             shape_2, newNodes_2 = self.AddNode(tmp_device_2, index) #0, pathposition) # i - pL/2,refresh=False)
00903             pathposition += 0.5; index += 1
00904             print tmp_device_2.GetName()
00905             
00906                
00907             tmp_link = Link(path[i][DEV_SYSTEM],path[i][DEV_LINK],False,False)
00908             self.CreateConnectedLink(tmp_link)
00909 
00910 
00911         self.Select(self.FindByName(deviceInfo[DEV_NAME]),refresh=False)
00912 
00913         if paintevent:
00914                 self.paintevent(None)
00915                 
00916         self.canvas.update()
00917 
00918     ##
00919     #  Respond to a keypress event.
00920     # 
00921     #             We make the arrow keys move the selected object(s) by one pixel in
00922     #             the given direction.
00923     #         
00924     def OnKeyEvent(self, event):
00925         
00926         key = event.GetKeyCode()
00927 
00928         if key == WXK_UP:
00929             self._MoveObject(0, -1)
00930         elif key == WXK_DOWN:
00931             self._MoveObject(0, 1)
00932         elif key == WXK_LEFT:
00933             self._MoveObject(-1, 0)
00934         elif key == WXK_RIGHT:
00935             self._MoveObject(1, 0)
00936         else:
00937             event.Skip()
00938 
00939     ##
00940     #  Respond to the user clicking in our visual window.
00941     #             How we respond depends on the currently selected tool and
00942     #       on the mouse event.
00943     # 
00944     #       @event - contains information such as which mouse event and where the event
00945     #       occured (coordinates)
00946     #         
00947     def OnMouseEvent(self, event):
00948         
00949         if not self.main.GetCdb(): #not connected to db
00950                 return False
00951 
00952         if not (event.Dragging() or event.LeftUp() or event.LeftDown() or event.Moving()):
00953             return
00954 
00955         # LHCb system - our LCHb illustration image map
00956         if (self.levelzoom == 0) and (event.Moving() or event.LeftUp() or event.LeftDown()): #valid mouse events
00957                 #w_and_h = [width,height,x,y_offset_from_middle_of_window,MACRO_ID,subsystem name]
00958                 w_and_h = [[55,25,50,-2,"","VELO"],[30,80,105,-1,"","RICH1"],[15,35,137,-1,"","TT"],[40,50,279,30,"","OT"],[40,13,279,-2,"","IT"],[40,50,279,-32,"","OT"],[60,160,319,-1,"","RICH2"],[12,140,379,-1,"1","MUON"],[6,75,391,-40,"","PRS"],[6,75,391,40,"","PUS"],[20,150,397,-1,"","ECAL"],[42,166,417,-1,"","HCAL"],[29,180,459,-1,"2","MUON"],[30,195,488,-1,"3","MUON"],[30,210,518,-1,"4","MUON"],[30,220,548,-1,"5","MUON"],[70,21,232,-155,"","ECS"],[70,20,302,-155,"","TFC"],[65,20,372,-155,"","DAQ"],[70,24,232,-131,"","L0DU"],[70,24,302,-131,"","L0MUON"],[65,24,372,-131,"","L0CALO"]]
00959                 new_x,new_y = self.contentsX(), self.contentsY() #self.CalcUnscrolledPosition(0,0)
00960                 my_w,my_h = self.GetSizeTuple() #width and height
00961                 new_x = new_x + my_w/2
00962                 new_y = new_y + my_h/2
00963 
00964                 if self.mem_image != None: # if LHCb illustration already loaded; set up the image map
00965                         image_w, image_h = self.mem_image.GetSizeTuple()
00966         
00967                         startx = new_x-image_w/2
00968                         starty = new_y
00969 
00970                         mouse_x = event.GetX()
00971                         mouse_y = event.GetY()
00972                         mouse_x, mouse_y = self.contentsX() + mouse_x, self.contentsY() + mouse_y  #self.CalcUnscrolledPosition(mouse_x,mouse_y)
00973 
00974                         i = 0
00975                         oversystem = False
00976                         for subsystem in w_and_h:
00977                                 x = startx + subsystem[2]
00978                                 y = starty - subsystem[1]/2 + subsystem[3]
00979                                 w = subsystem[0]
00980                                 h = subsystem[1]
00981                                 if mouse_x >= x and mouse_x <= x+w and mouse_y >= y and mouse_y <= y+h:
00982                                         oversystem = True
00983                                         self.SetCursor(wxStockCursor(wxCURSOR_HAND))
00984                                         if event.Moving():
00985                                                 if self.prevsystemover != str(subsystem[5] + " " + subsystem[4]):
00986                                                         self.prevsystemover = str(subsystem[5] + " " + subsystem[4])
00987                                                         self.Refresh()
00988                                                 dc = wxClientDC(self)
00989                                                 dc.SetBrush(wxBrush(Qt.white, wxSOLID)) #to be changed to another colour
00990                                                 self.PrepareDC(dc)
00991                                                 dc.BeginDrawing()
00992                                                 dc.DrawText(str(subsystem[5]) + " " + str(subsystem[4]),new_x-my_w/2,new_y-my_h/2)
00993                                                 dc.EndDrawing()
00994                                         elif event.LeftUp():
00995                                                 # if we click -> move to next leve in selected subsystem
00996                                                 self.main.SetActiveSystem(subsystem[5],"visual") #NB! only valid systems
00997                                                 self.SetLevelSelections(str(subsystem[4]),subsystem[5],1,reset=True)
00998                                                 self.SetLevelZoom(1) #to next level
00999                                         break
01000                                 i += 1
01001                         if not oversystem or event.LeftUp():
01002                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01003 
01004                         return # Ignore mouse movement without click/drag.
01005         # level 1 subsystem -> only set up for muon so far. -> muon station
01006         # if you want to add a specific levelzoom for a subsystem, add it before the elif-statement below, at the same level
01007         elif self.levelzoom == 1 and self.main.GetActiveSystem() == "MUON":
01008                 if event.LeftUp():
01009                         mousePt = self._GetEventCoordinates(event)
01010 
01011                         obj = self._GetObjectAt(mousePt,True)
01012                         if (obj != None):
01013                                 self.macroobjects = [] # we reset the global macro objects list
01014                                 #station = self.levelselections[self.main.GetActiveSystem()][0] #try error
01015                                 self.SetLevelSelections(str(obj.GetMacroID()),self.main.GetActiveSystem(),2)
01016                                 self.SetLevelZoom(2) #change level
01017                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01018                 elif event.Moving():
01019                         mousePt = self._GetEventCoordinates(event)
01020 
01021                         obj = self._GetObjectAt(mousePt,True)
01022                         if (obj != None):
01023                                 # The user is moving over a clickable object
01024                                 self.SetCursor(wxStockCursor(wxCURSOR_HAND))
01025                         else:
01026                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01027 
01028                 return
01029         # level 2 subsystem -> muon quadrant
01030         elif self.levelzoom == 2 and self.main.GetActiveSystem() == "MUON":
01031                 if event.LeftUp():
01032                         mousePt = self._GetEventCoordinates(event)
01033 
01034                         obj = self._GetObjectAt(mousePt,True)
01035                         if (obj != None):
01036                                 self.macroobjects = [] # we reset the global macro objects list
01037                                 self.SetLevelSelections(str(obj.GetMacroID()),"MUON",3)
01038                                 self.SetLevelZoom(3) #change level
01039                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01040                 elif event.Moving():
01041                         mousePt = self._GetEventCoordinates(event)
01042 
01043                         obj = self._GetObjectAt(mousePt,True)
01044                         if (obj != None):
01045                                 self.SetCursor(wxStockCursor(wxCURSOR_HAND))
01046                         else:
01047                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01048 
01049                 return
01050         # level 3 subsystem -> double gap view in Muon
01051         elif self.levelzoom == 3 and self.main.GetActiveSystem() == "MUON":
01052                 if event.LeftUp():
01053                         mousePt = self._GetEventCoordinates(event)
01054 
01055                         obj = self._GetObjectAt(mousePt,True)
01056                         if (obj != None):
01057                                 self.macroobjects = [] # we reset the global macro objects list
01058                                 self.SetLevelSelections(str(obj.GetMacroID()),"MUON",5)
01059                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01060                 elif event.Moving():
01061                         mousePt = self._GetEventCoordinates(event)
01062 
01063                         obj = self._GetObjectAt(mousePt,True)
01064                         if (obj != None):
01065                                 self.SetCursor(wxStockCursor(wxCURSOR_HAND))
01066                         else:
01067                                 self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
01068 
01069                 return
01070 
01071 
01072         # The rest is handling mouse events in device level (level -1)
01073         feedbackType = feedback_RECT
01074         action       = self.SelectByRectangle
01075         actionParam  = param_RECT
01076         selecting    = True
01077         dashedLine   = True
01078 
01079         if event.LeftDown():
01080             mousePt = self._GetEventCoordinates(event)
01081             if selecting:
01082                 obj, handle = self._GetObjectAndSelectionHandleAt(mousePt)
01083 
01084             if selecting and (obj != None) and (handle != handle_NONE) and ((self.curTool == tool_EDIT and obj.GetType() == obj_LINK) or (obj.GetType() == obj_NODE)): #only in creation mode
01085 
01086                 # The user clicked on an objects selection handle.  Let the
01087                 # user resize the clicked-on object.
01088 
01089                 self.dragMode     = drag_RESIZE
01090                 self.resizeObject = obj
01091 
01092                 if obj.GetType() in [obj_LINE, obj_LINK]:
01093                     self.resizeFeedback = feedback_LINE
01094                     pos  = obj.GetPosition()
01095                     startPt = QPoint(pos.x + obj.GetStartPt().x,
01096                                       pos.y + obj.GetStartPt().y)
01097                     endPt   = QPoint(pos.x + obj.GetEndPt().x,
01098                                       pos.y + obj.GetEndPt().y)
01099                     if handle == handle_START_POINT:
01100                         self.resizeAnchor  = endPt
01101                         self.resizeFloater = startPt
01102                         self.startpointsel = True
01103                         self.main.ShowError("You have chosen the start point of the link.",ERR_INFORMATION)
01104                     else:
01105                         self.resizeAnchor  = startPt
01106                         self.resizeFloater = endPt
01107                         self.startpointsel = False
01108                         self.main.ShowError("You have chosen the end point of the link.",ERR_INFORMATION)
01109                 else:
01110                     self.resizeFeedback = feedback_RECT
01111                     pos  = obj.GetPosition()
01112                     size = obj.GetSize()
01113                     topLeft  = QPoint(pos.x, pos.y)
01114                     topRight = QPoint(pos.x + size.width, pos.y)
01115                     botLeft  = QPoint(pos.x, pos.y + size.height)
01116                     botRight = QPoint(pos.x + size.width, pos.y + size.height)
01117 
01118                     if handle == handle_TOP_LEFT:
01119                         self.resizeAnchor  = botRight
01120                         self.resizeFloater = topLeft
01121                     elif handle == handle_TOP_RIGHT:
01122                         self.resizeAnchor  = botLeft
01123                         self.resizeFloater = topRight
01124                     elif handle == handle_BOTTOM_LEFT:
01125                         self.resizeAnchor  = topRight
01126                         self.resizeFloater = botLeft
01127                     elif handle == handle_BOTTOM_RIGHT:
01128                         self.resizeAnchor  = topLeft
01129                         self.resizeFloater = botRight
01130 
01131                 self.curPt = mousePt
01132                 self.resizeOffsetX = self.resizeFloater.x - mousePt.x
01133                 self.resizeOffsetY = self.resizeFloater.y - mousePt.y
01134                 endPt = QPoint(self.curPt.x + self.resizeOffsetX,
01135                                 self.curPt.y + self.resizeOffsetY)
01136                 self._DrawVisualFeedback(self.resizeAnchor, endPt,
01137                                          self.resizeFeedback, False)
01138 
01139             elif selecting and (self._GetObjectAt(mousePt) != None):
01140 
01141                 # The user clicked on an object to select it.  If the user
01142                 # drags, he/she will move the object.
01143 
01144                 #distinguish between device and link, a link can be selected but not appear in the devicelist in selectpanel
01145 
01146                 obj = self._GetObjectAt(mousePt)
01147                 if obj not in self.selection:
01148                     # The user clicked on a new object
01149                     if event.ControlDown() == False:
01150                         self.Select(obj,refresh=True)
01151                     else: #controlkey was down
01152                         self.Select(obj,True,refresh=True) #add to selection    
01153                 elif obj in self.selection and event.ControlDown() == True:
01154                         self.Deselect(obj,refresh=True)
01155 
01156                 self.dragMode = drag_MOVE
01157                 self.moveOrigin = mousePt
01158                 self.curPt      = mousePt
01159                 self._DrawObjectOutline(0, 0)
01160 
01161             elif selecting and (self._GetObjectAt(mousePt) == None) and event.ControlDown() == True:
01162                 #clicked in the visual window where no object is, when holding down Ctrl : missed object on click
01163                 self.dragMode = drag_MOVE
01164                 self.moveOrigin = mousePt
01165                 self.curPt      = mousePt
01166                 self._DrawObjectOutline(0, 0)
01167                 self.main.ResetActiveObjects()
01168             else:
01169                 # The user is dragging out a selection rect or new object.
01170                 self.dragOrigin = mousePt
01171                 self.curPt      = mousePt
01172                 self.SetCursor(wxCROSS_CURSOR)
01173                 self.CaptureMouse()
01174                 self._DrawVisualFeedback(mousePt, mousePt, feedbackType,
01175                                          dashedLine)
01176                 self.dragMode = drag_DRAG
01177                 self.main.ResetActiveObjects()
01178             event.Skip()
01179             return
01180 
01181         if event.Dragging():
01182             if self.dragMode == drag_RESIZE:
01183 
01184                 # We are resizing an object.
01185 
01186                 mousePt = self._GetEventCoordinates(event)
01187                 if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y): #we dragged away from last position
01188                     if self.curTool == tool_EDIT: #only in creation mode
01189                             #Know whether we "resized" to a node -> moved selection part to a node
01190                             dc = wxClientDC(self)
01191                             self.PrepareDC(dc)
01192                             dc.BeginDrawing()
01193 
01194                             dc.SetPen(wxPen(wxRED, 1, wxSOLID))
01195 
01196                             if self.resizeObject.GetType() == obj_LINK:
01197                                 obj = self._GetObjectAt(QPoint(mousePt.x,mousePt.y))
01198                                 if obj and obj.GetType() != obj_LINK:
01199                                         if obj != self.prevseldragobj and self.prevseldragobj != None: #deselect prev
01200                                                 self.prevseldragobj.Draw(dc,draw_NORMAL,self.zoom >= 65,self.zoom >= 50)
01201 
01202                                         self.prevseldragobj = obj
01203                                         obj.Draw(dc,draw_NORMAL,self.zoom >= 65,self.zoom >= 50,False)
01204                                 else:
01205                                         if self.prevseldragobj != None: #deselect prev
01206                                                 self.prevseldragobj.Draw(dc,draw_NORMAL,self.zoom >= 65,self.zoom >= 50)
01207                                                 self.prevseldragobj = None
01208 
01209                             dc.EndDrawing()
01210 
01211                     # We draw a visual feedback line or rectangle instead of the object itself
01212                     # Erase previous visual feedback.
01213                     endPt = QPoint(self.curPt.x + self.resizeOffsetX,
01214                                     self.curPt.y + self.resizeOffsetY)
01215                     self._DrawVisualFeedback(self.resizeAnchor, endPt,
01216                                              self.resizeFeedback, False)
01217                     self.curPt = mousePt
01218                     # Draw new visual feedback.
01219                     endPt = QPoint(self.curPt.x + self.resizeOffsetX,
01220                                     self.curPt.y + self.resizeOffsetY)
01221                     self._DrawVisualFeedback(self.resizeAnchor, endPt,
01222                                              self.resizeFeedback, False)
01223 
01224 
01225             elif self.dragMode == drag_MOVE:
01226 
01227                 # We are moving a selected object.
01228 
01229                 mousePt = self._GetEventCoordinates(event)
01230                 if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y):
01231                     # Erase previous visual feedback.
01232                     self._DrawObjectOutline(self.curPt.x - self.moveOrigin.x,
01233                                             self.curPt.y - self.moveOrigin.y)
01234                     self.curPt = mousePt
01235                     # Draw new visual feedback.
01236                     self._DrawObjectOutline(self.curPt.x - self.moveOrigin.x,
01237                                             self.curPt.y - self.moveOrigin.y)
01238 
01239             elif self.dragMode == drag_DRAG:
01240                     # We are dragging out a new object or selection rect.
01241 
01242                     mousePt = self._GetEventCoordinates(event)
01243                     if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y):
01244                         # Erase previous visual feedback.
01245                         self._DrawVisualFeedback(self.dragOrigin, self.curPt,
01246                                              feedbackType, dashedLine)
01247                         self.curPt = mousePt
01248                         # Draw new visual feedback.
01249                         self._DrawVisualFeedback(self.dragOrigin, self.curPt,
01250                                                  feedbackType, dashedLine)
01251             event.Skip()
01252             return
01253 
01254         if event.LeftUp():
01255             if self.dragMode == drag_RESIZE: 
01256 
01257                 mousePt = self._GetEventCoordinates(event)
01258                 # Erase last visual feedback.
01259                 endPt = QPoint(self.curPt.x + self.resizeOffsetX,
01260                                 self.curPt.y + self.resizeOffsetY)
01261                 self._DrawVisualFeedback(self.resizeAnchor, endPt,
01262                                          self.resizeFeedback, False)
01263 
01264                 resizePt = QPoint(mousePt.x + self.resizeOffsetX,
01265                                    mousePt.y + self.resizeOffsetY)
01266 
01267                 if (self.resizeFloater.x != resizePt.x) or \
01268                    (self.resizeFloater.y != resizePt.y):
01269                    self._ResizeObject(self.resizeObject,
01270                                       self.resizeAnchor,
01271                                       self.resizeFloater,
01272                                       resizePt)
01273                 else:
01274                     pass
01275                     self.Refresh() # Clean up after empty resize.
01276 
01277 
01278                 # We are resizing an object.
01279                 if self.curTool == tool_EDIT: #only in creation mode
01280                     #Know whether we "resized" to a node -> moved selection part to a node
01281                     dc = wxClientDC(self)
01282                     self.PrepareDC(dc)
01283                     dc.BeginDrawing()
01284 
01285                     if self.resizeObject.GetType() == obj_LINK:
01286                         obj = self._GetObjectAt(QPoint(mousePt.x,mousePt.y))
01287                         if obj and obj.GetType() != obj_LINK:
01288                                 #self.resizeObject
01289                                 obj.Draw(dc,draw_NORMAL,self.zoom >= 65,self.zoom >= 50,False)
01290                                 self.main.ModifyLinkClick(None,self.resizeObject.GetObject(),self.startpointsel,obj.GetObject())
01291 
01292                         else:
01293                                 pass
01294 
01295                     self.prevseldragobj = None
01296                     dc.EndDrawing()
01297                     self.Refresh()
01298 
01299             elif self.dragMode == drag_MOVE:
01300 
01301                 # We are moving a selected object.
01302 
01303                 mousePt = self._GetEventCoordinates(event)
01304                 # Erase last visual feedback.
01305                 self._DrawObjectOutline(self.curPt.x - self.moveOrigin.x,
01306                                         self.curPt.y - self.moveOrigin.y)
01307                 if (self.moveOrigin.x != mousePt.x) or \
01308                    (self.moveOrigin.y != mousePt.y):
01309                     self._MoveObject(mousePt.x - self.moveOrigin.x,
01310                                      mousePt.y - self.moveOrigin.y)
01311                 else:
01312                     pass
01313 
01314             elif self.dragMode == drag_DRAG:
01315                 # We are dragging out a new object or selection rect.
01316 
01317                 mousePt = self._GetEventCoordinates(event)
01318                 # Erase last visual feedback.
01319                 self._DrawVisualFeedback(self.dragOrigin, self.curPt,
01320                                          feedbackType, dashedLine)
01321                 self.ReleaseMouse()
01322                 self.SetCursor(wxSTANDARD_CURSOR)
01323                 # Perform the appropriate action for the current tool.
01324                 if actionParam == param_RECT:
01325                     x1 = min(self.dragOrigin.x, self.curPt.x)
01326                     y1 = min(self.dragOrigin.y, self.curPt.y)
01327                     x2 = max(self.dragOrigin.x, self.curPt.x)
01328                     y2 = max(self.dragOrigin.y, self.curPt.y)
01329 
01330                     startX = x1
01331                     startY = y1
01332                     width  = x2 - x1
01333                     height = y2 - y1
01334 
01335                     if not selecting:
01336                         if ((x2-x1) < 8) or ((y2-y1) < 8): return # Too small.
01337 
01338                     action(x1, y1, x2-x1, y2-y1)
01339                 elif actionParam == param_LINE:
01340                     action(self.dragOrigin.x, self.dragOrigin.y,
01341                            self.curPt.x, self.curPt.y)
01342             self.dragMode = drag_NONE # We have finished with this mouse event.
01343             event.Skip()
01344 
01345 
01346     ##
01347     #  Respond to a double-click in the visual window. Only used for device level (-1)
01348     # 
01349     #   @event - mouse event information
01350     #   @paintevent - whether we should manually trigger a paint event or not
01351     #         
01352     def OnDoubleClickEvent(self, event=None,paintevent=True):
01353         
01354         mousePt = self._GetEventCoordinates(event)
01355         obj = self._GetObjectAt(mousePt)
01356         if obj == None: 
01357                 return
01358         
01359         # Let the user edit the given object.
01360         if ((self.main.GetViewMode() != self.main.GetPrevView()) or self.main.GetViewMode() == ID_SUCCESSORS_MODE or self.main.GetViewMode() == ID_PATHS_MODE):
01361                 # Change view; needed for UNDO/REDO to know whether we can paste objects in visual window or not
01362                 self.main.SetPrevView(self.main.GetViewMode())
01363                 self.main.WhenChangeView()
01364 
01365 
01366         if obj.GetType() == obj_NODE:
01367             if self.main.GetViewMode() == ID_DYNAMIC_MODE:
01368                 self.ShowNeighbourLinks(obj,obj.GetObject(),refresh=False)
01369             elif self.main.GetViewMode() == ID_SUBSYSTEM_MODE:
01370                         #self.main.ViewSubSystem(obj.GetObject().GetName(),refresh=False)
01371                         #self.Select(obj,refresh=False)
01372                         self.OnDeviceSelected(obj.GetObject(),False,True,refresh=False) 
01373                         #set last parameter her to False if we want to expand/collapse with subsystem
01374                         self.CenterToObject(obj)
01375             elif self.main.GetViewMode() == ID_PATHS_MODE:
01376                         self.main.GetSelectWindow().UpdatePath(obj.GetObject())
01377                 
01378             else: #Neighbor view
01379                 self.main.GetSelectWindow().UpdateInfo(obj.GetObject())
01380                 self.OnDeviceSelected(obj.GetObject(),refresh=False)
01381 
01382         elif obj.GetType() == obj_TEXT: # Not used
01383             pass
01384             
01385         else:
01386             pass
01387 
01388         if paintevent:
01389                 self.paintevent(None)
01390 
01391     ##
01392     #  To make the choice of link type to view have immediate effect in the
01393     #       visual window. If the user chooses to view a given link type, all links
01394     #       of other link types are removed for visual display. If the user chooses to
01395     #       view all link types nothing happens before next time the user chooses something
01396     #       to display (because we do not know what the user would like to view)
01397     # 
01398     #       We do not need any parameters as the link type (name) is taken care of in a member
01399     #       varible in CdbVis module.
01400     # 
01401     #       !return - False if action not taken because then would all objects on the screen disappear, True if successful
01402     #   
01403     def ViewOnlyLinksOfGivenType(self):
01404         print "restricted: " + str(self.main.IsLinkTypeRestricted())
01405 
01406         tbd_links = []
01407         total_links = 0
01408         tbd_devs = []
01409 
01410         linktype = self.main.GetRestrictedLinkType()
01411         i = 0
01412         while i < len(visWindow.contents):
01413                 my_itm = visWindow.contents[i]
01414                 if my_itm.GetObject().__class__ == Link:
01415                         if my_itm.GetObject().GetType() != linktype:
01416                                 tbd_links.append(my_itm)
01417                                 my_itm.show()
01418                         else:
01419                                 my_itm.hide()
01420                         total_links += 1
01421                 i += 1
01422 
01423         if (len(tbd_links) == total_links):
01424                 self.main.ShowError("None of the links that are shown are of the given link type, it would therefore have resulted in an empty visual window, and the choice was skipped.",ERR_INFORMATION,True)
01425                 return False
01426 
01427         # now it is time to check the devices, if they do not have any connections left..we remove them
01428         i = 0
01429         # while i < len(visWindow.contents):
01430                 # my_itm = visWindow.contents[i]
01431                 # if my_itm.GetObject().__class__ == Device and my_itm.GetName() != self.main.GetActiveDevice():
01432                         # typelist = map(Link.GetType,my_itm.GetLinks())
01433                         # if :
01434                                 # self.DoDeleteObj(my_itm.GetName(),False,refresh=False)
01435                                 # continue
01436                 # i += 1
01437 
01438     ##
01439     #  Show or hide the neighbor objects of a selected object in the visual window; and
01440     #       the links between them. If the neighbors are shown; the links to them will be collapsed
01441     #       and the neighbors removed from visual window when calling this method, if they are hidden;
01442     #       the links to them will be expanded and they will be shown.
01443     # 
01444     #       @origShape - the drawing object that we want to view the neighbors for
01445     #       @deviceobj - the data object for the drawing object we want to view neighbors for
01446     #       @refresh - whether we should trigger a paint event manually or not.
01447     #   
01448     def ShowNeighbourLinks(self,origShape,deviceobj,refresh=True):
01449         
01450         if GetZoomFactor() != 100:
01451                 prev_zoom = GetZoomFactor()
01452                 self.main.OnZoom(100,False)
01453         else:
01454                 prev_zoom = 100
01455 
01456         
01457         ##
01458         #  Return the number of linked nodes of the given linkList. This is a private
01459         #           method inside ShowNeighborLinks(...) and hence not visible outside.
01460         # 
01461         #           @linkList - a list of link objects for a device
01462         # 
01463         #           !return - an integer telling the number of other devices this device is connected
01464         #           to in the given link list for a device
01465         #             
01466         def _CountNodes(linkList):
01467 
01468             nodes = {}
01469             for linkobj in linkList:
01470                 link = linkobj.GetObjectInfo(True)
01471                 node = link[DEV_SWITCH_FROM]
01472                 nodes[node] = node              
01473                 node = link[DEV_SWITCH_TO]
01474                 nodes[node] = node
01475                 
01476             # Return all nodes (if no node is linked, there is still the node from 
01477             # which we are searching!)
01478             return max(len(nodes), 1)
01479         
01480         
01481         cdb = self.main.GetCdb()
01482 
01483         #Get position of parent node
01484         ylayer_pos = origShape.GetLayer()
01485         node_pos = origShape.GetPosition()
01486 
01487         #Number of ingoing links
01488         inputLinks = deviceobj.GetLinks(False)  #Previous in path
01489         if inputLinks == False:
01490                 self.ShowError(str(deviceobj.GetErrorMessage()),ERR_ERROR)
01491                 if prev_zoom != 100:
01492                         self.main.OnZoom(prev_zoom,False)
01493                 return ([],[])
01494 
01495         #Number of outgoing links
01496         outputLinks = deviceobj.GetLinks(True)  #Next in path
01497         if outputLinks == False:
01498                 self.ShowError(str(deviceobj.GetErrorMessage()),ERR_ERROR)
01499                 if prev_zoom != 100:
01500                         self.main.OnZoom(prev_zoom,False)
01501                 return ([],[])
01502         
01503         #max ports
01504         #find whether maximum number of nodes are of in or out type, to correctly calculate the length in AddNode()
01505         if (deviceobj.GetPortsOut() > deviceobj.GetPortsIn()):
01506             max_ports = deviceobj.GetPortsOut()
01507         else:
01508             max_ports = deviceobj.GetPortsIn()
01509 
01510 
01511 
01512         ### COLLAPSE/EXPAND CODE ###
01513         ##
01514         # Count whether we have 0 or many (n > 0) connections for a node. We only count
01515         #               connections to other nodes than the parent; we need to do this in order to know
01516         #               whether the node is fully or partially expanded; since it is only the links
01517         #               to the parent node that are visible after a call to ShowNeighbourLinks(...)
01518         #               Private method for ShowNeighbourLinks(...).
01519         # 
01520         #               Rule: We cannot remove links from devices connected to a collapsing device; if
01521         #               they are not collapsed and connected to other devices as well.
01522         # 
01523         #               @selfobj - parent object; the device that we wanted to see the neighbors of
01524         #               @portlist - the port list for a neighbor node of the parent device (the one we want
01525         #               to view the neighbors of)
01526         # 
01527         #               !return - -1 if the node/device contain connections to other nodes as well, 0 if the
01528         #               node is only connected to the parent device here.
01529         #               
01530         def countConnections(selfobj,portlist): 
01531                 
01532                 for item in portlist:
01533                         if item != None and (item.GetObject().GetNodeTo() != selfobj.GetName() and item.GetObject().GetNodeFrom() != selfobj.GetName()): #connections to parent we want to collapse doesnt count
01534                                 return -1
01535 
01536                 return 0
01537 
01538         ##
01539         #  If we are collapsing links to neighbors; both the links and the neighbors will
01540         #               be removed from visual window. This method removes links that are to be collapsed;
01541         #               between the parent device (the device that was double-clicked) and a child device.
01542         # 
01543         #               @obj - the child device; that are about to be collapsed
01544         #               @portlist - list of links for the parent-device that is going to be collapsed
01545         #               @porttype - whether we are removing links going "IN" to the child device
01546         #               or "OUT" from the child device
01547         #               
01548         def removeConnection(obj,portlist,porttype):
01549                 
01550                 i = 0
01551                 if porttype == "IN":
01552                         for item in portlist:
01553                                 if item != None:
01554                                         if item.GetObject().GetNodeFrom() == obj.GetName(): # link going to parent -> remove
01555                                                 tmp = portlist.pop(i)
01556                                                 portlist.insert(i,None)
01557                                                 if item in self.selection:
01558                                                         self.selection.remove(item)
01559                                                 if item in visWindow.contents:
01560                                                         visWindow.contents.remove(item)
01561                                                                 
01562                                 i += 1
01563 
01564                 elif porttype == "OUT":
01565                         for item in portlist:
01566                                 if item != None:
01567                                         if item.GetObject().GetNodeTo() == obj.GetName():
01568                                                 tmp = portlist.pop(i)
01569                                                 portlist.insert(i,None)
01570                                                 if item in self.selection:
01571                                                         self.selection.remove(item)
01572                                                 if item in visWindow.contents:
01573                                                         visWindow.contents.remove(item)
01574         
01575                                 
01576                                 i += 1
01577         
01578 
01579         if origShape.GetExpanded() == 2: #totally expanded: we will need to collapse.
01580                 tbd_content = []                
01581                 tmp_collapsed = 0 #if we can not remove a node connection because of further linking to other devices,
01582                                   #this one is set to 1, partially collapsed/expanded
01583                                   
01584                 for lnk in inputLinks: #ie. the parent node is the outputNode, we check from-nodes to the parent node
01585                         visobj = self.FindByName(lnk.GetNodeFrom())
01586                         visparent = self.FindByName(lnk.GetNodeTo())
01587                         vislink = self.FindByName(lnk.GetName())
01588                         if visobj != None: #object found
01589                                 if (visobj.GetExpanded() == 0) \
01590                                         or (visobj.GetExpanded() == 2 \
01591                                         and countConnections(visparent,visobj.GetPortList(port_IN)) == 0 \
01592                                         and countConnections(visparent,visobj.GetPortList(port_OUT)) == 0) \
01593                                         or (visobj.GetExpanded() == 1 \
01594                                         and countConnections(visparent,visobj.GetPortList(port_IN)) == 0 \
01595                                         and countConnections(visparent,visobj.GetPortList(port_OUT)) == 0):
01596                                         #we remove connections between parent device and child device if the expand/collapse
01597                                         #states matches:
01598                                         # a. child is totally collapsed
01599                                         # b. child is totally expanded and no other links than to parent device
01600                                         # c. child is partially expanded and no other links than to parent device
01601 
01602                                         removeConnection(visobj,origShape.GetPortList(port_IN),"IN")
01603                                         tbd_content.append(visobj)
01604 
01605                                 elif (visobj.GetExpanded() == 1) \
01606                                         and (countConnections(visparent,visobj.GetPortList(port_IN)) != 0 \
01607                                         or countConnections(visparent,visobj.GetPortList(port_OUT)) != 0):
01608                                         # if
01609                                         # parent still has connections to other devices
01610                                         # set to partially expanded/collapsed
01611                                         tmp_collapsed = 1
01612                                 elif (visobj.GetExpanded() == 2) \
01613                                         and (countConnections(visparent,visobj.GetPortList(port_IN)) != 0 or \
01614                                         countConnections(visparent,visobj.GetPortList(port_OUT)) != 0):
01615                                         #if
01616                                         #parent still has connections to other devices
01617                                         #set to partially expaned/collapsed
01618                                         tmp_collapsed = 1
01619 
01620                 for lnk in outputLinks: # same as for iteration in inputLinks; but opposite
01621                         visobj = self.FindByName(lnk.GetNodeTo())
01622                         visparent = self.FindByName(lnk.GetNodeFrom())
01623                         vislink = self.FindByName(lnk.GetName())
01624                         if visobj != None: #object found
01625                                 if (visobj.GetExpanded() == 0) or \
01626                                         (visobj.GetExpanded() == 2 \
01627                                         and countConnections(visparent,visobj.GetPortList(port_IN)) == 0 \
01628                                         and countConnections(visparent,visobj.GetPortList(port_OUT)) == 0) \
01629                                         or (visobj.GetExpanded() == 1 \
01630                                         and countConnections(visparent,visobj.GetPortList(port_IN)) == 0 \
01631                                         and countConnections(visparent,visobj.GetPortList(port_OUT)) == 0):
01632 
01633                                         removeConnection(visobj,origShape.GetPortList(port_OUT),"OUT")
01634                                         tbd_content.append(visobj)
01635 
01636                                 elif (visobj.GetExpanded() == 1) \
01637                                         and (countConnections(visparent,visobj.GetPortList(port_IN)) != 0 \
01638                                         or countConnections(visparent,visobj.GetPortList(port_OUT)) != 0):
01639                                         tmp_collapsed = 1
01640                                 elif (visobj.GetExpanded() == 2) \
01641                                         and (countConnections(visparent,visobj.GetPortList(port_IN)) != 0 \
01642                                         or countConnections(visparent,visobj.GetPortList(port_OUT)) != 0):
01643                                         tmp_collapsed = 1
01644 
01645                 # objects to be removed from visual window because they no longer have any connections (single/free objects)
01646                 # in the visual window
01647                 for delitm in tbd_content:
01648                         if delitm in self.selection:
01649                                 self.selection.remove(delitm)
01650                         if delitm in visWindow.contents:
01651                                 visWindow.contents.remove(delitm)
01652                 
01653                 #set new expand/collapse property of parent device
01654                 origShape.SetExpanded(tmp_collapsed)
01655                 self.CenterToObject(origShape)
01656                 if prev_zoom != 100:
01657                         self.main.OnZoom(prev_zoom,False)
01658                 return True #if the parent device was expanded; we successfully collapsed it; and return
01659 
01660         ###END COLLAPSE CODE###
01661 
01662         ylayer_pos = origShape.GetLayer()
01663         node_pos = origShape.GetPosition()
01664         parent_x_pos_center = node_pos.x+(origShape.GetSize().GetWidth()/2)
01665 
01666         ### START EXPAND CODE ###
01667         position = 1
01668         nr_out_added = 0
01669         devices_on_output = {}
01670         for i in range(len(outputLinks)): # output links, positioning
01671                 tmp_link = outputLinks[i].GetObjectInfo(True)
01672                 tmp_devobj = Device(self.main.GetActiveSystem(),tmp_link[DEV_SWITCH_TO],False)
01673                 index,portnr = origShape.FindCorrespondingPortIndex(outputLinks[i].GetPortFrom(),outputLinks[i].GetPortTypeFrom(),port_OUT)
01674                 port_pos = origShape.GetPortPosition(index,port_OUT)
01675                 shape,newNodes = self.AddNode(tmp_devobj,port_pos.x,1,False,deviceobj.GetPortsOut(),parent_x_pos_center,port_pos.y,max_ports,refresh=False) #+1 from parentnode (y layer 1)
01676 
01677                 # add all entries (links) for a device, to find average position and set that later
01678                 if outputLinks[i].GetNodeTo() not in devices_on_output.keys(): # have to add new entry if not exist
01679                         devices_on_output[outputLinks[i].GetNodeTo()] = []
01680                         
01681                 my_x = shape.GetPosition().x
01682                 my_y = shape.GetPosition().y
01683                 devices_on_output[outputLinks[i].GetNodeTo()].append([my_x,my_y])
01684                 
01685                 #device to -> connect it
01686                 self.CreateConnectedLink(outputLinks[i])
01687                 position += 1
01688                 nr_out_added += newNodes
01689 
01690         # If there are several links between two devices, we find the average position for the node for all the links
01691         #print str(devices_on_output)
01692         for out_node in devices_on_output:
01693                 sum_x = 0
01694                 sum_y = 0
01695                 for out_link in devices_on_output[out_node]:
01696                         sum_x += out_link[0]
01697                         sum_y += out_link[1]
01698                         
01699                 vis_node = self.FindByName(out_node)
01700                 avg_x = int(sum_x / len(devices_on_output[out_node]))
01701                 avg_y = int(sum_y / len(devices_on_output[out_node]))
01702                 if vis_node != None:
01703                         vis_node.SetPosition(QPoint(avg_x,avg_y))
01704             
01705         position = 1
01706         nr_in_added = 0
01707         devices_on_input = {}
01708         for i in range(len(inputLinks)): #input links, positioning
01709                 tmp_link = inputLinks[i].GetObjectInfo(True)
01710                 tmp_devobj = Device(self.main.GetActiveSystem(),tmp_link[DEV_SWITCH_FROM],False)
01711                 index,portnr = origShape.FindCorrespondingPortIndex(inputLinks[i].GetPortTo(),inputLinks[i].GetPortTypeTo(),port_IN)
01712                 port_pos = origShape.GetPortPosition(index,port_IN)
01713                 shape,newNodes = self.AddNode(tmp_devobj,port_pos.x,-1,False,deviceobj.GetPortsIn(),parent_x_pos_center,port_pos.y,max_ports,refresh=False) #-1 from parentnode (y layer -1)
01714                 
01715                 if inputLinks[i].GetNodeFrom() not in devices_on_input.keys(): # have to add new entry if not exist
01716                         devices_on_input[inputLinks[i].GetNodeFrom()] = []
01717                         
01718                 my_x = shape.GetPosition().x
01719                 my_y = shape.GetPosition().y
01720                 devices_on_input[inputLinks[i].GetNodeFrom()].append([my_x,my_y])
01721                 
01722                 #device from -> connect it
01723                 self.CreateConnectedLink(inputLinks[i])
01724                 position += 1
01725                 nr_in_added += newNodes
01726 
01727         # If there are several links between two devices, we find the average position for the node for all the links
01728         for in_node in devices_on_input:
01729                 sum_x = 0
01730                 sum_y = 0
01731                 for in_link in devices_on_input[in_node]:
01732                         sum_x += in_link[0]
01733                         sum_y += in_link[1]
01734                         
01735                 vis_node = self.FindByName(in_node)
01736                 avg_x = int(sum_x / len(devices_on_input[in_node]))
01737                 avg_y = int(sum_y / len(devices_on_input[in_node]))
01738                 if vis_node != None:
01739                         vis_node.SetPosition(QPoint(avg_x,avg_y))
01740         
01741             
01742         #we rearrange and count the total number of nodes in each layer after insertion for both input and output nodes
01743         absY_out = self.GetAbsY(ylayer_pos+1)
01744         self.SetAbsY(1, absY_out + nr_out_added)
01745 
01746         absY_in = self.GetAbsY(ylayer_pos-1)
01747         self.SetAbsY(1, absY_in + nr_in_added)
01748 
01749         self.Select(origShape,refresh=False)
01750         origShape.SetExpanded(2) #expanded
01751         self.CenterToObject(origShape)
01752         
01753         if prev_zoom != 100:
01754                 self.main.OnZoom(prev_zoom,False)
01755 
01756         if refresh:
01757                 self.Refresh()
01758 
01759     ##
01760     #  Respond to the user right-clicking in the visual window.
01761     # 
01762     #             We select the clicked-on item, if necessary, and display a pop-up
01763     #             menu of available options which can be applied to the selected
01764     #             item(s).
01765     #         
01766     def OnRightClick(self, event):
01767 
01768         if self.GetLevelZoom() != -1:
01769                 return
01770         
01771         mousePt = self._GetEventCoordinates(event)
01772         obj = self._GetObjectAt(mousePt)
01773 
01774         if obj == None: # Nothing selected. Show a general visual menu.
01775                 if not self.main.GetCdb(): # Do not show menu if not connected to ConfDB
01776                         return False
01777                 
01778                 menu = wxMenu()
01779                 menu.Append(menu_SELECTALL, "Select All")
01780                 menu.Append(menu_DESELECTALL, "Deselect All")
01781 
01782                 EVT_MENU(self, menu_SELECTALL, self.SelectAll)
01783                 EVT_MENU(self, menu_DESELECTALL, self.DeselectAll)
01784                 
01785                 zoommenu = wxMenu()
01786                 zoommenu.Append(menu_ZOOMIN, "Zoom In")
01787                 zoommenu.Append(menu_ZOOMOUT, "Zoom Out")
01788                 zoommenu.Append(menu_ZOOMCUSTOM, "Custom Zoom")
01789 
01790                 menu.AppendMenu(-1,"Zoom",zoommenu,"")
01791 
01792                 # We have to go through the CdbVis module because the zoom function is always called from that module
01793                 EVT_MENU(self, menu_ZOOMIN, self.main.ZoomIn)
01794                 EVT_MENU(self, menu_ZOOMOUT, self.main.ZoomOut)
01795                 EVT_MENU(self, menu_ZOOMCUSTOM, self.main.ZoomCustom)
01796 
01797                 #TODO: Up and Down one level?
01798                 
01799 
01800                 clickPt = QPoint(event.GetX(),event.GetY())
01801                 self.PopupMenu(menu,clickPt)
01802                 menu.Destroy()
01803         
01804         else: # obj != None
01805 
01806                 # Select the clicked-on object.
01807                 if obj not in self.selection:
01808                     self.Select(obj,refresh=True)
01809                 
01810                 
01811                 if self.curTool == tool_EDIT:
01812                         # Build our pop-up menu.
01813 
01814                         menu = wxMenu()
01815                         menu.Append(menu_CLONE, "Clone")
01816                         menu.Append(menu_DUPLICATE, "Duplicate")
01817                         menu.Append(menu_DELETE,    "Delete")
01818                         menu.Append(menu_MODIFY,"Modify")
01819 
01820                         EVT_MENU(self, menu_DUPLICATE,     self.DoDuplicateHelper)
01821                         EVT_MENU(self, menu_DELETE,        self.DoDelete)
01822                         EVT_MENU(self,menu_CLONE,self.DoCloneHelper)
01823 
01824                         if obj.GetObject().__class__ == Device:
01825                                 EVT_MENU(self, menu_MODIFY, self.main.ModifyDeviceClick)
01826                         else:
01827                                 EVT_MENU(self, menu_MODIFY, self.main.ModifyLinkClick)
01828 
01829                         # Show the pop-up menu.
01830 
01831                         clickPt = QPoint(event.GetX(), event.GetY())
01832                         self.PopupMenu(menu, clickPt)
01833                         menu.Destroy()
01834 
01835     ##
01836     #  Change the level zoom to the given level.
01837     # 
01838     #   @factor - level to change to (-1 -> n, where n is the max level in the active subsystem
01839     #   
01840     def SetLevelZoom(self,factor):
01841         self.levelzoom = factor
01842         #self.paintevent(None)
01843 
01844     ##
01845     #  Get the level zoom
01846     # 
01847     #   !return - level zoom (integer)
01848     #   
01849     def GetLevelZoom(self):
01850         return self.levelzoom
01851 
01852     ##
01853     #  Get the whole row of history of navigation within this active subsystem
01854     # 
01855     #   !return - a list with entries describing what the user chose in each level, 
01856     #   or False is returned if an error occured.
01857     #   
01858     def GetLevelInfo(self):
01859         try:
01860                 levelinfo = self.levelselections[self.main.GetActiveSystem()]
01861                 return levelinfo
01862         except KeyError,err:
01863                 return False
01864         
01865     ##
01866     #  Get the history information about what the user chose in the previous level (1 up)
01867     # 
01868     #   !return - string describing the choice made at the previous level, or False if an error
01869     #   occurs
01870     #   
01871     def GetLevelSelections(self):
01872         try:
01873                 levelinfo = self.levelselections[self.main.GetActiveSystem()][self.levelzoom-1]
01874                 return levelinfo
01875         except IndexError,err:
01876                 return False
01877         
01878     ##
01879     #  Get the history information about the current level.
01880     # 
01881     #   !return - string describing the contents of the current level.
01882     #   
01883     def GetLevelSelection(self,level):
01884         return self.levelselections[self.main.GetActiveSystem()][level]
01885 
01886     ##
01887     #  Set history information about the choice the user made at the previous/current
01888     #   level.
01889     # 
01890     #   @id - obsolete, not used
01891     #   @system - the name of the active subsystem
01892     #   @level - the number/id of the level
01893     #   @reset - whether the history information about other levels should be reset
01894     #   before adding this new history information.
01895     #   
01896     def SetLevelSelections(self,id,system,level,reset=False):
01897         try:
01898                 if self.levelselections[system]:
01899                         if reset:
01900                                 self.levelselections[system] = []
01901                         while len(self.levelselections[system]) >= level:
01902                                 self.levelselections[system].pop(level-1)
01903 
01904                         self.levelselections[system].append(id)
01905         except KeyError,err:
01906                 self.levelselections[system] = []
01907                 self.levelselections[system].append(id)
01908 
01909     ##
01910     #  Helper function that checks the contents of the window and automatically make them fit inside the window,
01911     #   down to 25% zoom. If lower zoom is needed, the user will have to set it himself, because the devices doesnt show
01912     #   properly at lower zoom.
01913     # 
01914     #   The items in the visual window is only auto zoomed when new items are added, or the user explicitly change the
01915     #   enable autozoom to enabled on the View menu.
01916     # 
01917     #   This function works quite nice, but it does have some weird bugs:
01918     #   * sometimes it sets the zoom to 100 %, even though it should have been much smaller (seems that it breaks the
01919     #   iterative loop somehow, but because of lack of time I have not had possibillity to investigate this further)
01920     #   * The visible visual window also counts area behind widgets that is on top of the visual window (menu bar and tool
01921     #   bar and scroll bar and sash), therefore it often happens that devices that is close to one of the 4 edges of the
01922     #   window will not be seen as outside the visible portion of the window, and thus considered as no zoom is needed)
01923     #   
01924     def ResizeToFitContents(self):
01925 
01926         # We may want to have less zoom after last change, therefore we go all the way out to 100%, and see
01927         # how much zoom-out that is needed again. We do this every time the content changes on the screen.
01928         if GetZoomFactor() < 100:
01929                 self.main.OnZoom(100,False)     
01930                 
01931         # if device level, we zoom to fit the contents in the window (but we do not zoom more than 25%)
01932         if self.levelzoom == -1:
01933                 vw_size_w, vw_size_h = self.width(), self.height() #self.GetSize() #width and height of visible vis_win part
01934                 vw_start_x, vw_start_y = self.contentsX(), self.contentsY()  #self.CalcUnscrolledPosition(0,0) # coordinates upper left corner
01935                 
01936                 # to float, because we will get decimals to work with later
01937                 vw_start_x = float(vw_start_x)
01938                 vw_start_y = float(vw_start_y)
01939                 vw_size_w = float(vw_size_w)
01940                 vw_size_h = float(vw_size_h)
01941                 
01942                 # end window coords.
01943                 vw_end_x = vw_start_x + vw_size_w 
01944                 vw_end_y = vw_start_y + vw_size_h
01945 
01946                 # center vis.win. coords.
01947                 center_x = vw_start_x + vw_size_w/2.0
01948                 center_y = vw_start_y + vw_size_h/2.0
01949                 greatest_distance = 1.0 # This is a distance factor for objects outside the visible window, if it is greater
01950                 # than 1.0, we will have to zoom-out. The distance factor is calculated by finding the distance from the
01951                 # center of the visual window to the edge of the visual portion of the window, and we divide the total
01952                 # distance to the furthest object on this distance.
01953                 zoom = 100.0 # default zoom, before we check if we need to zoom-out
01954 
01955                 # maximum distance to the edge of the visible window, as well as the angle
01956                 max_distance_rect = ((vw_size_w/2.0)*(vw_size_w/2.0) + (vw_size_h/2.0)*(vw_size_h/2.0))**(0.5) # hyptenuse
01957                 max_angle_rect = (vw_size_h/2.0)/(vw_size_w/2.0) # angle of the diagonal in the vis.win, which is the
01958                 # greatest distance from the center to the edges, in radians (before arctan)
01959                 max_angle_rect_deg = degrees(atan(max_angle_rect)) # the angle in degrees, after arctan
01960                 
01961                 for vis_obj in visWindow.contents: # we find the outer positions of objects in all directions
01962                         if vis_obj.GetType() == obj_NODE:
01963                                 obj_start_x, obj_start_y = vis_obj.GetPosition().x(), vis_obj.GetPosition().y()
01964                                 obj_size_w, obj_size_h = vis_obj.GetSize().width(), vis_obj.GetSize().height()
01965 
01966                                 obj_start_x = float(obj_start_x)
01967                                 obj_start_y = float(obj_start_y)
01968                                 obj_size_w = float(obj_size_w)
01969                                 obj_size_h = float(obj_size_h)
01970                                 
01971                                 obj_end_x = obj_start_x + obj_size_w
01972                                 obj_end_y = obj_start_y + obj_size_h
01973                                 
01974                                 # first we check whether the object is too much to the left of the vis.win.
01975                                 if obj_start_x < vw_start_x:
01976                                         x_dist = fabs(center_x - obj_start_x) # absolute distance to center x from startx pos. on obj
01977 
01978                                         # we take bottom y corner if it is below the center y, and top y corner if above
01979                                         if (obj_start_y < center_y):
01980                                                 y_dist = fabs(center_y - obj_start_y)
01981                                         else:
01982                                                 y_dist = fabs(center_y - obj_end_y)
01983                                                 
01984                                         # calculate the distance to the point of the object that is most far away
01985                                         tot_dist = (x_dist*x_dist + y_dist*y_dist)**(0.5)
01986 
01987                                         # to avoid zero-division, if difference in x is 0
01988                                         if x_dist == 0.0:
01989                                                 x_dist = 0.001
01990 
01991                                         angle = y_dist/x_dist # angle to our object, radians before arctan
01992                                         angle_deg = degrees(atan(angle)) # angle, degrees after arctan
01993 
01994                                         # if greater, it has a greater distance in another direction (y up or down)
01995                                         if angle_deg <= max_angle_rect_deg:
01996                                                 distance_to_rect = ((tot_dist/x_dist) * vw_size_w/2.0) # calculate distance to
01997                                                 # edge on the way to our object, by using similar triangles
01998                                                 # compare to distance to the object itself, how much greater distance we need (1.xx)
01999                                                 my_distance = tot_dist/distance_to_rect # how much more zoom we need to see it
02000 
02001                                                 # if the zoom we need is smaller than the zoom calculated so far..we set it as new zoom
02002                                                 if my_distance > greatest_distance:
02003                                                         zoom = 100.0 / my_distance
02004                                                         greatest_distance = my_distance
02005 
02006                                 if (obj_end_x > vw_end_x - 20):
02007                                         x_dist = fabs(center_x - obj_end_x)
02008                                         if (obj_end_y > center_y):
02009                                                 y_dist = fabs(center_y - obj_end_y)
02010                                         else:
02011                                                 y_dist = fabs(center_y - obj_start_y)
02012                                                 
02013                                         tot_dist = (x_dist*x_dist + y_dist*y_dist)**(0.5)
02014                                         
02015                                         if x_dist == 0.0:
02016                                                 x_dist = 0.001
02017 
02018                                         angle = y_dist/x_dist
02019                                         angle_deg = degrees(atan(angle))
02020 
02021                                         # if greater, it has a greater distance in another direction (y up or down)
02022                                         if angle_deg <= max_angle_rect_deg:
02023                                                 distance_to_rect = ((tot_dist/x_dist) * vw_size_w/2.0)
02024                                                 my_distance = (tot_dist+30.0)/distance_to_rect # how much more zoom we need to see it
02025 
02026                                                 if my_distance > greatest_distance:
02027                                                         zoom = 100.0 / my_distance
02028                                                         greatest_distance = my_distance
02029                                                         
02030                                 if obj_end_y > vw_end_y:
02031                                         if (obj_end_x > center_x):
02032                                                 x_dist = fabs(center_x - obj_end_x)
02033                                         else:
02034                                                 x_dist = fabs(center_x - obj_start_x)
02035                                                 
02036                                         y_dist = fabs(center_y - obj_end_y)
02037                                                 
02038                                         tot_dist = (x_dist*x_dist + y_dist*y_dist)**(0.5)
02039                                         
02040                                         if y_dist == 0.0:
02041                                                 y_dist = 0.001
02042 
02043                                         angle = x_dist/y_dist
02044                                         angle_deg = degrees(atan(angle))
02045 
02046                                         # if greater, it has a greater distance in another direction (y up or down)
02047                                         if angle_deg <= max_angle_rect_deg:
02048                                                 distance_to_rect = ((tot_dist/y_dist) * vw_size_h/2.0)
02049                                                 my_distance = tot_dist/distance_to_rect # how much more zoom we need to see it
02050 
02051                                                 if my_distance > greatest_distance:
02052                                                         zoom = 100.0 / my_distance
02053                                                         greatest_distance = my_distance
02054 
02055                                 if obj_start_y > vw_start_y:
02056                                         if (obj_start_x < center_x):
02057                                                 x_dist = fabs(center_x - obj_start_x)
02058                                         else:
02059                                                 x_dist = fabs(center_x - obj_end_x)
02060                                                 
02061                                         y_dist = fabs(center_y - obj_start_y)
02062                                                 
02063                                         tot_dist = (x_dist*x_dist + y_dist*y_dist)**(0.5)
02064                                         
02065                                         if y_dist == 0.0:
02066                                                 y_dist = 0.001
02067 
02068                                         angle = x_dist/y_dist
02069                                         angle_deg = degrees(atan(angle))
02070 
02071                                         # if greater, it has a greater distance in another direction (y up or down)
02072                                         if angle_deg <= max_angle_rect_deg:
02073                                                 distance_to_rect = ((tot_dist/y_dist) * vw_size_h/2.0)
02074                                                 my_distance = tot_dist/distance_to_rect # how much more zoom we need to see it
02075 
02076                                                 if my_distance > greatest_distance:
02077                                                         zoom = 100.0 / my_distance
02078                                                         greatest_distance = my_distance
02079 
02080                 zoom = (GetZoomFactor() * (zoom/100.0)) # calculate zoom to fit contents
02081 
02082                 # if below, 25, we set it to 25 coz smaller zoom is on users own risk :)
02083                 if zoom < 25: 
02084                         zoom = 25 #minimum
02085                 else:
02086                         zoom = int(zoom) # no decimals, cast to integer
02087 
02088                 if zoom < GetZoomFactor():
02089                         self.main.OnZoom(zoom,False) # Zoom!
02090 
02091 
02092     def paintevent(self, event):
02093         pass
02094 
02095     ##
02096     #  Respond to the "Select All" menu command:
02097     #   select all objects in the visual window.
02098     #         
02099     def DoSelectAll(self, event):
02100         self.SelectAll() 
02101 
02102     ##
02103     #  Method called when clone is chosen for a selection of objects.
02104     # 
02105     #   @addtoundo - whether the clone information should be added to the UNDO list or not
02106     #   
02107     def DoCloneHelper(self,addtoundo=True):
02108         if len(self.selection) == 0:
02109                 self.main.ShowError("Cannot clone a device and/or link because nothing is seleted.",ERR_ERROR)
02110                 return False
02111         
02112         #nrofduplicates = wxGetNumberFromUser("How many clones do you want to make?","Nr. of clones","Nr. of clones",1,1,10000,self.main)
02113         nrofduplicates, valid = QInputDialog.getInteger("Nr. of clones","How many clones do you want to make?",1,1,10000,1,self)
02114         if not valid:
02115                 return False
02116         res = self.DoClone(addtoundo,nrofduplicates)
02117         self.canvas.update()
02118 
02119 
02120     ##
02121     #  The real clone method, clones the objects selected in the number of clones
02122     #   chosen.
02123     # 
02124     #   @addtoundo - whether the clone information should be added to the UNDO list or not.
02125     #   @nrofclones - number of clones of each selected object to be created
02126     #   
02127     def DoClone(self,addtoundo=True,nrofclones=1):
02128         
02129         if len(self.selection) == 0:
02130                 self.main.ShowError("Cannot clone a device and/or link because nothing is seleted.",ERR_ERROR)
02131                 return False
02132 
02133         if addtoundo:
02134                 undoindex = self.main.GetFirstNewUndoIndex()
02135 
02136                 if len(self.selection) == 0: #None selected
02137                         return False
02138                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_NODE:
02139                         descr = "clone device: " + str(self.selection[0].GetName()) + " " + str(nrofclones) + " times"
02140                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_LINK:
02141                         descr = "clone link: " + str(self.selection[0].GetName()) + " " + str(nrofclones) + " times"
02142                 else:
02143                         descr = "clone objects " + str(nrofclones) + " times"
02144 
02145         selecteditems = []
02146         for node in self.selection:
02147                 selecteditems.append(node.GetObject().GetName())
02148 
02149         #Find free links; we want to find links to be cloned where 1 or 2 of the nodes it is attached to at the moment is not to be cloned, hence the cloned link will connect to available ports in the not-cloned devices
02150         to_links = {}
02151         from_links = {}
02152         free_links_available_to = {}    #nr of INGOING ports of given devices
02153         free_links_to_arr = []          #names of devices we know information about free to-ports
02154         free_links_available_from = {}  #nr of free OUTGOING ports of given devices
02155         free_links_from_arr = []        #names of devices we know information about free from-ports
02156 
02157         sorted_links = {} # sorted on: port type,port nbr
02158         port_reference = {}
02159         for itm in self.selection:
02160                 #print "LinkName: " + str(itm.GetObject().GetName())
02161                 if itm.GetType() == obj_LINK: #only links
02162                         if itm.GetObject().GetNodeTo() not in selecteditems: #found free to link
02163                                 is_in_hash = False
02164                                 if itm.GetObject().GetNodeTo() in free_links_to_arr:
02165                                         inp = free_links_available_to[itm.GetObject().GetNodeTo()] #get nr of free in-links from given device
02166                                         is_in_hash = True
02167                                 else:
02168                                         dev_tmp = Device(itm.GetObject().GetSystem(),itm.GetObject().GetNodeTo(),False) #have to create a device to get port info
02169                                         totp,inp_arr,outp_arr = dev_tmp.GetFreePorts() #get information about how many free ports we have
02170                                         if totp == False and inp_arr == False and outp_arr == False:
02171                                                 self.main.ShowError("Cannot clone device: " + str(dev_tmp.GetName()) + ": " + str(dev_tmp.GetErrorMessage()),ERR_ERROR)
02172                                                 return False
02173                                         
02174                                         inp = len(inp_arr)
02175                                         outp = len(outp_arr)
02176 
02177                                 if inp < nrofclones:
02178                                         self.main.ShowError("Can not clone " + str(itm.GetObject().GetName()) + " because there are not enough free input ports on the device " + str(dev_tmp.GetName()) + ".",ERR_ERROR)
02179                                         return False
02180 
02181                                 if is_in_hash:
02182                                         free_links_available_to[itm.GetObject().GetNodeTo()] -= nrofclones #we subtract number of clones of given link, we may also have clones of other links connected to this device
02183                                 else:
02184                                         free_links_to_arr.append(itm.GetObject().GetNodeTo())
02185                                         free_links_available_to[itm.GetObject().GetNodeTo()] = inp-nrofclones
02186                                         
02187                                 to_links[itm.GetObject().GetName()] = dev_tmp
02188 
02189                         if itm.GetObject().GetNodeFrom() not in selecteditems: #found free from link
02190                                 is_in_hash = False
02191                                 if itm.GetObject().GetNodeFrom() in free_links_from_arr:
02192                                         outp = free_links_available_from[itm.GetObject().GetNodeFrom()]
02193                                         is_in_hash = True
02194                                 else:
02195                                         dev_tmp = Device(itm.GetObject().GetSystem(),itm.GetObject().GetNodeFrom(),False)
02196                                         totp,inp_arr,outp_arr = dev_tmp.GetFreePorts()
02197                                         inp = len(inp_arr)
02198                                         outp = len(outp_arr)
02199 
02200                                 if outp < nrofclones:
02201                                         self.main.ShowError("Can not clone " + str(itm.GetObject().GetName()) + " because there are not enough free output ports on the device " + str(dev_tmp.GetName()) + ".",ERR_ERROR)
02202                                         return False
02203 
02204                                 if is_in_hash:
02205                                         free_links_available_from[itm.GetObject().GetNodeFrom()] -= nrofclones
02206                                 else:
02207                                         free_links_from_arr.append(itm.GetObject().GetNodeFrom())
02208                                         free_links_available_from[itm.GetObject().GetNodeFrom()] = outp-nrofclones
02209         
02210                                 from_links[itm.GetObject().GetName()] = dev_tmp #=SAVE NR OF FREE PORTS IN A MEMBER VARIABLE SO IT CAN EASILY BE ACCESSED
02211 
02212                         porttype = itm.GetObject().GetPortTypeFrom()
02213                         try:
02214                                 portnbr = int(itm.GetObject().GetPortFrom())
02215                         except ValueError,err:
02216                                 portnbr = itm.GetObject().GetPortFrom()
02217 
02218                         if porttype not in sorted_links.keys():
02219                                 sorted_links[porttype] = []
02220 
02221                         sorted_links[porttype].append(portnbr)
02222                         port_reference[porttype+str(portnbr)] = itm
02223 
02224         from_links_copy = []
02225         to_links_copy = []
02226         for porttype in sorted_links:
02227                 sorted_links[porttype].sort() #sort the list of portnbrs for each port type!!! so that we can pick nbrs from the start
02228                 for port in sorted_links[porttype]:
02229                         linkname = port_reference[porttype+str(port)].GetObject().GetName()
02230                         #print "linkname: " + str(linkname)
02231                         if linkname in from_links:
02232                                 from_links_copy.append([linkname,from_links[linkname]])
02233                         if linkname in to_links:
02234                                 to_links_copy.append([linkname,to_links[linkname]])
02235                 
02236         pendinglinks = [] # links to be stored in dirty objects list
02237         i = 0
02238         while i < nrofclones:
02239                 prev_sel = self.selection[:] #because things get deselected f.ex. using DoDeleteObj
02240                 duplicateoriginlist = self.DoDuplicate(False,1,True,False)
02241 
02242                 ##
02243                 #  A helper function to find remaining ports in sorted order (first port type then portnbr)
02244                 #                       for a given port type, and return the first free port in the sorted order.
02245                 #                       
02246                 #                       @portlist - the port list (IN or OUT) for a device
02247                 #                       @orgporttype - we need to clone a link and connect it to the same port type as the original
02248                 #                       link, therefore we need to know what port type the original link was connected to.
02249                 #                       
02250                 def sortmyports(portlist,orgporttype):
02251 
02252                         ports = {}
02253 
02254                         for port in portlist:
02255                                 tmp_port = port.split(":")
02256                                 porttype = tmp_port[1].strip()
02257 
02258                                 if porttype not in ports.keys():
02259                                         ports[porttype] = []
02260 
02261                                 try:
02262                                         portnbr = int(tmp_port[0].strip())
02263                                 except ValueError,err:
02264                                         portnbr = tmp_port[0].strip()
02265 
02266                                 ports[porttype].append(portnbr) #porttype -> portnbr[]
02267 
02268                         for porttype in ports:
02269                                 ports[porttype].sort() #sort the list of portnbrs for each port type!!! so that we can pick nbrs from the start
02270                         if orgporttype not in ports.keys():
02271                                 return "-1"
02272                         else:
02273                                 return str(ports[orgporttype].pop(0)) #first free (lowest nr or alphabetical string)
02274 
02275 
02276                 # IF we cant find a proper port to connect to, we HAVE to delete the given link, because we can not have free or partially free links
02277                 # Both from visual window and remove from dirty list
02278                 for tolink in to_links_copy:
02279                         #totalp,inp,outp = to_links[tolink].GetSavedFreePorts()
02280                         totalp,inp,outp = tolink[1].GetSavedFreePorts()
02281                         if len(inp) <= 0:
02282                                 self.main.ShowError("Could not clone " + str(duplicateoriginlist[tolink[0]].GetName()) + " to " + str(tolink[1].GetName()) + " because there are not enough free ports.",ERR_ERROR)
02283                                 #return False?
02284                         else:
02285                                 #tmp_link = self.main.GetDirtyObject(duplicateoriginlist[tolink],Link) #We work directly on the link in dirtylist, overwrite information given in dirty list with information about the cloned objects
02286                                 tmp_link = duplicateoriginlist[tolink[0]]
02287                                 if not tmp_link:
02288                                         return False
02289                                 
02290                                 if tmp_link not in pendinglinks:
02291                                         pendinglinks.append(tmp_link)
02292 
02293                                 if tmp_link.GetNodeTo() not in selecteditems: #if true, we will connect this link to a device that will not be cloned
02294 
02295                                         newportnbr = sortmyports(inp,tmp_link.GetPortTypeTo()) #!
02296                                         if newportnbr == "-1":
02297                                                 self.main.ShowError("Could not clone " + str(duplicateoriginlist[tolink[0]].GetName()) + " to " + str(tolink[1].GetName()) + " because there are not any ports left with the same port type.",ERR_ERROR)
02298                                                 continue #Here we should clean up instead? Or at least delete the object that failed.
02299                                         else:
02300                                                 inp.remove(newportnbr + " : " + tmp_link.GetPortTypeTo()) #This can never fail, because we found this in the list
02301                                 else: #we will connect this link to a device we are cloning as well, which means connect to the SAME ports as with the original
02302                                         newportnbr = tmp_link.GetPortTo()
02303 
02304                                 tmp_link.SetNodeTo(tolink[1].GetName())
02305                                 tmp_link.SetPortTo(newportnbr) #to be changed, need have a smarter solution to pick "correct" port
02306                                 tmp_link.SetPortTypeTo(tmp_link.GetPortTypeTo())
02307 
02308                                 #newObj.SetPortIndexFrom(link.GetPortIndexFrom()) #! have to set this as well!!!
02309 
02310                                 self.DoDeleteObj(tmp_link.GetName(),False,refresh=False) #?
02311                                 self.CreateConnectedLink(tmp_link)
02312                                 
02313                 for fromlink in from_links_copy:
02314                         #totalp,inp,outp = from_links[fromlink].GetSavedFreePorts()
02315                         totalp,inp,outp = fromlink[1].GetSavedFreePorts()
02316                         if len(outp) <= 0:
02317                                 self.main.ShowError("Could not clone " + str(duplicateoriginlist[fromlink[0]].GetName()) + " from " + str(fromlink[1].GetName()) + " because there are not enough free ports.",ERR_ERROR)
02318                                 #return False?
02319                         else:
02320                                 #tmp_link = self.main.GetDirtyObject(duplicateoriginlist[fromlink],Link)
02321                                 tmp_link = duplicateoriginlist[fromlink[0]]
02322                                 if not tmp_link:
02323                                         #tmp_link = Link(itm.GetObject().GetSystem(),duplicateoriginlist[fromlink],False,False)
02324                                         return False
02325                                 
02326                                 if tmp_link not in pendinglinks:
02327                                         pendinglinks.append(tmp_link)
02328 
02329                                 if tmp_link.GetNodeFrom() not in selecteditems: #connect link to a device that will not be cloned
02330                                         newportnbr = sortmyports(outp,tmp_link.GetPortTypeFrom()) #!
02331                                         if newportnbr == "-1":
02332                                                 self.main.ShowError("Could not clone " + str(duplicateoriginlist[fromlink[0]].GetName()) + " from " + str(fromlink[1].GetName()) + " because there are not any ports left with the same port type.",ERR_ERROR)
02333                                                 continue #Here we should clean up instead? Or at least delete the object that failed.
02334                                         else:
02335                                                 outp.remove(newportnbr + " : " + tmp_link.GetPortTypeFrom()) #This can never fail, because we found this in the list
02336                                 else: #we will connect this link to a device we are cloning as well, which means connect to the SAME ports as with the original
02337                                         newportnbr = tmp_link.GetPortFrom()
02338 
02339                                 tmp_link.SetNodeFrom(fromlink[1].GetName())
02340                                 tmp_link.SetPortFrom(newportnbr)
02341                                 tmp_link.SetPortTypeFrom(tmp_link.GetPortTypeFrom())
02342                                 #delete the one in the window and replace with a new one
02343                                 self.DoDeleteObj(tmp_link.GetName(),False,refresh=False)
02344                                 self.CreateConnectedLink(tmp_link)
02345                 
02346                 # We have to wait until here to add links to the dirty objects list, because the same link may go through
02347                 # both loops (for to_links and from_links), reset list as well for next iteration.
02348                 for link in pendinglinks:
02349                         link.Create()
02350 
02351                 pendinglinks = []
02352 
02353                 self.selection = prev_sel
02354                 i += 1
02355 
02356 
02357         #UNDO information
02358         if addtoundo:
02359                 #undo information
02360                 #redo information is always directly stolen from undo information
02361                 pass ############# self.main.AddToUndo(undoindex,descr)
02362 
02363         #Set up the free links to connect to the same device if possible (enough ports of the given type in/out
02364 
02365     ##
02366     #  Called when the user chooses to duplicate a selection of objects
02367     # 
02368     #   @addtoundo - whether the duplicate actions should be added to the undo list for later
02369     #   duplication or not.
02370     #   
02371     def DoDuplicateHelper(self,addtoundo=True):
02372 
02373         if len(self.selection) == 0:
02374                 self.main.ShowError("Cannot duplicate a device and/or link because nothing is seleted.",ERR_ERROR)
02375                 return False
02376         
02377         nrofduplicates = wxGetNumberFromUser("How many duplicates do you want to make?","Nr. of duplicates","Nr. of duplicates",1,1,10000,self.main)
02378         if nrofduplicates == -1:
02379                 self.main.ShowError("Invalid number of duplicates.",ERR_ERROR)
02380                 return False
02381         teststr = str(nrofduplicates)
02382         if teststr.find(".",0,len(teststr)) != -1: #float
02383                 self.main.ShowError("Float number is not supported.",ERR_ERROR)
02384                 return False
02385                 
02386         res = self.DoDuplicate(addtoundo,int(nrofduplicates),False,False)
02387         self.paintevent(None)
02388 
02389     ##
02390     #  Duplicates the selected objects in the number of duplicates selected by
02391     #   the user.
02392     # 
02393     #   @addtoundo - whether the duplicate actions should be added to the undo list for alter
02394     #   duplication or not.
02395     #   @nrofduplicates - the number of duplicates that will be created of each selected object.
02396     #   @fromclone - whether this method was called from the DoClone(...) method or not; 
02397     #   there are some differences in code
02398     #   @paintevent - whether we should trigger a paint event or not.
02399     #         
02400     def DoDuplicate(self,addtoundo=True,nrofduplicates=1,fromclone=False,paintevent=True):
02401         
02402         duplicateoriginlist = {}
02403 
02404         if len(self.selection) == 0:
02405                 self.main.ShowError("Cannot duplicate a device and/or link because nothing is seleted.",ERR_ERROR)
02406                 return False
02407 
02408         #To duplicate a link, both devices it is connected to has to be duplicated as well. Check.
02409         if not fromclone:
02410                 devnames = []
02411                 links = []
02412                 for myitm in self.selection:
02413                         if obj_NODE == myitm.GetType():
02414                                 devnames.append(myitm.GetName())
02415                         elif obj_LINK == myitm.GetType():
02416                                 links.append(myitm.GetObject())
02417 
02418                 for link in links:
02419                         if not (link.GetNodeTo() in devnames and link.GetNodeFrom() in devnames):
02420                                 self.main.ShowError("Cannot duplicate the link " + str(link.GetName()) + " because it has to be connected to two devices after duplication.",ERR_ERROR)
02421                                 return False
02422 
02423         if addtoundo:
02424                 undoindex = self.main.GetFirstNewUndoIndex()
02425         #ONLY when addtoundo = true
02426 
02427 
02428         i = 0
02429         while i < nrofduplicates:
02430                 duplicatelist = {}
02431                 tmplinks = []
02432                 prev_portListIn = {}
02433                 prev_portListOut = {}
02434                 objs = [] #new objects
02435                 #ports = [] #new ports (duplicates)
02436 
02437                 for obj in self.selection:
02438                         type = obj.GetType()
02439                         if type == obj_NODE:
02440                             #pdb.set_trace()
02441                             newObj = Box(self.canvas,type)
02442                             newObj.SetData(obj.GetData()) #(1) Device + DeviceType
02443                             prev_portListIn[obj.GetName()] = obj.GetPortList(port_IN)[:] #copy
02444                             prev_portListOut[obj.GetName()] = obj.GetPortList(port_OUT)[:] #copy
02445 
02446                             tmp_obj = newObj.GetObject()
02447 
02448                             devid = self.main.GetNextDeviceID(obj.GetObject().GetSystem(),obj.GetObject().GetType()) #(2)
02449                             if devid == False:
02450                                 #should not happen..but you never know
02451                                 devid = ((str(self.main.GetActiveSystem()) + "_tmp_device_" + str(self.main.GetNewLinkNr())).upper())
02452 
02453                             tmp_obj.SetName(devid)
02454 
02455                             #Duplicate ports
02456                             old_ports = obj.GetObject().GetPorts()
02457                             for tmp_oldport in old_ports:
02458                                 tmp_newport = Port(tmp_oldport.GetSystem(),tmp_oldport.GetPortNbr(),tmp_oldport.GetPortType(),tmp_oldport.GetPortWay(),tmp_oldport.GetDevice(),True)
02459                                 tmp_newport.SetDict(tmp_oldport.GetObjectInfo(True))
02460                                 tmp_newport.SetDevice(tmp_obj.GetName())
02461                                 tmp_newport.SetPortID(-1) #So we do not mistaken this port to be the old one...
02462 
02463                                 #ports.append(tmp_newport)
02464                                 tmp_newport.Create()
02465 
02466                             #selectpanel, treeview updates
02467                             try:
02468                                 pass ##!!!!!!!!!!!    my_id = self.main.GetSelectWindow().GetItemID(tmp_obj.GetType())
02469                                 ##!!!!!!!!!!!!!!!!!!!!    self.main.GetSelectWindow().AddItem(my_id,tmp_obj.GetName(),TN_DEVICE)
02470                             except KeyError,err:
02471                                 #print "treeitemid not found"
02472                                 pass
02473 
02474                             tmp_obj.SetID("")
02475                             tmp_obj.Create() #set savestatus to insert
02476                             newObj.SetText(tmp_obj.GetName())
02477 
02478                             duplicateoriginlist[obj.GetObject().GetName()] = devid
02479                             newObj.ClearPorts()
02480                             objs.append(newObj)
02481                             duplicatelist[obj.GetObject().GetName()] = tmp_obj.GetName() #to handle the links afterwards
02482                             ### SHOW THE DEVICE NOW
02483                             newObj.show()
02484                         elif obj_LINK == type:
02485                                 tmplinks.append(obj) #add to linklist tmp to walk through when we finished this loop
02486 
02487                 for link in tmplinks:
02488                         newObj = myLine(self.canvas,type)
02489                         newObj.SetData(link.GetData())
02490 
02491                         newObj.SetPortIndexFrom(link.GetPortIndexFrom())
02492                         newObj.SetPortIndexTo(link.GetPortIndexTo())
02493 
02494                         tmp_obj = newObj.GetObject()
02495                         tmp_obj.SetName(("tmp_link_" + str(self.main.GetNewLinkNr())).upper())
02496                         if fromclone: #set first to the same as the previous object, fake of course, but so that it can be saved
02497                                 if link.GetObject().GetNodeTo() not in duplicatelist:
02498                                         tmp_obj.SetNodeTo(link.GetObject().GetNodeTo())
02499                                 else:
02500                                         tmp_obj.SetNodeTo(duplicatelist[link.GetObject().GetNodeTo()])
02501                                         
02502                                 if link.GetObject().GetNodeFrom() not in duplicatelist: #only happens with cloning
02503                                         tmp_obj.SetNodeFrom(link.GetObject().GetNodeFrom())
02504                                 else:
02505                                         tmp_obj.SetNodeFrom(duplicatelist[link.GetObject().GetNodeFrom()])
02506 
02507                                 tmp_obj.SetPortFrom(link.GetObject().GetPortFrom())
02508                                 tmp_obj.SetPortTypeFrom(link.GetObject().GetPortTypeFrom())
02509                                 tmp_obj.SetPortTo(link.GetObject().GetPortTo())
02510                                 tmp_obj.SetPortTypeTo(link.GetObject().GetPortTypeTo())
02511                                 newObj.SetFixed(False)
02512                         #tmp_obj.SetID("")
02513                         if not fromclone: #pending save to dirty objects list before all properties set for cloning
02514                                 tmp_obj.Create() #savestatus to insert
02515                         newObj.SetText(tmp_obj.GetName())
02516                         newObj.SetFixed(True)
02517 
02518                         duplicateoriginlist[link.GetObject().GetName()] = tmp_obj #.GetName() #old name -> duplicate name
02519                         
02520                         if not fromclone:
02521                                 if link.GetObject().GetNodeTo() not in duplicatelist: #only happens with cloning, because connection between links and devices is handled in DoClone(...)
02522                                         tmp_obj.SetNodeTo("-1")
02523                                         tmp_obj.SetPortTo("-1")
02524                                         tmp_obj.SetPortTypeTo("")
02525                                         newObj.SetFixed(False)
02526                                 else:
02527                                         tmp_obj.SetNodeTo(duplicatelist[link.GetObject().GetNodeTo()])
02528 
02529                                 if link.GetObject().GetNodeFrom() not in duplicatelist: #only happens with cloning
02530                                         tmp_obj.SetNodeFrom("-1")
02531                                         tmp_obj.SetPortFrom("-1")
02532                                         tmp_obj.SetPortTypeFrom("")
02533                                         newObj.SetFixed(False)
02534                                 else:
02535                                         tmp_obj.SetNodeFrom(duplicatelist[link.GetObject().GetNodeFrom()])
02536 
02537                         objs.append(newObj)
02538                         
02539                         duplicatelist[link.GetObject().GetName()] = tmp_obj.GetName() #to handle the links afterwards
02540                         #### We show now the new object
02541                         newObj.show()
02542                 #update..so we can find by findbyname
02543                 visWindow.contents = objs + visWindow.contents
02544 
02545                 #update link connections for the nodes
02546                 for itm in prev_portListIn:
02547                         tmp_inlist = []
02548                         for port in prev_portListIn[itm]:
02549                                 if port != None:
02550                                         if port.GetObject().GetName() not in duplicatelist: #if not given link was duplicated
02551                                                 tmp_inlist.append(None)
02552                                         else:
02553                                                 tmp_inlist.append(self.FindByName(duplicatelist[port.GetObject().GetName()])) #if duplicated
02554 
02555                                 else:
02556                                         tmp_inlist.append(None)
02557 
02558                         self.FindByName(duplicatelist[itm]).SetPortList(port_IN,tmp_inlist[:])
02559 
02560                 for itm in prev_portListOut:
02561                         tmp_outlist = []
02562                         for port in prev_portListOut[itm]:
02563                                 if port != None:
02564                                         if port.GetObject().GetName() not in duplicatelist:
02565                                                 tmp_outlist.append(None)
02566                                         else:
02567                                                 tmp_outlist.append(self.FindByName(duplicatelist[port.GetObject().GetName()]))
02568                                 else:
02569                                         tmp_outlist.append(None)
02570                         self.FindByName(duplicatelist[itm]).SetPortList(port_OUT,tmp_outlist[:])
02571 
02572 
02573                 tmp_sel = self.selection[:]
02574                 self.selection = []
02575                 
02576                 self.SelectMany(objs,refresh=False)
02577                 tab = [-1,1]
02578                 tabentry = i%2
02579 
02580                 self._MoveObject(-100,tab[tabentry]*i*10) #move all selected objects
02581 
02582                 self.selection = tmp_sel
02583 
02584                 i += 1 #nrofduplicates created  
02585 
02586         #UNDO information
02587         if addtoundo:
02588                 #undo information
02589                 #redo information is always directly stolen from undo information
02590                 if len(self.selection) == 0:
02591                         return False
02592                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_NODE:
02593                         descr = "duplicate device: " + str(tmp_obj.GetName()) + " " + str(nrofduplicates) + " times"
02594                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_LINK:
02595                         descr = "duplicate link: " + str(tmp_obj.GetName()) + " " + str(nrofduplicates) + " times"
02596                 else:
02597                         descr = "duplicate objects " + str(nrofduplicates) + " times"
02598 
02599                 self.main.AddToUndo(undoindex,descr)
02600                 #undoindex had to be retrieved before anything was added to the dirty list from this function
02601                 
02602         if paintevent:
02603                 self.paintevent(None)
02604 
02605         return duplicateoriginlist
02606 
02607     ##
02608     #  Delete objects from the visual window, and add to the dirty objects
02609     #   list if set to do so.
02610     #   
02611     #   @addtoundo - whether we should add information about the action to the undo list; and 
02612     #   that the objects deleted should be deleted for real (True), if False it is only removed
02613     #   for visual appearance.
02614     #   @refresh - whether we should trigger the paint event or not.
02615     #         
02616     def DoDelete(self, event=None,addtoundo=True,refresh=True):
02617 
02618         # Ok to delete?
02619         ans = QMessageBox.question(self,"Delete ?","Are you sur you want to delete this Device.","Yes","No","",0,1)
02620         if ans == 1: # No
02621                 return
02622         if addtoundo: #check that if one try to delete a device, that it is not stored in the db yet. The ports are always stuck to the devices so if it is okey to delete a device, it is also ok to delete a port (none of them is then saved in the db)
02623                 for obj in self.selection:
02624                         if obj.GetType() == obj_NODE:
02625                                 test_obj = Device(self.main.GetActiveSystem(),obj.GetObject().GetName(),True)
02626                                 success = test_obj.Update(True) #We force to check in the db, because if it manages
02627                                 # to return data, it is already stored in db; and hence not possible to delete
02628                                 if success != False and success != {}: #managed to retrieve data from the db, thus cannot delete device
02629                                         self.main.ShowError("Cannot delete the objects in the selection because at least one of the devices (" + str(obj.GetObject().GetName()) + "), is already stored in the database.",ERR_ERROR)
02630                                         return False
02631 
02632         # Create undo information
02633         if addtoundo:
02634                 #undo information
02635                 #redo information is always directly stolen from undo information
02636                 if len(self.selection) == 0:
02637                         self.main.ShowError("Cannot delete a device and/or link because nothing is seleted.",ERR_ERROR)
02638                         return False
02639                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_NODE:
02640                         descr = "delete device: " + str(self.selection[0].GetName())
02641                 elif len(self.selection) == 1 and self.selection[0].GetType() == obj_LINK:
02642                         descr = "delete link: " + str(self.selection[0].GetName())
02643                 else:
02644                         descr = "delete objects"
02645 
02646                 undoindex = self.main.GetFirstNewUndoIndex()
02647 
02648 
02649         addlast = []
02650         addfirst = []
02651         i = len(self.selection) - 1
02652         while i >= 0: #We add the devices to a new list, so that they are tried to be deleted after all links have been deleted. Easier to see if there are any links left connected to the devices one wants to have removed
02653                 if self.selection[i].GetType() == obj_NODE:
02654                         addlast.append(self.selection.pop(i))
02655                 else: #obj_LINK
02656                         addfirst.append(self.selection.pop(i))
02657                 i -= 1
02658 
02659         #my_list = self.selection + addlast
02660         my_list = addfirst + addlast
02661         tmp_obj = None
02662         for obj in my_list:
02663 
02664             if addtoundo:
02665                     if obj.GetType() == obj_NODE:
02666                             isfree = obj.GetObject().IsAllPortsFree()
02667                     else:
02668                             isfree = True #for links, always true
02669 
02670                     if isfree == False:
02671                                 self.main.ShowError("An error occured while trying to fetch port information for " + str(obj.GetObject().GetName()) + ". Could not delete object.",ERR_ERROR)
02672                                 addlast.remove(obj)
02673                                 continue
02674                     elif isfree == -1:
02675                                 self.main.ShowError("Could not delete the device " + str(obj.GetObject().GetName()) + ", because it is connected to a non-deleted link. To delete this device, first delete the link, then the device.",ERR_ERROR)
02676                                 addlast.remove(obj)
02677                                 continue
02678 
02679             if addtoundo: #to be moved to cdbvis delete method later
02680                     try:
02681                         #remove from treelist
02682                         my_id = self.main.GetSelectWindow().GetItemID(obj.GetName())
02683                         self.main.GetSelectWindow().RemoveItem(my_id,obj.GetObject().GetType()) #link and device
02684                         self.main.GetSelectWindow().SetItemToDeleted(obj.GetName())
02685                     except KeyError,err:
02686                         print "treeitemid not found"
02687 
02688             #we copy the create object to make a delete object
02689             if addtoundo:
02690                 if not self.main.FindDirtyObject(obj.GetName(),obj.GetObject().__class__):
02691                         obj.GetObject().Delete() #set object to be deleted, and added to dirty list. We do not have to create a new object because this object is not
02692                                                  #yet in the dirtylist, and hence no references is overwritten
02693                 else:
02694                         #tmp_obj = copy.deepcopy(obj.GetObject())
02695                         if obj.GetType() == obj_NODE:
02696                                 tmp_obj = Device(self.main.GetActiveSystem(),obj.GetObject().GetName(),False)
02697                         elif obj.GetType() == obj_LINK:
02698                                 tmp_obj = Link(self.main.GetActiveSystem(),obj.GetObject().GetName(),False,False)
02699 
02700                         tmp_obj.Delete() #set the new object to delete status, and add to dirty list, has to be done before removed from contents, because
02701                                          #visual object is added to visual undo list
02702                 
02703             if obj.GetType() == obj_LINK: #remove references to this link in the nodes that this link is connected to
02704                 tmp_nodefrom = obj.GetObject().GetNodeFrom()
02705                 tmp_nodeto = obj.GetObject().GetNodeTo()
02706 
02707                 tmp_visnodefrom = self.FindByName(tmp_nodefrom)
02708                 tmp_visnodeto = self.FindByName(tmp_nodeto)
02709 
02710                 if tmp_visnodefrom != None and tmp_visnodefrom not in addlast: #only remove link info from a device if the link is deleted and not the device
02711                         tmp_portoutlist = tmp_visnodefrom.GetPortList(port_OUT)
02712                         i = 0
02713                         for port in tmp_portoutlist:
02714                                 if port == obj:
02715                                         tmp_portoutlist[i] = None
02716                                         break
02717                                 i += 1
02718                 else:
02719                         #print "There are no devices this link is connected to in the visual window any more"
02720                         pass
02721 
02722                 if tmp_visnodeto != None and tmp_visnodeto not in addlast:
02723                         tmp_portinlist = tmp_visnodeto.GetPortList(port_IN)
02724                         i = 0
02725                         for port in tmp_portinlist:
02726                                 if port == obj:
02727                                         tmp_portinlist[i] = None
02728                                         break
02729                                 i += 1
02730 
02731                 else:
02732                         #print "There are no devices this link is connected to in the visual window any more"
02733                         pass
02734 
02735                 visWindow.contents.remove(obj) #this has to be done after Delete() since Delete() grabs the visobj reference from contents
02736 
02737             elif obj.GetType() == obj_NODE:
02738                 #if we are deleting the object for real
02739                 if addtoundo: #a real delete
02740                         my_ports = obj.GetObject().GetPorts()
02741                         if my_ports == False:
02742                                 self.main.ShowError("An error occured while retrieving port data from the ConfDB: " + str(obj.GetObject().GetErrorMessage()),ERR_ERROR)
02743                         else:
02744                                 for port in my_ports:
02745                                         tmp_port = Port(self.main.GetActiveSystem(),port.GetPortNbr(),port.GetPortType(),port.GetPortWay(),port.GetDevice(),False)
02746                                         tmp_port.Delete()
02747                                 
02748                 visWindow.contents.remove(obj)  
02749 
02750             #del obj #also delete ports on devices, and set free links to non fixed
02751             if obj.GetObject().__class__ == Device and self.main.GetActiveDevice() == obj.GetName():
02752                 self.main.SetActiveDevice(None)
02753             elif obj.GetObject().__class__ == Link and self.main.GetActiveLink() == obj.GetName():
02754                 self.main.SetActiveLink(None)
02755 
02756         if (addfirst + addlast) != [] and addtoundo:
02757                 self.main.AddToUndo(undoindex,descr)
02758 
02759         self.DeselectAll(refresh=refresh)
02760 
02761     ##
02762     #  Return a list of references to the visual objects in the visual window
02763     # 
02764     #   !return - a list of references to visual objects (DrawingObject)
02765     #   
02766     def GetContents(self):
02767         return visWindow.contents
02768 
02769     ##
02770     #  Return a list of references to the visual objects in the visual window
02771     #   that are selected.
02772     # 
02773     #   !return - a list of references to visual objects (DrawingObject)
02774     #   
02775     def GetSelection(self):
02776         return self.selection
02777 
02778     ##
02779     #  Delete an object given by name.
02780     #       A object can only be deleted if it does not have any links attached to itself.
02781     # 
02782     #       @name - name of the object to delete
02783     #       @addtoundo - whether the delete information should be real and added to the 
02784     #       dirty objects list.
02785     #       @refresh - whether we should trigger a paint event or not.
02786     #         
02787     def DoDeleteObj(self, name,addtoundo=True,refresh=True):
02788         
02789         self.DeselectAll(refresh=False)
02790         visobj = self.FindByName(name)
02791 
02792         if visobj != None:
02793                 self.Select(visobj,refresh=False)
02794         else:
02795                 return False
02796         self.DoDelete(None,addtoundo,refresh=refresh)
02797 
02798     ##
02799     #  Remove all visual objects in visual window from the screen. None
02800     #   of them will be deleted for real.
02801     # 
02802     #   @onlyselected - whether only the selected objects should be deleted (True),
02803     #   or every object in the visual window should be removed (False)
02804     #   @refresh - whether we shoul trigger the paint event or not
02805     #   
02806     def DoDeleteAll(self, event = None,onlyselected=False,refresh=False):
02807         
02808         
02809         # if not onlyselected:
02810                 # for obj in visWindow.contents:
02811                     # obj.hide()
02812                     # del obj
02813                 # visWindow.contents = []
02814                 # self.DeselectAll(refresh=refresh)
02815         # else:
02816                 # for obj in self.selection:
02817                         # obj.hide()
02818                         # del obj
02819                 # self.selection = []
02820                 # list = self.canvas.collisions(QRect(self.contentsX(),self.contentsY(),self.width(),self.height()))
02821                 # for obj in list:
02822                         # obj.hide()
02823                         # del obj
02824                 # del list
02825                 # self.DeselectAll(refresh=refresh)             
02826 
02827                 
02828         self.selection = []
02829         self.main.SetActiveDevice(None)
02830         self.main.SetActiveLink(None)
02831         self.pendingItem, self.activeItem, = None, None
02832         self.__moving = None
02833         # for item in self.canvas.allItems():
02834                 # item.setCanvas(None)
02835                 
02836                 
02837         # for item in self.canvas.allItems():
02838             # if isinstance(item,myLine):
02839                 # item.setCanvas(None)
02840                 # item.nodeFrom.setCanvas(None)
02841                 # item.nodeTo.setCanvas(None)
02842                 #del item.nodeFrom
02843                 #del item.nodeTo
02844             # elif isinstance(item,Box):
02845                 # item.Canvastext.setCanvas(None)
02846                 #del item.Canvastext
02847                 # del item.portList  #PortList = {0: [<visWindow.myLine object at 0x09308C90>, None, None], 1: [None, None]}
02848                 #del item.object
02849         for item in visWindow.contents: ##self.canvas.allItems():
02850            if isinstance(item,Box) or isinstance(item,myLine):  ###### OBSELETE : dans le liste contents on n a que des lignes et des boxes.
02851                 if item not in self.keptItems:
02852                         item.hide()
02853                         item._delete()
02854                 
02855         for item in visWindow.contents: ##self.canvas.allItems():
02856                 if item not in self.keptItems:
02857                         item.setCanvas(None)
02858                         if item in visWindow.contents: visWindow.contents.remove(item)
02859                         del item
02860         list = []
02861         
02862 
02863         ### Personal memory gestion
02864         # for TYPE in [Box, myLine]:
02865                 # for i in range(len(Memo[TYPE])):
02866                         # Memo[TYPE][i][0].setCanvas(None)
02867                         # Memo[TYPE][i][1] = FREE
02868                 
02869         
02870 
02871         print " ############  WARNING : " + str(len(self.canvas.allItems())) + "  Items still in the Canvas"
02872         visWindow.contents  = []
02873         
02874         ##Check if there is kept item : (The kept items are delete the second time the DodeleteAll function is called )
02875         # if self.keptItems: # and not visWindow.contents:
02876                 ##Move item :
02877                 # for item in self.keptItems:
02878                         # if isinstance(item,Box):
02879                                 # kept = Box(self.canvas,obj_NODE, item)
02880                                 # kept.move(2500,2400)
02881                                 # kept.show()
02882                 # self.keptItems = []
02883         self.canvas.update()
02884 
02885     ##
02886     #  Respond to the "Move Forward" menu command, to move
02887     #   the selected object one step to the front; possibly
02888     #   hiding other objects.
02889     #         
02890     def DoMoveForward(self, event):
02891         if len(self.selection) != 1: return
02892 
02893         obj = self.selection[0]
02894         index = visWindow.contents.index(obj)
02895         if index == 0: return
02896 
02897         del visWindow.contents[index]
02898         visWindow.contents.insert(index-1, obj)
02899 
02900         self.Refresh()
02901         self._AdjustMenus()
02902 
02903 
02904     ##
02905     #  Respond to the "Move To The Front" menu command, to move
02906     #   the selected object all the way to the front; possibly
02907     #   hiding other objects; but not objects can hide this.
02908     #         
02909     def DoMoveToFront(self, event):
02910         if len(self.selection) != 1: return
02911 
02912         obj = self.selection[0]
02913         visWindow.contents.remove(obj)
02914         visWindow.contents.insert(0, obj)
02915 
02916         self.Refresh()
02917         self._AdjustMenus()
02918 
02919     ##
02920     #  Respond to the "Move backward" menu command, to move
02921     #   the selected object one step to the back; possibly
02922     #   being hided by other objects.
02923     #         
02924     def DoMoveBackward(self, event):
02925         
02926         if len(self.selection) != 1: return
02927 
02928         obj = self.selection[0]
02929         index = visWindow.contents.index(obj)
02930         if index == len(visWindow.contents) - 1: return
02931 
02932         del visWindow.contents[index]
02933         visWindow.contents.insert(index+1, obj)
02934 
02935         self.Refresh()
02936         self._AdjustMenus()
02937 
02938 
02939     ##
02940     #  Respond to the "Move To Back" menu command, to move
02941     #   the selected object all the way to the back; possibly
02942     #   being hided by other objects.
02943     #         
02944     def DoMoveToBack(self, event):
02945         if len(self.selection) != 1: return
02946 
02947         obj = self.selection[0]
02948         visWindow.contents.remove(obj)
02949         visWindow.contents.append(obj)
02950 
02951         self.Refresh()
02952         self._AdjustMenus()
02953 
02954 
02955     # =============================
02956     # == Object Creation Methods ==
02957     # =============================
02958 
02959     ##
02960     #  Creates a new node object at the given position and size)
02961     # 
02962     #   @x - x position to create the object (upper left corner)
02963     #   @y - y position to create the object (upper left corner)
02964     #   @obj - the data object to be created as visual object
02965     #   @refresh - whether we should trigger the paint event or not
02966     #         
02967     def CreateNode(self, x, y, obj,refresh=True): #from info to obj
02968         info = obj.GetObjectInfo(True)
02969 
02970         #set the size of the object to constants
02971         pin = info[DEV_PORTS_IN]
02972         pout = info[DEV_PORTS_OUT]
02973         maxp = 0
02974         if pin > pout:
02975                 maxp = pin
02976         else:
02977                 maxp = pout
02978         if maxp < 5:
02979                 maxp = 5
02980         if maxp > 100:
02981                 maxp = 100
02982                 
02983         new_height = NODE_HEIGHT
02984         new_width = NODE_WIDTH * maxp
02985         if maxp >= 20:
02986                 new_height += maxp/20/10
02987 
02988         obj_tmp = Box(self.canvas,obj_NODE, obj, QPoint(x, y),
02989                             QSize(new_width, new_height),
02990                             self.penColour,
02991                             Color(info[DEV_COLOUR]),
02992                             self.lineSize)
02993         ##print "///////////////////////// juste apres la cretation dans CreateNode" + str(sys.getrefcount(obj_tmp))
02994         
02995         # obj_tmp = myAlloc(Box,self.canvas,obj_NODE, object = obj, position = QPoint(x, y),
02996                             # size = QSize(new_width, new_height),
02997                             # penColour = self.penColour,
02998                             # fillColour = info[DEV_COLOUR],
02999                             # lineSize = self.lineSize)
03000         visWindow.contents.insert(0, obj_tmp)
03001         obj_tmp.SetText(str(info[DEV_NAME]))
03002         obj_tmp.SetPorts(port_IN, info[DEV_PORTS_IN])
03003         obj_tmp.SetPorts(port_OUT, info[DEV_PORTS_OUT])
03004 
03005         if refresh:
03006                 self.canvas.update()#WALID_CHANGE self.Refresh()
03007 
03008         return obj_tmp
03009 
03010 
03011     ##
03012     #  Create a new link object at the given position and size.
03013     # 
03014     #   @x1 - x position of the start of the link
03015     #   @y1 - y position of the start of the link
03016     #   @x2 - x position of the end of the link
03017     #   @y2 - y position of the end of the link
03018     #   @obj - the data object that will be created to visual object
03019     #         
03020     def CreateLink(self, x1, y1, x2, y2, obj): #from info to obj
03021 
03022         topLeftX  = min(x1, x2)
03023         topLeftY  = min(y1, y2)
03024         botRightX = max(x1, x2)
03025         botRightY = max(y1, y2)
03026 
03027         #no check whether the object was created or not...should be
03028         obj_tmp = myLine(self.canvas,obj_LINK, obj, QPoint(topLeftX, topLeftY),
03029                             QSize(botRightX-topLeftX, botRightY-topLeftY),
03030                             Qt.black,
03031                             self.fillColour,
03032                             self.lineSize,
03033                             QPoint(x1 - topLeftX, y1 - topLeftY),
03034                             QPoint(x2 - topLeftX, y2 - topLeftY))        
03035         # obj_tmp = myAlloc(myLine,self.canvas,obj_LINK, object = obj, position=QPoint(topLeftX, topLeftY),
03036                             # size=QSize(botRightX-topLeftX,
03037                                         # botRightY-topLeftY),
03038                             # penColour= Qt.black,
03039                             # fillColour=self.fillColour,
03040                             # lineSize=self.lineSize,
03041                             # startPt = QPoint(x1 - topLeftX, y1 - topLeftY),
03042                             # endPt   = QPoint(x2 - topLeftX, y2 - topLeftY))
03043         #obj_tmp.SetFixed(True) #set in createconnectedlink!
03044         obj_tmp.SetText(str(obj.GetObjectInfo(True)[DEV_LINK]))
03045         visWindow.contents.append(obj_tmp)
03046         return obj_tmp
03047 
03048     ##
03049     #  Create a new connection between two devices, where both the connection information
03050     #   for the devices connected and the link is set.
03051     # 
03052     #         The connections to nodes are set, too. They must be present as visual objects before,
03053     #         otherwise the link is NOT created and None is returned.
03054     #         The link is created at position (0,0)
03055     # 
03056     #   @object - the link data object for the connection that will be created
03057     #   @linkpos - positon of the link to be created (neglected)
03058     #   @size - size of the link being created (neglected)
03059     #   @paintevent - whether the function should trigger the paint event (True) or not (False
03060     #         
03061     def CreateConnectedLink(self, object,linkpos=QPoint(0,0),linksize=QSize(0,0),paintevent=False):
03062         deviceInfo = object.GetObjectInfo(True) 
03063         
03064         obj = self.FindByName(str(deviceInfo[DEV_LINK]))
03065         if not obj:
03066                 obj = self.CreateLink(linkpos.x(), linkpos.y(), linkpos.x() + linksize.width(), linkpos.y() + linksize.height(), object) #f.ex. info about dev- and port- from and to
03067                 obj.SetFixed(True) #set here when it is connected to two objects...
03068         else: #remove previous links for this device, in order to reconnect properly
03069                 #we found an object, we have to take care of it in case we want to undo
03070                 tmp_nodefrom = obj.GetObject().GetNodeFrom()
03071                 tmp_nodeto = obj.GetObject().GetNodeTo()
03072 
03073                 tmp_visnodefrom = self.FindByName(tmp_nodefrom)
03074                 tmp_visnodeto = self.FindByName(tmp_nodeto)
03075 
03076                 if tmp_visnodefrom != None:
03077                         tmp_portoutlist = tmp_visnodefrom.GetPortList(port_OUT)
03078                         i = 0
03079                         for port in tmp_portoutlist:
03080                                 if port == obj:
03081                                         tmp_portoutlist[i] = None
03082                                         break
03083                                 i += 1
03084                 else:
03085                         #print "Device not found to connect to!!!"
03086                         pass
03087 
03088                 if tmp_visnodeto != None:
03089                         tmp_portinlist = tmp_visnodeto.GetPortList(port_IN)
03090                         i = 0
03091                         for port in tmp_portinlist:
03092                                 if port == obj:
03093                                         tmp_portinlist[i] = None
03094                                         break
03095                                 i += 1
03096 
03097                 else:
03098                         #print "Device not found to connect to!!!"      
03099                         pass
03100 
03101         connected = False
03102         connected2 = False
03103         node_from = self.FindByName(deviceInfo[DEV_SWITCH_FROM])
03104         
03105         if node_from:
03106                 deviceindex,portnr = node_from.FindCorrespondingPortIndex(object.GetPortFrom(),object.GetPortTypeFrom(),port_OUT)
03107                 # print node_from.GetName(), node_from.GetType()
03108                 # print portnr
03109                 # print "DATAOBJETC.GetPortFrom() : " + str(object.GetPortFrom())
03110                 # print "%%%%%%%%%%%%%%%%%%%%%%"
03111                 obj.SetPortIndexFrom(deviceindex)
03112                 if portnr != -1:
03113                         connected = obj.SetConnection(node_from,port_OUT,portnr)
03114         if not connected:
03115                 self.missing_parentnodes.append([obj.GetName(),deviceInfo[DEV_SWITCH_FROM]])
03116         node_to = self.FindByName(deviceInfo[DEV_SWITCH_TO])
03117         if node_to:
03118                 deviceindex,portnr = node_to.FindCorrespondingPortIndex(object.GetPortTo(),object.GetPortTypeTo(),port_IN)
03119                 obj.SetPortIndexTo(deviceindex)
03120                 if portnr != -1:
03121                         connected2 = obj.SetConnection(node_to,port_IN,portnr)
03122         if not connected2:
03123                 self.missing_parentnodes.append([obj.GetName(),deviceInfo[DEV_SWITCH_FROM]])
03124 
03125         obj.SetText(str(deviceInfo[DEV_LINK]))
03126         #pdb.set_trace()
03127         obj.to_delta = obj.nodeTo.GetPortPosition(obj.portindexto,port_IN).x() - obj.nodeTo.x()
03128         obj.from_delta = obj.nodeFrom.GetPortPosition(obj.portindexfrom,port_OUT).x() - obj.nodeFrom.x()
03129         obj.show()
03130         if paintevent:
03131                 self.paintevent(None)
03132         return obj
03133 
03134 
03135     # =======================
03136     # == Selection Methods ==
03137     # =======================
03138 
03139     ##
03140     #  Select every DrawingObject in the visual window.
03141     # 
03142     #   @refresh - whether the paint event should be triggered or not.
03143     #         
03144     def SelectAll(self,refresh=True):
03145         
03146         self.selection = []
03147         for obj in visWindow.contents:
03148             self.selection.append(obj)
03149 
03150         if refresh:
03151                 self.Refresh()
03152 
03153         self._AdjustMenus()
03154         self.main.GetSelectWindow().UpdateInfo(None)
03155 
03156 
03157     ##
03158     #  Deselect every DrawingObject in the visual window.
03159     # 
03160     #   @refresh - whether the paint event should be triggered or not
03161     #         
03162     def DeselectAll(self,refresh=True):
03163         
03164         self.selection = []
03165 
03166         if refresh:
03167                 pass #WAL_PROB self.Refresh()
03168 
03169         self._AdjustMenus()
03170         self.main.GetSelectWindow().UpdateInfo(None)
03171 
03172     ##
03173     #  Deselect a given object.
03174     # 
03175     #   @obj - the data object of the object to be deselected
03176     #   @refresh - whether the paint event should be triggered or not
03177     #   
03178     def Deselect(self,obj,refresh=True):
03179         
03180         tmp_name = obj.GetObject().GetName()
03181         i = 0
03182         for item in self.selection:
03183                 if item.GetObject().GetName() == tmp_name:
03184                         self.selection.pop(i)
03185                 i += 1
03186 
03187         if refresh:
03188                 self.Refresh()
03189 
03190         self._AdjustMenus()
03191 
03192     ##
03193     #  Select the given DrawingObject in the visual window.
03194     # 
03195     #   @obj - the visual object of the object to be selected
03196     #   @add - whether the object should be added to an already existing
03197     #   selection of objects; or that the already existing selection of
03198     #   objects (if any) should be reset, and this object should be
03199     #   selected alone
03200     #   @showinfo - whether the info about this object should be shown in the
03201     #   information window (True) or not (False)
03202     #   @refresh - whether the paint event should be triggered or not
03203     #         
03204     def Select(self, obj,add=False,showinfo=True,refresh=True):
03205         if add == False:
03206                 self.selection = [obj]
03207         else:
03208                 self.selection.append(obj)
03209 
03210 
03211         self._AdjustMenus()
03212         if obj.GetType() in [obj_NODE]: #because 
03213             #IS this correct, should the selected device be set to the active device, and its devicetype to the active devicetype?
03214             self.main.SetActiveDeviceType(obj.GetObject().GetObjectInfo(True)[DEV_TYPE]) #should I set active device type here?
03215             self.main.SetActiveDevice(obj.GetObject().GetName())
03216             self.main.SetActiveLinkType(None)
03217             self.main.SetActiveLink(None)
03218                 
03219             if showinfo:
03220                     if add == False:
03221                         self.main.GetSelectWindow().UpdateInfo(obj.GetObject())
03222                     else:
03223                         self.main.GetSelectWindow().UpdateInfo(None)
03224                         
03225         elif obj.GetType() in [obj_LINK]:
03226                 self.main.SetActiveLinkType(obj.GetObject().GetType())
03227                 self.main.SetActiveLink(obj.GetObject().GetName())
03228                 self.main.SetActiveDeviceType(None)
03229                 self.main.SetActiveDevice(None)
03230                 if showinfo:
03231                         if add == False:
03232                                 self.main.GetSelectWindow().UpdateInfo(obj.GetObject())
03233                         else:
03234                                 self.main.GetSelectWindow().UpdateInfo(None)
03235 
03236         if refresh:
03237                 self.Refresh()
03238 
03239 
03240     ##
03241     #  Select the a range of objects.
03242     # 
03243     #   @objs - a list of visual objects that should be selected
03244     #   @refresh - whether the paint event should be triggered or not
03245     #         
03246     def SelectMany(self, objs,refresh=True):
03247         self.selection = objs
03248         
03249         if refresh:
03250                 self.Refresh()
03251 
03252         self._AdjustMenus()
03253         self.main.GetSelectWindow().UpdateInfo(None)
03254 
03255 
03256     ##
03257     #  Select every DrawingObject in the given rectangular region
03258     #   which was set up by the user (selection area).
03259     # 
03260     #   @x - x start position of selection area
03261     #   @y - y start position of selection area
03262     #   @width - width of selection area
03263     #   @height - height of selection area
03264     #         
03265     def SelectByRectangle(self, x, y, width, height):
03266         
03267         self.selection = []
03268         for obj in visWindow.contents:
03269             if obj.ObjectWithinRect(x, y, width, height):
03270                 self.selection.append(obj)
03271         self.Refresh()
03272         self._AdjustMenus()
03273         if len(self.selection) == 1:
03274             if obj.GetType() in [obj_NODE, obj_LINK]:
03275                 self.main.GetSelectWindow().UpdateInfo(obj.GetObject())
03276         else: 
03277             self.main.GetSelectWindow().UpdateInfo(None)
03278         
03279     ##
03280     #  Search after a DrawingObject (visual object) in the visual
03281     #   window by name, and return it if found
03282     # 
03283     #   @name - name of the visual object to be looking for
03284     #   
03285     #   !return - either the DrawingObject instance of the object if found,
03286     #   or None if not found.
03287     #         
03288     def FindByName(self, name):
03289         for obj in visWindow.contents:
03290             if obj.GetName() == name:
03291                 return obj
03292         return None
03293 
03294     # =====================
03295     # == Private Methods ==
03296     # =====================
03297     
03298     ##
03299     #  Adjust our menus to reflect the current state of the
03300     #             world (the objects and number of them selected)
03301     #         
03302     def _AdjustMenus(self):
03303         selection = len(self.selection) > 0
03304         onlyOne   = len(self.selection) == 1
03305         isText    = onlyOne and (self.selection[0].GetType() == obj_TEXT)
03306         front     = onlyOne and (self.selection[0] == visWindow.contents[0])
03307         back      = onlyOne and (self.selection[0] == visWindow.contents[-1])
03308 
03309     ##
03310     #  Set the currently selected tool.
03311     # 
03312     #   @newTool - a constant defining the tool to use
03313     #         
03314     def SetCurrentTool(self, newTool):
03315         if self.curTool == newTool: return # Nothing to do.
03316         self.curTool = newTool
03317 
03318 
03319     ##
03320     #  Set the default or selected objects pen colour.
03321     # 
03322     #   @colour - colour used for lines
03323     #   @refresh - whether we should trigger the paint event or not
03324     #         
03325     def _SetPenColour(self, colour,refresh=True):
03326         if len(self.selection) > 0:
03327             for obj in self.selection:
03328                 obj.SetPenColour(colour)
03329 
03330             if refresh:
03331                     self.Refresh()
03332         else:
03333             self.penColour = colour
03334             self.optionIndicator.setPenColour(colour)
03335 
03336 
03337     ##
03338     #  Set the default or selected objects fill colour.
03339     # 
03340     #   @colour - colour used for fill
03341     #   @refresh - whether we should trigger the paint event or not
03342     #         
03343     def _SetFillColour(self, colour, refresh=True):
03344         if len(self.selection) > 0:
03345             for obj in self.selection:
03346                 obj.SetFillColour(colour)
03347             if refresh:
03348                     self.Refresh()
03349         else:
03350             self.fillColour = colour
03351             self.optionIndicator.SetFillColour(colour)
03352 
03353 
03354     ##
03355     #  Set the default or selected objects line size.
03356     #   
03357     #   @size - size of line
03358     #   @refresh - whether we should trigger the paint event or not
03359     #         
03360     def _SetLineSize(self, size,refresh=True):
03361         if len(self.selection) > 0:
03362             for obj in self.selection:
03363                 obj.SetLineSize(size)
03364             if refresh:
03365                     self.Refresh()
03366         else:
03367             self.lineSize = size
03368             self.optionIndicator.SetLineSize(size)
03369 
03370 
03371     ##
03372     #  Resize the given object. The object should fit within the given 
03373     #   dimensions, though if the new point is less than the anchor point 
03374     #   the object will need to be moved as well as resized, to avoid giving 
03375     #   it a negative size.
03376     # 
03377     #   @obj - the visual object to be resized
03378     #         @anchorPt - is the unchanging corner of the object, while the
03379     #         opposite corner has been resized.
03380     #   @oldPt - are the current coordinates for the changed corner
03381     #   @newPt - are the new coordinates for the changed corner.
03382     #   @refresh - whether we should trigger the paint event or not
03383     #         
03384     def _ResizeObject(self, obj, anchorPt, oldPt, newPt,refresh=True):
03385         if obj.GetType() == obj_TEXT:
03386             # Not allowed to resize text objects -- they are sized to fit text.
03387             wxBell()
03388             return
03389 
03390         if obj.IsFixed():
03391             # object fixed, resizing not allowed
03392             return
03393 
03394         topLeft  = QPoint(min(anchorPt.x, newPt.x),
03395                            min(anchorPt.y, newPt.y))
03396         botRight = QPoint(max(anchorPt.x, newPt.x),
03397                            max(anchorPt.y, newPt.y))
03398 
03399         newWidth  = botRight.x - topLeft.x
03400         newHeight = botRight.y - topLeft.y
03401 
03402         if obj.GetType() in [obj_LINE, obj_LINK]:
03403             # Adjust the line so that its start and end points match the new
03404             # overall object size.
03405 
03406             startPt = obj.GetStartPt()
03407             endPt   = obj.GetEndPt()
03408 
03409             slopesDown = ((startPt.x < endPt.x) and (startPt.y < endPt.y)) or \
03410                          ((startPt.x > endPt.x) and (startPt.y > endPt.y))
03411 
03412             # Handle the user flipping the line.
03413 
03414             hFlip = ((anchorPt.x < oldPt.x) and (anchorPt.x > newPt.x)) or \
03415                     ((anchorPt.x > oldPt.x) and (anchorPt.x < newPt.x))
03416             vFlip = ((anchorPt.y < oldPt.y) and (anchorPt.y > newPt.y)) or \
03417                     ((anchorPt.y > oldPt.y) and (anchorPt.y < newPt.y))
03418 
03419             if (hFlip and not vFlip) or (vFlip and not hFlip):
03420                 slopesDown = not slopesDown # Line flipped.
03421 
03422             if slopesDown:
03423                 obj.SetStartPt(QPoint(0, 0))
03424                 obj.SetEndPt(QPoint(newWidth, newHeight))
03425             else:
03426                 obj.SetStartPt(QPoint(0, newHeight))
03427                 obj.SetEndPt(QPoint(newWidth, 0))
03428 
03429         # Finally, adjust the bounds of the object to match the new dimensions.
03430 
03431         obj.SetPosition(topLeft)
03432         obj.SetSize(QSize(botRight.x - topLeft.x, botRight.y - topLeft.y))
03433 
03434         if refresh:
03435                 self.Refresh()
03436 
03437 
03438     ##
03439     #  Move the currently selected object(s) by the given offset.
03440     # 
03441     #   @offsetX - offset in the x direction
03442     #   @offsetY - offset in the y direction
03443     #   @refresh - whether we should trigger the paint event or not
03444     #         
03445     def _MoveObject(self, offsetX, offsetY,refresh=True):
03446 
03447         for obj in self.selection:
03448             if not obj.IsFixed():
03449                 obj.move(obj.x() + offsetX, obj.y() + offsetY)
03450 
03451         if refresh:
03452                 self.canvas.update() #self.Refresh()
03453 
03454     ##
03455     #  Move the given object to the given position
03456     # 
03457     #   @obj - the visual object to be moved
03458     #   @posX - the new X position
03459     #   @posY - the new Y position
03460     #   @refresh - whether we should trigger the paint event or not
03461     #         
03462     def MoveObjectToPos(self, obj, posX, posY,refresh=True):
03463         pos = obj.GetPosition()
03464         pos=QPoint(posX,posY) #pos.x = posX; pos.y = posY
03465         obj.SetPosition(pos)
03466 
03467         if refresh:
03468                 self.Refresh()
03469 
03470 
03471     ##
03472     #  Return the coordinates associated with the given mouse event.
03473     # 
03474     #         The coordinates have to be adjusted to allow for the current scroll
03475     #         position.
03476     # 
03477     #         !return - QPoint(...) for the given mouse event.
03478     #         
03479     def _GetEventCoordinates(self, event):
03480         
03481         originX, originY = self.GetViewStart()
03482         unitX, unitY = self.GetScrollPixelsPerUnit()
03483         return QPoint(event.GetX() + (originX * unitX),
03484                        event.GetY() + (originY * unitY))
03485 
03486 
03487     ##
03488     #  Return the object and selection handle at the given point.
03489     # 
03490     #             We draw selection handles (small rectangles) around the currently
03491     #             selected object(s).  If the given point is within one of the
03492     #             selection handle rectangles, we return the associated object and a
03493     #             code indicating which selection handle the point is in.  If the
03494     #             point is not within any selection handle at all, we return the tuple
03495     #             (None, handle_NONE).
03496     # 
03497     #       @pt - the point we are looking for objects at (that contains this point)
03498     # 
03499     #       !return - a tuple of the visual object and its handle if found,
03500     #       (None,handle_NONE) if not.
03501     #         
03502     def _GetObjectAndSelectionHandleAt(self, pt):
03503         for obj in self.selection:
03504             handle = obj.GetSelectionHandleContainingPoint(pt.x, pt.y)
03505             if handle != handle_NONE:
03506                 return obj, handle
03507 
03508         return None, handle_NONE
03509 
03510 
03511     ##
03512     #  Return the first object found which is at the given point.
03513     # 
03514     #   @pt - the point we look for visual objects at (point within the visual object)
03515     #   @macrodevice - whether we are looking for a macro device (virtual device) or not;
03516     #   need a check because not all macro devices are clickable.
03517     # 
03518     #   !return - the first found visual object (DrawingObject) that contains the point given.
03519     #         
03520     def _GetObjectAt(self, pt,macrodevice=False):
03521         if macrodevice:
03522                 for obj in self.macroobjects:
03523                         if obj.ObjectContainsPoint(pt.x,pt.y):
03524                                 if obj.IsClickable():
03525                                         return obj
03526                                 elif not obj.IsClickable():
03527                                         continue
03528                 return None
03529 
03530         else:#nodes and links
03531                 for obj in visWindow.contents:
03532                     if obj.ObjectContainsPoint(pt.x, pt.y):
03533                         return obj
03534                 return None
03535 
03536 
03537     ##
03538     #  Draw an outline of the currently selected object.
03539     # 
03540     #             The selected objects outline is drawn at the objects position
03541     #             plus the given offset.
03542     # 
03543     #             Note that the outline is drawn by *inverting* the windows
03544     #             contents, so calling _drawObjectOutline twice in succession will
03545     #             restore the windows contents back to what they were previously.
03546     # 
03547     #       @offsetX - offset in x direction for the outline
03548     #       @offsetY - offst in y direction for the outline
03549     #         
03550     def _DrawObjectOutline(self, offsetX, offsetY):
03551         
03552         if len(self.selection) == 0: return
03553         
03554         dc = wxClientDC(self)
03555         self.PrepareDC(dc)
03556         dc.BeginDrawing()
03557         dc.SetPen(Qt.black_DASHED_PEN)
03558         dc.SetBrush(wxTRANSPARENT_BRUSH)
03559         dc.SetLogicalFunction(wxINVERT)
03560         
03561         # draw object outline for all objects in selection
03562         for obj in self.selection:
03563             position = obj.GetPosition()
03564             size     = obj.GetSize()
03565             dc.DrawRectangle(position.x + offsetX, position.y + offsetY,
03566                              size.width, size.height)
03567             
03568         dc.EndDrawing()
03569 
03570 
03571     ##
03572     #  Draw visual feedback for a drawing operation.
03573     # 
03574     #             The visual feedback consists of a line, ellipse, or rectangle based
03575     #             around the two given points.  'type' should be one of the following
03576     #             predefined feedback type constants:
03577     # 
03578     #                 feedback_RECT     ->  draw rectangular feedback.
03579     #                 feedback_LINE     ->  draw line feedback.
03580     #                 feedback_ELLIPSE  ->  draw elliptical feedback.
03581     # 
03582     #             if 'dashedLine' is True, the feedback is drawn as a dashed rather
03583     #             than a solid line.
03584     # 
03585     #             Note that the feedback is drawn by *inverting* the windows
03586     #             contents, so calling _drawVisualFeedback twice in succession will
03587     #             restore the windows contents back to what they were previously.
03588     # 
03589     #       @startPt - start point QPoint(...) x and y for the rectangle feedback
03590     #       @endPt - end point QPoint(...) x and y for the rectangle feedback
03591     #       @type - type of feedback (depends on what kind of visual object we do
03592     #       an operation on (feedback_RECT, feedback_LINE or feedback_ELLIPSE)
03593     #       @dashedLine - whether the feedback should be drawn as a dashed line or not
03594     #         
03595     def _DrawVisualFeedback(self, startPt, endPt, type, dashedLine):
03596         dc = wxClientDC(self)
03597         self.PrepareDC(dc)
03598         dc.BeginDrawing()
03599         if dashedLine:
03600             dc.SetPen(Qt.black_DASHED_PEN)
03601         else:
03602             dc.SetPen(Qt.black_PEN)
03603         dc.SetBrush(wxTRANSPARENT_BRUSH)
03604         dc.SetLogicalFunction(wxINVERT)
03605 
03606         if type == feedback_RECT:
03607             dc.DrawRectangle(startPt.x, startPt.y,
03608                              endPt.x - startPt.x,
03609                              endPt.y - startPt.y)
03610         elif type == feedback_LINE:
03611             dc.DrawLine(startPt.x, startPt.y, endPt.x, endPt.y)
03612         elif type == feedback_ELLIPSE:
03613             dc.DrawEllipse(startPt.x, startPt.y,
03614                            endPt.x - startPt.x,
03615                            endPt.y - startPt.y)
03616 
03617         dc.EndDrawing()
03618 
03619 #----------------------------------------------------------------------------
03620         
03621         
03622 ##
03623 #  An object within the drawing panel.
03624 # 
03625 #         A pySketch document consists of a front-to-back ordered list of
03626 #         DrawingObjects.  Each DrawingObject has the following properties:
03627 # 
03628 #             'type'          What type of object this is (node, link or macro (virtual))
03629 #             'position'      The position of the object within the document.
03630 #             'size'          The size of the object within the document.
03631 #             'penColour'     The colour to use for drawing the objects outline.
03632 #             'fillColour'    Colour to use for drawing objects interior.
03633 #             'lineSize'      Line width (in pixels) to use for objects outline.
03634 #             'startPt'       The point, relative to the objects position, where
03635 #                             an obj_LINE objects line should start.
03636 #             'endPt'         The point, relative to the objects position, where
03637 #                             an obj_LINE objects line should end.
03638 #             'text'          The objects text (obj_TEXT objects only).
03639 #             'textFont'      The text objects font name.
03640 #             'textSize'      The text objects point size.
03641 #             'textBoldface'  If True, this text object will be drawn in
03642 #                             boldface.
03643 #             'textItalic'    If True, this text object will be drawn in italic.
03644 #             'textUnderline' If True, this text object will be drawn underlined.
03645 #             'linkLength'    Integer how long the link connectors of a node are
03646 #             'fixed'         If True, the object is connected with others and cannot be resized alone   
03647 #             'object'      Data object (device or link) defined with the visual object
03648 #             'portList'      List of link objects connected to a node
03649 #           'expanded'      Boolean, whether the neighbours of given _node_ is expanded or not..For use in dynamic link view                             mode.
03650 #           'zoomfactor'    Integer, what zoom the visual object has right now.
03651 #           'clickable'     Boolean, whether the visual object is click-sensitive (triggers visual feedback) when you click
03652 #                           on it or not.
03653 #           'originalsize'  QSize, the original size of the object in 100% zoom.
03654 #           'macroid'       Integer, the unique macroID needed to identify macro/virtual objects
03655 #           'textvalign'    Integer constant, where the text should be placed vertically on the object: text_CENTER,
03656 #                           text_RIGHT or text_LEFT
03657 #           'texthaling'    Integer constant, where the text should be placed horizontally ont he object; text_CENTER,
03658 #                           text_TOP or text_BOTTOM.
03659 #             
03660 class DrawingObject:
03661 
03662     def __init__(self, canvas, type, object = None, position=QPoint(0, 0), size=QSize(0, 0),
03663                  penColour=Qt.black, fillColour=Qt.white, lineSize=1,
03664                  text=None, startPt=QPoint(0, 0), endPt=QPoint(0,0),zoomFactor=100,clickable=True,originalsize=QSize(0,0),macroid=-1,textvalign=text_CENTER,texthalign=text_CENTER):
03665         """ Standard constructor.
03666 
03667             'type' is the type of object being created.  This should be one of
03668             the following constants: obj_NODE, obj_LINK, obj_MACRODEVICE
03669 
03670             The remaining parameters is explained above for the class.
03671         """
03672         QCanvasRectangle.__init__(self, canvas)
03673         self.i = 0 # temporary to remove !!  has no effect !!
03674         self.type              = type
03675         self.position          = position
03676         self.size              = size
03677         self.penColour         = penColour
03678         self.fillColour        = fillColour
03679         self.lineSize          = lineSize
03680         self.startPt           = startPt
03681         self.endPt             = endPt
03682         self.text              = text
03683         self.layer             = 0 #default layer...
03684         self.textFont          = "Arial" # wxSystemSettings_GetSystemFont( wxSYS_DEFAULT_GUI_FONT).GetFaceName()
03685         self.textvalign = textvalign
03686         self.texthalign = texthalign
03687         self.textSize          = 10
03688         self.textBoldface      = False
03689         self.textItalic        = False
03690         self.textUnderline     = False
03691         self.canvas = canvas
03692 
03693         self.linkLength        = 7
03694         self.fixed             = False
03695         self.zoomFactor        = zoomFactor
03696         if type == obj_LINK:
03697                 self.portindexfrom = -1 #index of the port on the given device its connected to the output
03698                 self.portindexto = -1 #index of the port on the given device it is connected to the input
03699 
03700         self.object             = object
03701 
03702         self.expanded           = 0 #always totally collapsed for links, 1 or 2 for nodes if expanded
03703 
03704         self.clickable = clickable
03705 
03706         self.originalsize = originalsize
03707         self.macroid = macroid
03708         
03709         # only used by obj_NODE: obj_LINK objects saved for each port
03710         if self.type == obj_NODE and self.object:
03711                 deviceinfo_tmp = self.object.GetObjectInfo(True)
03712                 self.portList  = {port_IN: [None for i in range(max(deviceinfo_tmp[DEV_PORTS_IN], 0))],
03713                                   port_OUT: [None for i in range(max(deviceinfo_tmp[DEV_PORTS_OUT], 0))]}
03714         else: self.portList    = {port_IN: [], port_OUT: []}
03715         
03716         
03717 
03718     # =============================
03719     # == Object Property Methods ==
03720     # =============================
03721 
03722     ##
03723     #  Return a copy of the objects internal data.
03724     #             This is used to save this DrawingObject to disk.
03725     # 
03726     #       !return a list of all member variables in this object.
03727     #         
03728     def GetData(self):
03729         return [self.type, self.x(), self.y(),
03730                 self.width(), self.height(),
03731                 self.penColour.red(),
03732                 self.penColour.green(),
03733                 self.penColour.blue(),
03734                 self.fillColour.red(),
03735                 self.fillColour.green(),
03736                 self.fillColour.blue(),
03737                 self.lineSize,
03738                 self.startPt.x(), self.startPt.y(),
03739                 self.endPt.x(), self.endPt.y(),
03740                 self.text,
03741                 self.textFont,
03742                 self.textSize,
03743                 self.textBoldface,
03744                 self.textItalic,
03745                 self.textUnderline,
03746                 self.linkLength,
03747                 self.fixed,
03748                 self.object,
03749                 self.portList,self.expanded,self.zoomFactor]
03750 
03751 
03752     ##
03753     #  Set the objects internal data.
03754     # 
03755     #             @data is a copy of an objects member variables, as returned by
03756     #             getData() above.  This is used to restore a previously saved
03757     #             DrawingObject.
03758     #         
03759     def SetData(self, data):
03760         
03761         self.type              = data[0]
03762 
03763         self.position          = QPoint(data[1], data[2])
03764         self.size              = QSize(data[3], data[4])
03765         self.penColour         = QColor(data[5], data[6], data[7])
03766         self.fillColour        = QColor(data[8], data[9], data[10])
03767         self.lineSize          = data[11]
03768         self.startPt           = QPoint(data[12], data[13])
03769         self.endPt             = QPoint(data[14], data[15])
03770         self.text              = data[16]
03771         self.textFont          = data[17]
03772         self.textSize          = data[18]
03773         self.textBoldface      = data[19]
03774         self.textItalic        = data[20]
03775         self.textUnderline     = data[21]
03776         self.linkLength        = data[22]
03777         self.fixed             = data[23]
03778         
03779         #NB!!!!! Handle carefully...we copy the object reference
03780         if self.type == obj_NODE: # We have to create a new device object for this visual object, cannot
03781                 #reference to the old one
03782                 self.object = Device(data[24].GetSystem(),data[24].GetName(),False)
03783         elif self.type == obj_LINK:
03784                 self.object = Link(data[24].GetSystem(),data[24].GetName(),False,False)
03785 
03786         if self.type == obj_NODE:
03787                 self.portList = {}
03788                 for item in data[25]:
03789                         self.portList[item] = data[25][item]
03790 
03791                 self.expanded = data[26]
03792 
03793         self.zoomFactor = data[27]
03794 
03795     ##
03796     #  Return this DrawingObjects type (obj_NODE, obj_LINK or obj_MACRODEVICE)
03797     #         
03798     def GetType(self):
03799         return self.type
03800 
03801     def SetLayer(self,layer):
03802         self.layer = layer
03803     def GetLayer(self):
03804         return self.layer
03805 
03806     ##
03807     #  Set the position (top-left corner) for this DrawingObject.
03808     # 
03809     #   @position - QPoint for top-left corner for this object.
03810     #   @adjust - whether the links to this object (if obj_NODE) should be adjusted
03811     #   to the new position.
03812     #         
03813     def SetPosition(self, position, adjust = True):
03814         self.position = QPoint(position.x(),position.y())
03815         if self.type == obj_NODE or self.type == obj_LINK:
03816                 if adjust: self._AdjustLinks()
03817     ##
03818     #  Return this DrawingObjects position.
03819     # 
03820     #   !return QPoint(...) for the position of the top-left corner of this object.
03821     #         
03822     def GetPosition(self):
03823         return self.position
03824 
03825     ##
03826     #  For visual objects of type obj_LINK, the port index they go from an
03827     #   obj_NODE (port index is the internal port numbering; from 0 to n-1 for the 
03828     #   port way).
03829     #   
03830     def GetPortIndexFrom(self):
03831         return self.portindexfrom
03832 
03833     ##
03834     #  For visual objects of type obj_LINK, the port index they go to an
03835     #   obj_NODE (port index is the internal port numbering; from 0 to n-1 for the 
03836     #   port way).
03837     #   
03838     def GetPortIndexTo(self):
03839         return self.portindexto
03840 
03841     ##
03842     #  Set internal port index, converted from the port number and port type.
03843     #   
03844     def SetPortIndexFrom(self,index):
03845         self.portindexfrom = index
03846     ##
03847     #  Set internal port index, converted from the port number and port type.
03848     #   
03849     def SetPortIndexTo(self,index):
03850         self.portindexto = index
03851 
03852     ##
03853     #  The expanded status of this obj_NODE.
03854     #   
03855     def GetExpanded(self):
03856         return self.expanded
03857 
03858     ##
03859     #  
03860     #           expanded - 0: totally collapsed
03861     #           expanded - 1: partly collapse/expanded
03862     #           expanded - 2: totally expanded
03863     #   
03864     def SetExpanded(self,expanded):
03865         self.expanded = expanded
03866 
03867     def SetZoomFactor(self,zf):
03868         self.zoomFactor = zf
03869     def GetZoomFactor(self):
03870         return self.zoomFactor
03871 
03872     ##
03873     #  Set the size for this DrawingObject.
03874     # 
03875     #   @size - QSize object
03876     #   @adjust - whether the links and a obj_NODE should be adjusted.
03877     #         
03878     def SetSize(self, size, adjust = True):
03879         self.size = size
03880         if self.type == obj_NODE or self.type == obj_LINK:
03881                 if adjust: self._AdjustLinks()
03882 
03883 
03884     ##
03885     #  Return this DrawingObjects size.
03886     #         
03887     def GetSize(self):
03888         return self.size
03889 
03890 
03891     ##
03892     #  Set the pen colour used for this DrawingObject.
03893     #         
03894     def SetPenColour(self, colour):
03895         self.penColour = colour
03896 
03897 
03898     ##
03899     #  Return this DrawingObjects pen colour.
03900     #         
03901     def GetPenColour(self):
03902         return self.penColour
03903 
03904 
03905     ##
03906     #  Set the fill colour used for this DrawingObject.
03907     #         
03908     def SetFillColour(self, colour):
03909         self.fillColour = colour
03910 
03911 
03912     ##
03913     #  Return this DrawingObjects fill colour.
03914     #         
03915     def GetFillColour(self):
03916         return self.fillColour
03917 
03918 
03919     ##
03920     #  Set the linesize used for this DrawingObject.
03921     #         
03922     def SetLineSize(self, lineSize):
03923         self.lineSize = lineSize
03924 
03925 
03926     ##
03927     #  Return this DrawingObjects line size.
03928     #         
03929     def GetLineSize(self):
03930         return self.lineSize
03931 
03932 
03933     ##
03934     #  Set the starting point for this line DrawingObject.
03935     #         
03936     def SetStartPt(self, startPt):
03937         self.startPt = startPt
03938 
03939 
03940     ##
03941     #  Return the starting point for this line DrawingObject.
03942     #         
03943     def GetStartPt(self):
03944         return self.startPt
03945 
03946 
03947     ##
03948     #  Set the ending point for this line DrawingObject.
03949     #         
03950     def SetEndPt(self, endPt):
03951         self.endPt = endPt
03952 
03953 
03954     ##
03955     #  Return the ending point for this line DrawingObject.
03956     #         
03957     def GetEndPt(self):
03958         return self.endPt
03959 
03960 
03961     ##
03962     #  Set the text for this DrawingObject.
03963     #         
03964     def SetText(self, text):
03965         self.text = text
03966 
03967 
03968     ##
03969     #  Return this DrawingObjects text.
03970     #         
03971     def GetText(self):
03972         return self.text
03973 
03974 
03975     ##
03976     #  Set the typeface for this text DrawingObject.
03977     #         
03978     def SetTextFont(self, font):
03979         self.textFont = font
03980 
03981 
03982     ##
03983     #  Return this text DrawingObjects typeface.
03984     #         
03985     def GetTextFont(self):
03986         return self.textFont
03987 
03988 
03989     ##
03990     #  Set the point size for this text DrawingObject.
03991     #         
03992     def SetTextSize(self, size):
03993         self.textSize = size
03994 
03995 
03996     ##
03997     #  Return this text DrawingObjects text size.
03998     #         
03999     def GetTextSize(self):
04000         return self.textSize
04001 
04002 
04003     ##
04004     #  Set the boldface flag for this text DrawingObject.
04005     #         
04006     def SetTextBoldface(self, boldface):
04007         self.textBoldface = boldface
04008 
04009 
04010     ##
04011     #  Return this text DrawingObjects boldface flag.
04012     #         
04013     def GetTextBoldface(self):
04014         return self.textBoldface
04015 
04016 
04017     ##
04018     #  Set the italic flag for this text DrawingObject.
04019     #         
04020     def SetTextItalic(self, italic):
04021         self.textItalic = italic
04022 
04023 
04024     ##
04025     #  Return this text DrawingObjects italic flag.
04026     #         
04027     def GetTextItalic(self):
04028         return self.textItalic
04029 
04030 
04031     ##
04032     #  Set the underling flag for this text DrawingObject.
04033     #         
04034     def SetTextUnderline(self, underline):
04035         self.textUnderline = underline
04036 
04037 
04038     ##
04039     #  Return this text DrawingObjects underline flag.
04040     #         
04041     def GetTextUnderline(self):
04042         return self.textUnderline
04043 
04044     def IsClickable(self):
04045         return self.clickable
04046     def GetOriginalSize(self):
04047         return self.originalsize #QSize object; (w,h)
04048     def GetMacroID(self):
04049         return self.macroid
04050     def SetMacroID(self,macroid):
04051         self.macroid = macroid #ID of the macro device in the given level
04052 
04053 
04054     ##
04055     #  Assign data object to this visual object; Device for obj_NODe
04056     #   and Link for obj_LINK.
04057     # 
04058     #   @object - the data object to be assigned to this object.
04059     #         
04060     def SetObject(self, object):
04061         if self.type == obj_NODE:
04062                 self.object = Device(object.GetSystem(),object.GetName(),False)
04063         elif self.type == obj_LINK:
04064                 self.object = Link(object.GetSystem(),object.GetName(),False,False)
04065                 
04066     ##
04067     #  Assign a data object reference to this visual object; Device for obj_NODE
04068     #   and Link for obj_LINK
04069     #   
04070     def SetObjectRef(self,object):
04071         self.object = object
04072         self.text = self.object.GetName()
04073 
04074     ##
04075     #  Return object with deviceInfo..reference
04076     #         
04077     def GetObject(self):
04078         return self.object
04079         
04080     ##
04081     #  Return name of visual object, which
04082     #   is retrieved from the data object it has
04083     #   assigned.
04084     #         
04085     def GetName(self):
04086         return self.object.GetName()
04087         
04088     ##
04089     #  Set if object is fixed to another object
04090     #         
04091     def SetFixed(self, fixed):
04092         self.fixed = fixed
04093 
04094     ##
04095     #  Return, wheter object is fixed
04096     #         
04097     def IsFixed(self):
04098         return self.fixed
04099 
04100     ##
04101     #  Set the number of ports of port way (only obj_NODE)
04102     #   for this object, we have one list for each port way (in
04103     #   and out)
04104     # 
04105     #   @portType - the port way this list of ports is assigned to
04106     #   @nr - nr of ports to assigned to the given port way
04107     #         
04108     def SetPorts(self, portType, nr):
04109         self.portList[portType] = [None for i in range(nr)]
04110 
04111     ##
04112     #  Return the number of ports of given port way.
04113     # 
04114     #   @portType - port way to get port list for.
04115     # 
04116     #   !return - list of ports (port indexes) for given port way.
04117     #         
04118     def GetPorts(self, portType):
04119         return len(self.portList[portType])
04120 
04121     ##
04122     #  Remove the references to links in the port lists
04123     #   for this visual object (if obj_NODE).
04124     #   
04125     def ClearPorts(self):
04126         self.SetPorts(port_IN, self.GetPorts(port_IN))
04127         self.SetPorts(port_OUT, self.GetPorts(port_OUT))
04128 
04129     ##
04130     #  Set the port list for the given port way.
04131     # 
04132     #   @portType - port way to set the port list for
04133     #   @list - list of references to links to set for this port way
04134     #   for this visual object.
04135     #         
04136     def SetPortList(self, portType, list):
04137         self.portList[portType] = list
04138 
04139     ##
04140     #  Return objects to all links connected to ports at portType
04141     #         
04142     def GetPortList(self, portType):
04143         return self.portList[portType]
04144 
04145     ##
04146     #  Return all the references to links in the port lists
04147     #   for this visual object, if this is of type obj_NODE
04148     # 
04149     #   !return - a list of references to link visual objects referred
04150     #   to in the port list of this device
04151     #         
04152     def GetLinks(self):
04153         list = []
04154         if obj_NODE == self.GetType():
04155             for obj in self.GetPortList(port_IN) + self.GetPortList(port_OUT):
04156                 if obj: list.append(obj)
04157         return list
04158 
04159     ##
04160     #  Find corresponding port index for a port number, port type and port direction
04161     #       collection for a port. This is "calculated" by using specific algorithms for each
04162     #       device type because of the big differences in how the devices are given port number
04163     #       and port types as well as port direction.
04164     # 
04165     #       @portnbr - the port number of the port
04166     #       @porttype - the port type of the port
04167     #       @portdirection - the port direction/way of the port
04168     # 
04169     #       !return - a tuple of port_index and port_number; the port index is the internal
04170     #       indexing of the port in this class, and the port number is the place where it is
04171     #       added to in the port list.
04172     #   
04173     def FindCorrespondingPortIndex(self,portnbr="",porttype="",portdirection=port_IN):
04174 
04175         #standard indexing, as f.ex. FEEs use
04176         # IN/OUT PORTS
04177         port = -1
04178         i = 0
04179         for obj in self.GetPortList(portdirection):
04180                 if obj == None: # look for free port
04181                         port = i+1 #portnr, not the index
04182                         break
04183                 i += 1
04184         if port == -1: #all ports filled up
04185                 print "No free ports found."
04186                 return -1,-1 #both index in portlist and index on device set to -1
04187 
04188         try:
04189                 if self.GetObject().GetType() == "M5R4":
04190                         if porttype.lower() in ["a","b"]:
04191                                 if porttype.lower() == "a":
04192                                         offset = int(portnbr)/8 * 8
04193                                 else:
04194                                         offset = (int(portnbr)+8)/8 * 8
04195                                 index = int(portnbr) + offset
04196                         elif porttype.lower() == "ab":
04197                                 offset = 48 #48 FEE ports
04198                                 index = int(portnbr) + offset
04199                         else:
04200                                 print "The M5R4 device does not have correct syntax on all ports. Fix this according to the syntax given in the documentation!"
04201                                 return -1,-1
04202                 else:   #standard device with default numbering, like this:
04203                         # __________________
04204                         # | 0 1 2 3 4 5 6 7| #numbering of input ports starts top left from 0
04205                         # |                |
04206                         # | 0 1 2 3 4 5 6 7| #numbering of output ports starts bottom left from 0
04207                         # ------------------
04208 
04209                         index = int(portnbr)
04210 
04211                 #print "Returning: " + str(index) + " and " + str(port)
04212                 return index,port
04213         except ValueError,err:
04214                 print "An error occured while trying to find corresponding index to portnbr, porttype and portdirection. The portnbr for M5R4s must have an integer as portnbr. Correct this, and try to connect."
04215                 return -1,-1
04216         
04217 
04218     # ========================================
04219     # == More spezialized get/set-functions ==
04220     # ========================================
04221     
04222     ##
04223     #  Get the port position on a visual object (obj_NODE) as a QPoint(...) 
04224     #   for a given port index.
04225     # 
04226     #   @index - port index of the port in the given port list (port way list)
04227     #   @portdir - port direction/way for the port.
04228     #   
04229     #         !return - QPoint of port (obj_NODE only)
04230     #         
04231     def GetPortPosition(self, index,portdir):
04232         #print "GetPortPosition Called " + str(self.i) + " time"
04233 
04234         if self.GetType() == obj_NODE:
04235             if self.GetObject().GetType() == "M5R4":
04236                 #I already know the number and location of the ports
04237                 # INOUTPORTS
04238                 if index >= 0:
04239                         if index < 48: #0-23 A,B FEE OUT
04240                                 if GetZoomFactor() < 50: #50% zoom
04241                                         xPos = self.position.x() + self.size.width()/2
04242                                         yPos = self.position.y() + self.size.height()
04243                                 else:
04244                                         xPos = self.position.x() + self.size.width()*(index+1)/(49)
04245                                         yPos = self.position.y() + self.size.height() + self.linkLength
04246                         elif index < 52: #0-3 AB HV IN
04247                                 if GetZoomFactor() < 50: #50% zoom
04248                                         xPos = self.position.x() + self.size.width()
04249                                         yPos = self.position.y() + self.size.height()/2
04250                                 else:
04251                                         xPos = self.position.x() + self.size.width() + self.linkLength - 1
04252                                         yPos = self.position.y() + self.size.height() - self.size.height()*(index+1-48)/(5)
04253                         elif index < 54: #4-5 AB GAS IN,OUT
04254                                 if GetZoomFactor() < 50: #50% zoom
04255                                         xPos = self.position.x()
04256                                         yPos = self.position.y() + self.size.height()/2
04257                                 else:
04258                                         xPos = self.position.x() - self.linkLength + 1
04259                                         yPos = self.position.y() + self.size.height()*(index+1-52)/(5)
04260                         else:
04261                                 print "Portindex is not valid. The given portindex cannot be found for the given devicetype: M5R4"
04262                                 return QPoint(-1,-1)
04263             else:
04264                     if GetZoomFactor() >= 50: #50% zoom
04265                         #pdb.set_trace()
04266                         xPos = self.x() + self.width()*(index+1)/(self.GetPorts(portdir)+1) #may fail, if index starts on 1 instead of 0
04267                         if portdir == port_IN:
04268                             yPos = self.y() - self.linkLength
04269                         else:
04270                             yPos = self.y() + self.height() + self.linkLength
04271                     else: #less than 50% zoom
04272                         xPos = self.x() + self.width()/2
04273                         if portdir == port_IN:
04274                             yPos = self.y()
04275                         else:
04276                             yPos = self.y() + self.height()
04277                         
04278             return QPoint(xPos, yPos)
04279         else:
04280                 return (-1,-1)
04281                 
04282     ##
04283     #  Connect the given link to the specified port of portType.
04284     #             
04285     # 
04286     #       @portType - the port way of the port (portIN or portOUT)
04287     #       @portNr - the port number of the port, 1 -> n, internal indexing
04288     #       of the port numbers
04289     #       @link - the visual object link that will be connected to a 
04290     #       port on a visual object device
04291     #       @override - whether we should set this link to the given port
04292     #       even when it is taken by another link.
04293     #       
04294     #             !return - True if port is set, else False
04295     #         
04296     def SetSinglePort(self, portType, portNr, link, override = True):
04297         if link.__class__ == myLine and link.GetType() == obj_LINK:
04298             if portNr > self.GetPorts(portType):
04299                 return False
04300             if self.portList[portType][portNr-1]: #portnr 1 is stored in the 0th position a.s.o.
04301                 # port already set
04302                 if override:
04303                     print "WARNING: Overwriting port already connected (port %i (type %i) of %s)" \
04304                            %(portNr, portType, self.GetName())
04305                 else:
04306                     # do not set port, leave old connection
04307                     print  "ERROR: Tried to overwrite port already connected. \
04308                               (port %i (type %i) of %s). NO overwritign activated" \
04309                               %(portNr, portType, self.GetName())
04310                                
04311                     return False
04312 
04313             self.portList[portType][portNr-1] = link
04314             return True
04315            
04316 
04317     ##
04318     #  Connect two DrawingObjects (links and nodes) together.
04319     # 
04320     #   @partner - the link or node that this object should be connected to.
04321     #   @portType - the port way they should connect to on the device.
04322     #   @portNr - the port number (internal indexing) they should connect to on
04323     #   the device
04324     #   @setPartner - whether the connection should be set for the partner of this
04325     #   as well (this method called for the partner as well)
04326     #   
04327     #         !return - True if connection is set, else False
04328     #         
04329     def SetConnection(self, partner, portType, portNr, setPartner = True):
04330         connected = False
04331         if self.GetType() == obj_NODE:
04332             if partner.__class__ == myLine and \
04333                partner.GetType() == obj_LINK and \
04334                portNr <= self.GetPorts(portType) and \
04335                portType in [port_IN, port_OUT]:
04336                     connected = self.SetSinglePort(portType, portNr, partner)
04337                     if setPartner: 
04338                         partner.SetConnection(self, portType, portNr, False)
04339             else: 
04340                 print "Connection failed (node)"
04341                     
04342         elif self.GetType() == obj_LINK:
04343             if partner.__class__ == Box and \
04344                partner.GetType() == obj_NODE and \
04345                portNr <= partner.GetPorts(portType) and \
04346                portType in [port_IN, port_OUT]: #if we have 2 ports on a device, portnr 1 in and portnr 2 out *or opposite*. 1 outports, 1 inports.
04347                     if portType == port_IN:
04348                         self.nodeTo = partner
04349                         self.portTo = portNr
04350                         self._AdjustLinks(None, partner.GetPortPosition(self.GetPortIndexTo(),port_IN))
04351                     else: #portType == port_OUT
04352                         self.nodeFrom = partner
04353                         self.portFrom = portNr
04354                         #WAL_OBSELETE ?????  self._AdjustLinks(partner.GetPortPosition(self.GetPortIndexFrom(),port_OUT), None)
04355                     if setPartner:
04356                         connected = partner.SetConnection(self, portType, portNr, False)
04357             else:
04358                 print "Connection failed (link)" 
04359 
04360         else:
04361             print "Connection failed: wrong type : %s"%str(self.GetType())
04362         return connected
04363 
04364             
04365             
04366     # ============================
04367     # == Object Drawing Methods ==
04368     # ============================
04369 
04370     ##
04371     #  Add two QPoint objects together.
04372     # 
04373     #   @point1 - the first QPoint(...) object
04374     #   @point2 - the second QPoint(...) object
04375     #   
04376     def AddPoints(self, point1, point2):
04377         return QPoint(point1.x() + point2.x(), point1.y() + point2.y())
04378 
04379     ##
04380     #  If links are moved or resized; the nodes they
04381     #   are connected to needs to be adjusted. If nodes are moved
04382     #   or resized; the links that connect tot hem need to be
04383     #   adjusted.
04384     # 
04385     #   @startPt - starting point QPoint(...) for the object this
04386     #   object needs to be adjusted to
04387     #   @endPt - end point QPoint(...) for the object this object
04388     #   need to be adjusted to
04389     #   
04390     def _AdjustLinks(self, startPt = None, endPt = None):
04391         
04392         if self.GetType() == obj_NODE:
04393                 for i in range(len(self.portList[port_IN])):
04394                         link = self.portList[port_IN][i]
04395                         if link:
04396                             pos = link.GetPosition()
04397                             start = link.GetStartPt()
04398                             
04399                             link._AdjustLinks(QPoint(pos.x()+start.x(), pos.y()+start.y()), self.GetPortPosition(link.GetPortIndexTo(),port_IN))
04400                 for i in range(len(self.portList[port_OUT])):
04401                         link = self.portList[port_OUT][i]
04402                         if link:
04403                             pos = link.GetPosition()
04404                             end = link.GetEndPt()
04405                             link._AdjustLinks(self.GetPortPosition(link.GetPortIndexFrom(),port_OUT), QPoint(pos.x()+end.x(), pos.y()+end.y()))
04406             
04407         elif self.GetType() == obj_LINK:
04408             if startPt == None: 
04409                 startPt = self.AddPoints(self.GetPosition(), self.GetStartPt())
04410             if endPt == None: 
04411                 endPt = self.AddPoints(self.GetPosition(), self.GetEndPt())
04412             topLeftX  = min(startPt.x(), endPt.x())
04413             topLeftY  = min(startPt.y(), endPt.y())
04414             botRightX = max(startPt.x(), endPt.x())
04415             botRightY = max(startPt.y(), endPt.y())
04416             
04417             self.SetPosition(QPoint(topLeftX, topLeftY), False)
04418             self.SetSize(QSize(botRightX-topLeftX, botRightY-topLeftY), False)
04419             self.SetStartPt(QPoint(startPt.x() - topLeftX, startPt.y() - topLeftY))
04420             self.SetEndPt(QPoint(endPt.x() - topLeftX, endPt.y() - topLeftY))
04421         
04422     def _delete(self):
04423         self.i = 0 
04424         ##del self.type             # = None
04425         del self.position         # = None
04426         del self.size             # = None
04427         del self.penColour        # = None
04428         del self.fillColour       # = None
04429         del self.lineSize         # = None
04430         del self.startPt          # = None
04431         del self.endPt            # = None
04432         del self.text             # = None
04433         del self.layer        # = None
04434         del self.textFont         # = None
04435         del self.textvalign # = None
04436         del self.texthalign # = None
04437         del self.textSize         # = None
04438         del self.textBoldface     # = None
04439         del self.textItalic       # = None
04440         del self.textUnderline    # = None
04441         del self.canvas# = None
04442         #del self.linkLength       # = None
04443         del self.fixed            # = None
04444         del self.zoomFactor           # = None
04445         #del self.portindexfrom# = None #index of the port on the given device its connected to the output
04446         #del self.portindexto# = None #index of the port on the given device it is connected to the input
04447         del self.object #       = None
04448         del self.expanded               #= None #always totally collapsed for links, 1 or 2 for nodes if expanded
04449         del self.clickable# = None
04450         del self.originalsize# = None
04451         del self.macroid# = None
04452         ##del self.deviceinfo_tmp # = None
04453         del self.portList # = None
04454 
04455         
04456 i = 0
04457 class Box(QCanvasRectangle,DrawingObject):
04458 
04459     def __init__(self, canvas, type, object = None, position=QPoint(0,0), size=QSize(3, 3),
04460                  penColour=Qt.black, fillColour=Qt.white, lineSize=1,
04461                  text=None,zoomFactor=100,clickable=True,originalsize=QSize(0,0),macroid=-1,textvalign=text_CENTER,texthalign=text_CENTER):
04462         DrawingObject.__init__(self, canvas, type, object, position, size, penColour, fillColour, lineSize,text, QPoint(0,0), QPoint(0,0),zoomFactor,clickable,originalsize,macroid,textvalign,texthalign)
04463         QCanvasRectangle.__init__(self, canvas)
04464         ##visWindow.contents.append(self)
04465         if self.object:
04466                 self.Canvastext = QCanvasText(self.GetName(),canvas)
04467                 self.Canvastext.setTextFlags(Qt.AlignCenter)
04468                 self.Canvastext.setFont(QFont("Arial",10))
04469                 self.setSize(size.width(),size.height())
04470                 self.move(position.x(),position.y())
04471 
04472                 fillColour = Color(self.fillColour)
04473                 self.setPen( QPen(QColor(0,0,0)) )
04474                 self.setBrush(QBrush(Color(self.fillColour)))
04475                 if fillColour.red()+fillColour.blue()+fillColour.green() < 200:
04476                         self.Canvastext.setColor(QColor(150,150,150))
04477 
04478     def SetData(self,data):
04479         DrawingObject.SetData(self,data)
04480         self.Canvastext = QCanvasText(self.GetName(),self.canvas)
04481         self.Canvastext.setTextFlags(Qt.AlignCenter)
04482         self.Canvastext.setFont(QFont("Arial",10,QFont.Bold))
04483         self.setSize(self.size.width(),self.size.height())
04484         fillColour = Color(self.fillColour)
04485         self.setPen( QPen(QColor(0,0,0)) )
04486         self.setBrush(QBrush(Color(self.fillColour)))
04487         if self.fillColour.red()+self.fillColour.blue()+self.fillColour.green() < 200:
04488                 self.Canvastext.setColor(QColor(150,150,150))
04489         
04490     def setCanvas(self,c):
04491         try:
04492            self.Canvastext.setCanvas(c)
04493         except:
04494                 print "WARNING : CanvasText not found"
04495         QCanvasItem.setCanvas(self,c)
04496 
04497     def hide(self):
04498         QCanvasRectangle.hide(self)
04499         try:
04500            self.Canvastext.hide()
04501         except:
04502            pass
04503     def _delete(self):
04504         try:
04505                 #DrawingObject._delete(self)
04506                 self.Canvastext = None
04507                 #del self.nodeFrom
04508                 #del self.nodeTo # = None, None
04509                 self.object = None
04510                 del self.portList #= None
04511                 self.canvas = None
04512         except:
04513                 pass
04514         
04515     def show(self):
04516         QCanvasRectangle.show(self)
04517         self.Canvastext.show()
04518         self.Canvastext.setZ(self.z()+1)
04519         self.Canvastext.move(self.x()+self.width()/2,self.y()+self.height()/2)
04520         self.Canvastext.move(self.x()+self.width()/2,self.y()+self.height()/2)
04521 
04522     def moveBy(self,x,y):
04523         QCanvasRectangle.moveBy(self,x,y)
04524         self.Canvastext.moveBy(x,y)
04525 
04526     def move(self,x,y):
04527         QCanvasRectangle.move(self,abs(x)%5000,abs(y)%5000)
04528 
04529     def SetSize(self, size, adjust = True):
04530         DrawingObject.SetSize(self,size,adjust)
04531         self.setSize(size.width(),size.height())
04532 
04533     def SetPosition(self, position, adjust = True):
04534         DrawingObject.SetPosition(self, position, adjust)
04535         self.move(position.x(),position.y())
04536 
04537     def areaPoints(self):
04538         points = QPointArray(4)
04539         A = QPoint(self.x(),self.y())# + self.offset()
04540         B = QPoint(self.x()+self.width(),self.y()+self.height()) #self.endPoint()# + self.offset()
04541         margin = 0
04542         if self.isActive(): margin = 2
04543         points.setPoint(0,A.x()-margin,A.y()-self.linkLength)
04544         points.setPoint(1,B.x()+margin,A.y()-self.linkLength)
04545         points.setPoint(2,A.x()-margin,B.y()+self.linkLength)
04546         points.setPoint(3,B.x()+margin,B.y()+self.linkLength)
04547         return points
04548 
04549     def drawShape(self,painter):
04550         if not (self in visWindow.contents):
04551                 self._delete()
04552                 self.setCanvas(None)
04553                 return
04554         # special way of drawin specific muon chambers  NOT TESTED YET
04555         if self.GetObject().GetType() in ["M5R4","M4R4"]: #chambertype M5R4 or M4R4 in the muon system
04556           #I already know the number and location of the ports
04557           # INOUTPORTS
04558           i = 0
04559           colour = dc.GetPen()
04560           while i < 48: #0-23 A,B FEE OUT
04561                 xPos = position.x + self.size.width*(i+1)/(49)
04562                 if (i > 7 and i < 16) or (i > 23 and i < 32) or (i > 39 and i < 48): #RED - A, GREEN - B
04563                         dc.SetPen(wxGREEN_PEN)
04564                 else:
04565                         dc.SetPen(wxRED_PEN)
04566                 dc.DrawLine(xPos, position.y+self.size.height,xPos, position.y+self.size.height+self.linkLength)
04567                 i += 1
04568 
04569           dc.SetPen(colour)
04570           i = 0
04571           while i < 4: #0-3 AB HV IN
04572                 yPos = position.y + self.size.height*(i+1)/(5)
04573                 dc.drawLine(position.x+self.size.width,yPos, position.x+self.size.width+self.linkLength,yPos)
04574                 i += 1
04575           i = 0
04576           while i < 4: #4-5 AB GAS IN,OUT
04577                 yPos = position.y + self.size.height*(i+1)/(5)
04578                 dc.drawLine(position.x, yPos, position.x-self.linkLength,yPos)
04579                 i += 2
04580         else: #assume default port numbering is used 
04581             ports = self.GetPorts(port_IN)
04582             if 2*ports < GetZoomFactor()/100*self.width():
04583                 xPos = self.x()
04584                 for x in range(ports):
04585                         xPos = self.x() +  self.width()*(x+1)/(ports+1)
04586                         painter.drawLine(xPos, self.y()-self.linkLength, xPos, self.y())
04587             else:
04588                 painter.save()
04589                 painter.setPen(Qt.NoPen)
04590                 painter.setBrush(QBrush(QColor(200,200,200)))
04591                 painter.drawRect(QRect(QPoint(self.x(),self.y()-self.linkLength),QPoint(self.x()+self.width()-1,self.y()-1)))
04592                 painter.restore()
04593             ports = self.GetPorts(port_OUT)
04594             if 2*ports < GetZoomFactor()/100*self.width():
04595                 xPos = self.x()
04596                 for x in range(ports):
04597                         xPos = self.x() +  self.width()*(x+1)/(ports+1)
04598                         painter.drawLine(xPos, self.y()+self.height(), xPos, self.y()+self.height()+self.linkLength)
04599             else:
04600                 painter.save()
04601                 painter.setPen(Qt.NoPen)
04602                 painter.setBrush(QBrush(QColor(200,200,200)))
04603                 painter.drawRect(QRect(QPoint(self.x(),self.y()+self.height()+self.linkLength),QPoint(self.x()+self.width()-1,self.y()+self.height()-1)))
04604                 painter.restore()
04605         #painter.save()
04606         if self.isActive():
04607                 painter.setPen(QPen(Qt.black,2,Qt.DashLine)) #QColor(200,50,0),2))
04608         if self.GetObject().GetName() in visWindow.main.DoNotShow:
04609                 painter.setBrush(QBrush(painter.brush().color(),Qt.Dense7Pattern))
04610 
04611         QCanvasRectangle.drawShape(self,painter)
04612         #painter.restore()
04613         QCanvasRectangle.drawShape(self,painter)
04614 
04615     def dragEnterEvent(self, event):
04616         event.ignore()
04617     def dragMoveEvent(self, event):
04618         event.ignore()
04619 
04620 class myLine(QCanvasLine,DrawingObject):
04621     def __init__(self,canvas,obj_link,object,position=QPoint(2500,2500),size=0,penColour=Qt.black, \
04622                 fillColour=Qt.black,lineSize=1,startPt=QPoint(2500,2500),endPt=QPoint(2500,2500)):
04623         DrawingObject.__init__(self,canvas,obj_link,object,position,size,penColour,fillColour,lineSize,startPt,endPt)
04624         QCanvasLine.__init__(self,canvas)
04625         self.penColour = Color(self.GetObject().GetColor())
04626 
04627     def dragEnterEvent(self, event):
04628         event.ignore()
04629     def dragMoveEvent(self, event):
04630         event.ignore()
04631     def show(self):
04632         try:
04633                 self.setPoints(self.nodeFrom.x()+self.from_delta,  self.nodeFrom.y()+self.nodeFrom.height()+self.linkLength,self.nodeTo.x()+self.to_delta ,self.nodeTo.y()-self.linkLength)
04634                 QCanvasLine.show(self)
04635         except:
04636                 print "There is an error in the Configuration database"
04637 
04638     def drawShape(self, painter):
04639         if not (self in visWindow.contents) or self.GetObject().GetName() in visWindow.main.DoNotShow:
04640                 self._delete()
04641                 self.setCanvas(None)
04642                 return
04643 
04644         self.setPoints(self.nodeFrom.x()+self.from_delta,  self.nodeFrom.y()+self.nodeFrom.height()+self.linkLength,self.nodeTo.x()+self.to_delta ,self.nodeTo.y()-self.linkLength)
04645         if self.isActive():
04646                 painter.setPen(QPen(self.penColour,2)) 
04647         else:
04648                 painter.setPen(QPen(self.penColour,1))
04649         QCanvasLine.drawShape(self,painter)
04650 
04651     def boundingRect(self):
04652         #return QRect(self.startPoint(),QPoint(self.startPoint().x()+10,self.startPoint().y()+10))
04653         return QRect(min(self.startPoint().x(),self.endPoint().x()),min(self.startPoint().y(),self.endPoint().y()), abs(self.startPoint().x()-self.endPoint().x()), abs(self.startPoint().y()-self.endPoint().y()))
04654 
04655     def areaPoints(self):
04656         points = QPointArray(4)
04657         A = self.startPoint()
04658         B = self.endPoint()
04659         zoomfactor=GetZoomFactor()/100
04660         delta_x = abs(A.x()-B.x())*zoomfactor
04661         delta_y = abs(A.y()-B.y())*zoomfactor
04662         delta = 4*max(delta_x,delta_y)
04663         points.setPoint(0,A.x(),A.y()-delta)
04664         points.setPoint(1,B.x(),B.y()-delta)
04665         points.setPoint(2,B.x(),B.y()+delta)
04666         points.setPoint(3,A.x(),A.y()+delta)
04667         return points
04668     def _delete(self):
04669         #DrawingObject._delete(self)
04670         try:
04671                 self.nodeFrom, self.nodeTo = None, None
04672                 self.object = None      
04673                 self.canvas = None      
04674         except:
04675                 pass
04676     def setCanvas(self,c):
04677         QCanvasItem.setCanvas(self,c)
04678 

Generated on Fri Aug 31 11:11:17 2007 for CDBVis by  doxygen 1.5.3