SpacerContainer.py
Go to the documentation of this file.
00001 from python_qt_binding.QtCore import *
00002 from python_qt_binding.QtGui import *
00003 from diarc.util import *
00004 import sys
00005 import logging
00006 log = logging.getLogger('qt_view.SpacerContainter')
00007 
00008 
00009 class SpacerContainer(QGraphicsWidget):
00010     """ A SpacerContainer is a specialized widget for creating artifical
00011     spacing between other widgets "inside" it. These spaces consist of Spacer
00012     objects, which are usually drawn blank to give the same effect as margins.
00013     Items and spacers occur in a linear arrangement, but the direction is unspecified.
00014     The items and spacers are intended to be linked together using an AnchoredLayout,
00015     as part of a two level layout process. The first level is called 'linking',
00016     in which we actually reassign new AnchoredLayout properties to objects that
00017     are defined to be beside each other. The second level is for the layout mechanism
00018     to perform the acutal layout, with items being children of the SpacerContainer's 
00019     parent object and Spacers being children of the SpacerContainer itself. 
00020     Spacer objects can be used as targets for drag and drop operations.
00021     This code is a generalization of repeated code used in qtview.
00022 
00023     
00024     +--------+          +---------+          +--------+
00025     | Item A | Spacer A | Current | Spacer B | Item B |
00026     +--------+          +---------+          +--------+
00027 
00028     +--------+        +--------+
00029     | Item A | Spacer | Item B |
00030     +--------+        +--------+
00031     """
00032     def __init__(self,parent):
00033         super(SpacerContainer,self).__init__(parent=parent)
00034         # Parent needs to be of type "DrawingBoard" to make sure that 
00035 #         self.parent = typecheck(parent,DrawingBoard,"parent")
00036         self.parent = parent
00037         self._spacers = list()
00038         # We need to know what specific type of spacer we are using, since
00039         # all new spacers are instantiated inside getSpacerA or getSpacerB. 
00040         self._spacerType = None #SpacerContainer.Spacer
00041 
00042     def _release(self):
00043         """ releases all spacer objects and dissasociates from parent """
00044         self.setVisible(False)
00045         self.setParent(None)
00046         self.parent = None
00047         for spacer in self._spacers:
00048             spacer._release()
00049             self._spacers.remove(spacer)
00050 
00051 
00052     def removeItemSpacers(self,item):
00053         """ Removes spacers that touch a particular item. Used by SpacerContainter.Item
00054         when it is being released.
00055         """
00056         removalList = list()
00057         for spacer in self._spacers:
00058             if spacer.itemA is not None and spacer.itemA == item:
00059                 removalList.append(spacer)
00060             if spacer.itemB is not None and spacer.itemB == item:
00061                 removalList.append(spacer)
00062         log.debug("... removing %d spacers linked to item"%len(removalList))
00063         for spacer in removalList:
00064             spacer._release()
00065             self._spacers.remove(spacer)
00066 
00067 
00068     def getSpacerA(self,item):
00069         """ Return the current spacer, or create a new one, in the direction of 
00070         the current item's 'itemA'. This is used by SpacerContainer.Item objects
00071         during the linking process.
00072         """
00073         # Determine if the item is currently being used
00074         isUsed = item.isUsed()
00075         # Find spacers where item is itemB (making this spacer A)
00076         ret = filter(lambda x: x.itemB == item, self._spacers)
00077         # Delete old unused spacers. Remove them from the QLayout system so 
00078         # they don't try to draw anymore and from our list of spacers so we
00079         # don't try to search it anymore.
00080         for spacer in ret:
00081             if (not spacer.itemA == item.itemA()) or (not isUsed):
00082                 spacer.setParent(None)
00083                 spacer._release()
00084                 self._spacers.remove(spacer)
00085         ret = filter(lambda x: x.itemB == item, self._spacers)
00086         # Once we have deleted old spacers, make sure we are using the band.
00087         # If we are not, don't return anything (just None)
00088         if not isUsed:
00089             return None
00090         # Return existing spacer if only one exists. There should not be extras
00091         if len(ret) == 1 and ret[0].itemA == item.itemA():
00092             return ret[0]
00093         elif len(ret) >= 1:
00094             raise Exception("To many spacers found %d"%len(ret))
00095         # No existing spacers fit - create a new spacer in direction A
00096         spacer = self.spacerType(self)
00097         spacer.itemB = item
00098         spacer.itemA = item.itemA()
00099         self._spacers.append(spacer)
00100         return spacer
00101 
00102     def getSpacerB(self,item):
00103         """ Finds the spacer for an item in direction b """
00104         # Determine if the item is currently being used
00105         isUsed = item.isUsed()
00106         # Find spacers where item is itemA (making this spacer B)
00107         ret = filter(lambda x: x.itemA == item, self._spacers)
00108         # Delete old unused spacers. Remove them from the QLayout system so 
00109         # they don't try to draw anymore and from our list of spacers so we
00110         # don't try to search it anymore.
00111         for spacer in ret:
00112             if (not spacer.itemB == item.itemB()) or (not isUsed):
00113                 spacer.setParent(None)
00114                 spacer._release()
00115                 self._spacers.remove(spacer)
00116         # TODO: This next line may not be needed
00117         ret = filter(lambda x: x.itemA == item, self._spacers)
00118         # Once we have deleted old spacers, make sure we are using the band.
00119         # If we are not, don't return anything (just None)
00120         if not isUsed:
00121             return None
00122         # Return existing spacer if only one exists. There should not be extras
00123         if len(ret) == 1 and ret[0].itemB == item.itemB():
00124             return ret[0]
00125         elif len(ret) >= 1:
00126             raise Exception("To many spacers found %d"%len(ret))
00127         # No existing spacers fit - create a new spacer in direction B
00128         spacer = self.spacerType(self)
00129         spacer.itemA = item
00130         spacer.itemB = item.itemB()
00131         self._spacers.append(spacer)
00132         return spacer
00133 
00134     def _get_spacerType(self):
00135         if isinstance(self._spacerType,types.NoneType):
00136             raise Exception("you must set the spacerType for the SpacerContainer %r"%type(self)) 
00137         return self._spacerType
00138     def _set_spacerType(self,spacerType):
00139 #         self._spacerType = typecheck(spacerType,SpacerContainer.Spacer,"spacerType")
00140         self._spacerType = spacerType
00141     spacerType = property(_get_spacerType,_set_spacerType)
00142 
00143 
00144 
00145     class Spacer(QGraphicsWidget):
00146         """ A Spacer between two items. 
00147         Spacers are automatically created and removed by the SpacerContainer to
00148         seperate adjacent Items. You must create your own Spacer object that 
00149         implements the link() method to define how the spacers connect to the
00150         Items on either side of it. The implementation may also contain hooks
00151         for receiving drag and drop events. 
00152         """
00153         def __init__(self,parent):
00154             self.parent = typecheck(parent,SpacerContainer,"parent")
00155             self.parent = parent
00156             super(SpacerContainer.Spacer,self).__init__(parent=parent)
00157             self.itemA = None
00158             self.itemB = None
00159 
00160         def _release(self):
00161             self.setVisible(False)
00162             self.itemA = None
00163             self.itemB = None
00164             self.setParent(None)
00165             self.parent = None
00166 
00167         def layout(self):
00168             """ Returns the QGraphicsLayout that is being used. """
00169             return self.parent.parent.layout()
00170 
00171         def link(self):
00172             """ Must be implemented by the subclass. This method should consist
00173             of self.layout().addAnchor(self, ..., self.itemA/B, ...) calls anchoring
00174             the sides of itemA and itemB to this spacer. 
00175             """
00176             raise Exception("You must implement the linking to the spacersA and B")
00177 
00178 
00179     class Item(QGraphicsWidget):
00180         """ An Item with spacers around it. """
00181         def __init__(self,parent,container):
00182 #             self.parent = typecheck(parent,DrawingBoard,"parent")
00183             self.parent = parent
00184             self.container = typecheck(container,SpacerContainer,"container")
00185             super(SpacerContainer.Item,self).__init__(parent=parent)
00186 
00187         def _release(self):
00188             self.setVisible(False)
00189             self.setParent(None)
00190             self.parent = None
00191             self.container.removeItemSpacers(self)
00192             self.container = None
00193             # TODO: This may need to delete former spacers too!
00194 
00195         def itemA(self):
00196             raise Exception("You must implement a way to return itemA")
00197 
00198         def itemB(self):
00199             raise Exception("You must implement a way to return itemB")
00200 
00201         def isUsed(self):
00202             """ return if the item is currently being used or not - determines
00203             if the item will be visible or not 
00204             """
00205             raise Exception("You must implement a way to return if the item is used")
00206 
00207         def link(self):
00208             """ This method manages the spacer objects linked on either side of 
00209             the item. When the spacers link() method is called, the anchored
00210             layout will hook into the object.
00211             """
00212             l = self.parent.layout()
00213             # Calculate Spacers A and B - deleteing old spacers to this item
00214             # when necessary, reusing existing spacers if possible, and otherwise
00215             # creating new spacers
00216             spacerA = self.container.getSpacerA(self)
00217             spacerB = self.container.getSpacerB(self)
00218             if isinstance(spacerA,types.NoneType) or isinstance(spacerB,types.NoneType):
00219                 self.setVisible(False)
00220                 return
00221             self.setVisible(True)
00222             spacerA.link()
00223             spacerB.link()
00224 
00225 
00226 


rqt_graphprofiler
Author(s): Dan Brooks
autogenerated on Thu Jun 6 2019 20:29:31