C:/mesDocs/QT_confDbVis_canvas/MiniatureWindow.py

Go to the documentation of this file.
00001 #################################
00002 # Miniature window module       #
00003 #################################
00004 # This module and its two classes are responsible for showing the miniature window of the visual window.
00005 
00006 from qt import *
00007 from visWindow import * # We need to import this module to get the rest of the imports from cdbVis. We cannot import cdbVis because this module will try to initialize the SystemWindow class before it is available
00008 
00009 
00010 ##########################################################################
00011 # SystemWindow class                                                    ##
00012 ##########################################################################
00013 
00014 #CONSTANTS -  for this class; GUI constants that does not make sense to collect with all the others in CdbVisCore
00015 SYSTEM_PANEL = 6001
00016 SYSTEM_WINDOW_HEIGHT = 200
00017 SYSTEM_WINDOW_WIDTH = 200
00018 
00019 ##
00020 #  This class is responsible for displaying the window with the Miniature Window inside; 
00021 #       which shows the whole visual window in a miniature size (zoomed out). The window will 
00022 #       stay on top of the parent window, but it is not modal; it floats on top of it as what
00023 #       you are used to with floating tool bars.
00024 # 
00025 #       TODO: At the moment it does only make sense to show this window if we are in the
00026 #       device level, but at the moment it is shown for every level...but only showing objects
00027 #       when in device level.
00028 # 
00029 #       Inherits wxMiniFrame for the graphical display, and dbUpdate (implements the interface)
00030 #       to include the methods included in that class.
00031 #       
00032 #     
00033 class SystemWindow(QDialog ,dbUpdate): #wxMiniFrame, dbUpdate):
00034 
00035     # Constructor
00036     ##
00037     #  The constructor: Initializes the System Window.
00038     # 
00039     #       Parameters:
00040     #       @self -     the instance object of this class
00041     #             @parent -     the parent window (usually mainWindow)
00042     #             TURNING OBSELETE -> @id -      ID of _this_ window, that the parent sets
00043     #             @main -       Our communication object (mainWindow)
00044     #         
00045     def __init__(self, main, parent):
00046         
00047         # We get the size and position of the parent window, so that we can position this window
00048         # relative to that; we put it close to the bottom right corner of the parent window.
00049         parent_pos = main.pos() #main.GetPosition()
00050         parent_size = main.size() #main.GetSize()
00051 
00052         # Call the constructor to wxMiniFrame which we inherit from; so that our window can be drawn as a frame.
00053         #wxMiniFrame.__init__(self, parent, id, "Miniature Window",pos=wxPoint(parent_pos.x+parent_size.GetWidth()-SYSTEM_WINDOW_WIDTH,parent_pos.y+parent_size.GetHeight()-SYSTEM_WINDOW_HEIGHT),size=wxSize(SYSTEM_WINDOW_WIDTH,SYSTEM_WINDOW_HEIGHT),style=wxDEFAULT_FRAME_STYLE)
00054         QDialog.__init__(self, parent)
00055 
00056         # Set the communication object to a member variable so that it is easily accessible within every method of this class
00057         self.main = main
00058 
00059         # We fill our frame (window) with the SystemPanel class, which shows the miniature of the visual window
00060         self.systemPanel = SystemPanel(self,self.main)
00061         
00062         EVT_CLOSE(self,self.OnClose)
00063 
00064     ##
00065     #  We need to know when this window closes to update the view menu in the main window; 
00066     #       remove the hatch telling us whether this window is shown or not.
00067     # 
00068     #       Parameters:
00069     #       @event - additional information sent from the close event trigger in this object
00070     #   
00071     def OnClose(self,event):
00072 
00073         self.main.ViewSystemsClick(False) 
00074 
00075     ##
00076     #  Whenever something is changed in Visual Window, we need to redraw the contents of 
00077     #       the miniature window as well. This method is then called from the paint method in
00078     #       Visual Window to inform this window that the miniature window needs a repaint. We
00079     #       send the information further to the "real" miniature window: the system panel,
00080     #       which actually shows the contents.
00081     #   
00082     def DrawSystem(self):
00083         
00084         self.systemPanel.DrawSystem(None,True)
00085                                                                                                                              
00086     ##
00087     #  Whenever the status of the database connection changes, this needs to be informed
00088     #       to "all" the classes, so it is this method that is called from its parent to tell
00089     #       this. We need to tell the SystemPanel about this as well. At the moment we don't
00090     #       need to take any action from this.
00091     # 
00092     #       Parameters:
00093     #       @evtReason - A constant defining what kind of database connection change that occured.
00094     #       @cdb - Reference to the database connection object.
00095     #         
00096     def OnDbUpdate(self, evtReason, cdb):
00097         
00098         self.systemPanel.OnDbUpdate(evtReason, cdb)
00099 
00100 
00101 ##########################################################################
00102 # SystemPanel class
00103 ##########################################################################
00104 
00105 # Constants for SystemPanel
00106 CLOSE_BUTTON = 101
00107 CREATE_SUBSYSTEM = 8001
00108 CLOSE_WINDOW = 8002
00109 MODIFY_SUBSYSTEM = 8003
00110 SET_AS_ACTIVE = 8004
00111 
00112 ##
00113 #  This is the window in the SystemWindow that actually shows miniature versions of the 
00114 #       visual objects.
00115 # 
00116 #       Inherits wxPanel which is just a widget to contain other widgets... and implements of
00117 #       course dbUpdate.
00118 #     
00119 class SystemPanel(QWidget, dbUpdate): #wxPanel,dbUpdate):
00120 
00121 
00122     ##
00123     #  Constructor.
00124     #   
00125     #       Parameters:
00126     #       @parent - parent of this panel (usually SystemWindow)
00127     #       @id     - id of this window (for widget reference), set by the parent
00128     #       @main   - reference to the communication object (MainWindow)
00129     #   
00130     #   
00131     def __init__(self, main, parent):
00132         
00133         #wxPanel.__init__(self,parent,id)
00134         QWidget.__init__(self,parent)
00135         self.main = main
00136         
00137         # We use black as background colour for the miniature window; as in contrast to the 
00138         # white background colour of the visual window.
00139 #       self.SetBackgroundColour(wxColour(0,0,0))
00140 
00141         # We set the width and height of this window in member variables to use them when we
00142         # draw the miniature window. They are changed if the window is resized, so that it's
00143         # always correct relative positioning and size of the miniature object tot the real
00144         # visual objects
00145         self.width,self.height = self.GetSize()
00146         self.centerX = self.width/2
00147         self.centerY = self.height/2
00148 
00149 #       EVT_PAINT(self, self.DrawSystem)
00150 #       EVT_SIZE(self,self.OnSize)
00151 
00152 #       EVT_LEFT_DOWN(self,self.OnMouseMove)
00153 #       EVT_LEFT_UP(self,self.OnMouseMove)
00154 #       EVT_MOTION(self,self.OnMouseMove)
00155 #       EVT_LEAVE_WINDOW(self,self.OnLeftWindow) # Whenever the cursor leaves the window...
00156 
00157         # Member variables needed to keep track of the red rectangle in our window; which
00158         # actually shows the shown part of the visual window.
00159         self.zoomarea = None    # The rectangle object, size and position
00160         self.dragMode = -1      # Whether we drag (mousebutton down) or move (mousebutton up) while moving mouse cursor
00161         self.moveOriginX = -1   # Origin X of rectangle's last position
00162         self.moveOriginY = -1   # Origin Y of rectangle's last position
00163         self.movedX = -1        # Dragged X from rectangle's last position
00164         self.movedY = -1        # Dragged Y from rectangle's last position
00165 
00166     ##
00167     #  Whenever the status of the database connection changes, this needs to be informed
00168     #       to "all" the classes, so it is this method that is called from its parent to tell
00169     #       this. We clear the miniature window. (and hide it? TBC)
00170     # 
00171     #       Parameters:
00172     #       @evtReason - A constant defining what kind of database connection change that occured.
00173     #       @cdb - Reference to the database connection object.
00174     #         
00175     def OnDbUpdate(self, evtReason, cdb):
00176 
00177         if evtReason == DB_DISCONNECTED:
00178                 self.DrawSystem(None,False)
00179         else:
00180                 self.DrawSystem(None,True) #systems has to be redrawn each time the db is updated..
00181 
00182     ##
00183     #  Whenever the cursor leaves the miniature window; we have to change it to the normal
00184     #       cursor again; as we may have changed it to something else when dragging or resizing.
00185     # 
00186     #       Parameters:
00187     #       @event - event object with information about the event
00188     #   
00189     def OnLeftWindow(self,event):
00190         self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
00191 
00192     ##
00193     #  When the mouse cursor is moved around in this window (on the SystemPanel, which covers the
00194     #       whole SystemWindow), we have to detect whether the we just move the mouse cursor or if we
00195     #       also hold down the left mousebutton, and if it is the latter one, if the mouse cursor is
00196     #       within the red rectangle. If all those are true: the user can move the red rectangle around,
00197     #       and when he/she releases the mouse button the view in the visual window is changed.
00198     # 
00199     #       @event - event object; we make use of the x and y positions of the mouse cursor, and the
00200     #       actions with the left mouse button (mouse down and mouse up)
00201     #   
00202     def OnMouseMove(self,event):
00203         
00204         setscrollbars = False # We do not change the view in the visual window as default, only if
00205                               # the mouse button is released (mouse button up event)
00206                           
00207         # If the red rectangle object is not initialized yet, we ignore this call and return.
00208         if self.zoomarea == None:
00209                 return False
00210 
00211         # A left mouse button down event starts the dragging (if the mouse cursor is within the red rectangle area)
00212         if event.LeftDown():
00213                 mouse_x,mouse_y = event.GetX(),event.GetY()
00214                 
00215                 # Check if the x and y position of the mouse cursor is inside the red rectangle's area
00216                 if mouse_x >= self.zoomarea.GetPosition().x and mouse_x <= (self.zoomarea.GetPosition().x+self.zoomarea.GetSize().GetWidth()) and mouse_y >= self.zoomarea.GetPosition().y and mouse_y <= (self.zoomarea.GetPosition().y+self.zoomarea.GetSize().GetHeight()):
00217                         self.dragMode = 1 # All right, it was inside the red rectangle; now we start dragging.
00218 
00219                         #Figure out where we clicked in the red rectangle, relatively to its upper left corner
00220                         self.moveOriginX,self.moveOriginY = mouse_x,mouse_y
00221 
00222         if event.Dragging(): # If we hold down the mouse button while we move the mouse cursor, we are dragging.
00223                              # We then need to recalculate the new position of the red rectangle in the miniature 
00224                              # window as we drag
00225                 if self.dragMode == 1: # Dragging started all right.
00226                         mouse_x,mouse_y = event.GetX(),event.GetY()
00227                         
00228                         rel_x = mouse_x - self.moveOriginX
00229                         rel_y = mouse_y - self.moveOriginY
00230 
00231                         self.moveOriginX,self.moveOriginY = mouse_x,mouse_y
00232                         self.zoomarea.SetRelativePosition(wxPoint(rel_x,rel_y))
00233 
00234                         print "X: " + str(mouse_x) + " Y: " + str(mouse_y)
00235 
00236         if event.LeftUp(): # We released the mouse button, thus dragging stopped (if any), and we then need to recalculate
00237                            # the new position of the scroll bars in the visual window according to the new placement of the
00238                            # red rectangle in the miniature window
00239                 if self.dragMode == 1:
00240                         self.dragMode = -1
00241                         setscrollbars = True # Oh yeah, now we need to change the visual window view
00242 
00243         if not (event.LeftDown() or event.Dragging() or event.LeftUp()):
00244                 pass # None of the events that we were looking for occured...here we can optionally change the mouse cursor..
00245         else:
00246                 self.DrawSystem(None,False,setscrollbars) # Ok, a mouse event of our taste occured; action -> reaction
00247                                                           # draw the new stuff.
00248 
00249     ##
00250     #  This is the paint method for this class disguised as a method to draw the system 
00251     #       in a miniature view. This method can be called from the system (paint event) or 
00252     #       an user (if we just need to repaint the window of some reason).
00253     # 
00254     #       Parameters:
00255     #       @event           - not used
00256     #       @donotchangearea - (default: True), if we scroll on the scroll bars in the visual window,
00257     #                           then we would like to update the relative position of the red rectangle
00258     #                           to the rest of the SystemPanel as well. Only set when the scroll bars 
00259     #                           change in the visual window by the user or by code.
00260     #       @setScrollBars   - (default: False), whether we should update the scroll bars of
00261     #                           the visual window or not (only on mouse button up after a drag
00262     #                           of the red rectangle)
00263     #   
00264     def DrawSystem(self,event,donotchangearea=True,setScrollBars=False):
00265 
00266         # We have to calculate the proportion between the size of the miniature window and the 
00267         # visual window (the whole visual window with the hidden part included) so that we can
00268         # draw everything else in the correct proportions as well
00269         zoomwin_size = self.GetSize() # Size of the SystemPanel (miniature window)
00270         viswin_size = self.main.GetVisWindow().GetSize() # Size of the Visual Window, the visible part
00271         height_factor = float(zoomwin_size.GetHeight())/float(viswin_size.GetHeight())
00272         width_factor = float(zoomwin_size.GetWidth())/float(viswin_size.GetWidth())
00273 
00274         viswin_maxwidth,viswin_maxheight = self.main.GetVisWindow().GetMaxSize() # Size of the Visual Window, the whole thing
00275         viswin_pos_x,viswin_pos_y = self.main.GetVisWindow().CalcUnscrolledPosition(0,0) # Get current scroll position
00276 
00277         height_max_factor = float(zoomwin_size.GetHeight())/float(viswin_maxwidth)
00278         width_max_factor = float(zoomwin_size.GetWidth())/float(viswin_maxheight)
00279 
00280         visobjects = self.main.GetVisWindow().GetContents()
00281         #selobjects = self.main.GetVisWindow().GetSelection() # If we want to draw the selected visual 
00282                                                               # objects with another colour etc, it's accessible
00283 
00284 
00285         if donotchangearea:
00286                 if self.zoomarea == None:
00287                         self.zoomarea = RectangleArea(wxPoint(viswin_pos_x*width_max_factor,viswin_pos_y*height_max_factor), wxSize(viswin_size.GetWidth()*width_max_factor,viswin_size.GetHeight()*height_max_factor))
00288                 else:
00289                         self.zoomarea.SetPosition(wxPoint(viswin_pos_x*width_max_factor,viswin_pos_y*height_max_factor))
00290                         self.zoomarea.SetSize(wxSize(viswin_size.GetWidth()*width_max_factor,viswin_size.GetHeight()*height_max_factor))
00291 
00292         else:
00293                 # Check if we tried to move the red rectangle out of the window, if so, set new position to edge of area
00294                 if self.zoomarea.GetPosition().x + self.zoomarea.GetSize().GetWidth() > self.GetSize().GetWidth():
00295                         self.zoomarea.SetX(self.GetSize().GetWidth()-self.zoomarea.GetSize().GetWidth())
00296                 elif self.zoomarea.GetPosition().x < 0:
00297                         self.zoomarea.SetX(0)
00298                 if self.zoomarea.GetPosition().y + self.zoomarea.GetSize().GetHeight() > self.GetSize().GetHeight():
00299                         self.zoomarea.SetY(self.GetSize().GetHeight()-self.zoomarea.GetSize().GetHeight())
00300                 elif self.zoomarea.GetPosition().y < 0:
00301                         self.zoomarea.SetY(0)
00302 
00303         if setScrollBars: #set scrollbars in visual window to the area the user changed to in this window
00304                 new_vis_x = self.zoomarea.GetPosition().x / width_max_factor
00305                 new_vis_y = self.zoomarea.GetPosition().y / height_max_factor
00306                 self.main.GetVisWindow().DoScroll(new_vis_x,new_vis_y) #upper left corner
00307 
00308         if(event==None):
00309                 dc = wxClientDC(self) # We explicitly requested an update
00310         else:
00311                 dc = wxPaintDC(self)  # The system thought that we would have need of an update
00312 
00313         dc.BeginDrawing()
00314         dc.SetPen(wxBLACK_PEN) # Line colour
00315         dc.SetBrush(wxBLACK_BRUSH) # Fill colour
00316         
00317         dc.DrawRectangle(0,0,zoomwin_size.GetWidth(),zoomwin_size.GetHeight()) # Whole area, covers whole SystemPanel
00318         
00319         dc.SetPen(wxRED_PEN)
00320 
00321         # Draw the red rectangle
00322         position = self.zoomarea.GetPosition()
00323         size = self.zoomarea.GetSize()
00324         dc.DrawRectangle(position.x,position.y,size.GetWidth(),size.GetHeight())
00325 
00326         # Draw miniature versions of objects (nodes/devices only) in visual window; in our miniature window
00327         for obj in visobjects:
00328                 if obj.GetType() == obj_NODE: #only for nodes in device level (-1)
00329                         dc.SetPen(wxPen(wxColour(255,255,0),width=1,style=wxSOLID)) # Yellow
00330                         dc.SetBrush(wxBrush(wxColour(255,255,0),wxSOLID))
00331                         x,y = obj.GetPosition()
00332                         w,h = obj.GetSize()
00333 
00334                         # If the miniature versions of our visual objects are to small, then we set a minimum size
00335                         # of the miniature objects so that they are always visible for the user (if he/she is not blind)
00336                         if w*width_max_factor < 1:
00337                                 w = 1
00338                         else:
00339                                 w = w*width_max_factor
00340                         if h*height_max_factor < 1:
00341                                 h = 1
00342                         else:
00343                                 h = h*height_max_factor
00344 
00345                         dc.DrawRectangle(x*width_max_factor,y*height_max_factor, w, h) # Draw the node!
00346 
00347         dc.EndDrawing()
00348 
00349     ##
00350     #  If we resize the miniature window, we redraw the contents with the new proportion 
00351     #       factor to the visual window.
00352     #   
00353     def OnSize(self,event):
00354         
00355         self.width,self.height = self.GetSize()
00356         self.centerX = self.width/2
00357         self.centerY = self.height/2
00358         
00359         self.DrawSystem(None,donotchangearea=True,setScrollBars=False) # Needed because it is not intelligent enough to tell
00360                                                                        # that a resize needs a repaint...true enough.
00361 
00362 ##
00363 #  An object to store size and position of the red rectangle (which represents the visible visual window)
00364 #       
00365 class RectangleArea:
00366         ##
00367         #  Constructor.
00368         #                   Parameters:
00369         #                   @position - x and y position of the object in a wxPoint() object
00370         #                   @size     - width and height of the object in a wxSize() object
00371         #               
00372         def __init__(self,position,size):
00373                 self.size = size
00374                 self.position = position
00375 
00376         ##
00377         #  Get the size of the rectangle.
00378         #                   !returns a wxSize() object with width and height of the rectangle
00379         #               
00380         def GetSize(self):
00381                 return self.size
00382         
00383         ##
00384         #  Set the size of the rectangle.
00385         #                   Parameters:
00386         #                   @size - wxSize(w,h) object
00387         #               
00388         def SetSize(self,size):
00389                 self.size = size
00390                 
00391         ##
00392         #  Get the position of the rectangle.
00393         #                   !returns a wxPoint() object width x and y position
00394         #               
00395         def GetPosition(self):
00396                 return self.position
00397         
00398         ##
00399         #  Set the absolute position of the rectangle.
00400         #                   Parameters:
00401         #                   @position - wxPoint(x,y) object
00402         #               
00403         def SetPosition(self,position):
00404                 self.position = position
00405                 
00406         ##
00407         #  Set the relative position of the rectangle.
00408         #                   Parameters:
00409         #                   @position - wxPoint(x,y) object
00410         #               
00411         def SetRelativePosition(self,position):
00412                 self.position = wxPoint(self.position.x + position.x,self.position.y + position.y)
00413                 
00414         ##
00415         #  Set the absolute x position of the rectangle.
00416         #                   Parameters:
00417         #                   @x - x position of the rectangle
00418         #               
00419         def SetX(self,x):
00420                 self.position = wxPoint(x,self.position.y)
00421                 
00422         ##
00423         #  Set the absolute y position of the rectangle.
00424         #                   Parameters:
00425         #                   @y - y position of the rectangle
00426         #               
00427         def SetY(self,y):
00428                 self.position = wxPoint(self.position.x,y)
00429 
00430 
00431 

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