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
00035
00036 self.parent = parent
00037 self._spacers = list()
00038
00039
00040 self._spacerType = None
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
00074 isUsed = item.isUsed()
00075
00076 ret = filter(lambda x: x.itemB == item, self._spacers)
00077
00078
00079
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
00087
00088 if not isUsed:
00089 return None
00090
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
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
00105 isUsed = item.isUsed()
00106
00107 ret = filter(lambda x: x.itemA == item, self._spacers)
00108
00109
00110
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
00117 ret = filter(lambda x: x.itemA == item, self._spacers)
00118
00119
00120 if not isUsed:
00121 return None
00122
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
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
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
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
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
00214
00215
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