4 from PyQt4.QtCore import *
5 from PyQt4.QtGui import *
7 from sfa.util.record import SfaRecord, SliceRecord, AuthorityRecord
8 from sface.config import config
9 from sface.sfidata import SfiData
10 from sface.sfiprocess import SfiProcess
13 MEMBERSHIP_STATUS_COLUMN = 1
15 # maximum length of a name to display before clipping
18 MODE_AUTHORITY_SLICES = 0x01
19 MODE_USER_SLICES = 0x02
20 MODE_SELECT_SINGLE = 0x10
22 slice_status = { "in": "Selected",
23 "out": "Not Selected"}
25 color_status = { "in": QColor.fromRgb(0, 250, 250), }
27 class SliceNameDelegate(QStyledItemDelegate):
28 def __init__(self, parent):
29 QStyledItemDelegate.__init__(self, parent)
31 def displayText(self, value, locale):
32 data = str(QStyledItemDelegate.displayText(self, value, locale))
33 if (len(data)>NAME_MAX_LEN):
34 data = data[:(NAME_MAX_LEN-3)] + "..."
37 def paint(self, painter, option, index):
39 data = str(self.displayText(index.data(), QLocale()))
40 status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
41 status_data = status_index.data().toString()
43 fm = QFontMetrics(option.font)
44 rect = QRect(option.rect)
46 rect.setHeight(rect.height() - 2)
47 rect.setWidth(fm.width(QString(data)) + 6)
48 rect.setX(rect.x() + 5)
49 rect.setY(rect.y() - 1)
51 textRect = QRect(option.rect)
52 textRect.setWidth(fm.width(QString(data)) + 6)
53 textRect.setX(rect.x())
55 x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width()
58 path.addRoundedRect(x - 1, y + 1, w, h, 4, 4)
61 painter.setRenderHint(QPainter.Antialiasing)
63 if option.state & QStyle.State_Selected:
64 painter.fillRect(option.rect, option.palette.color(QPalette.Active, QPalette.Highlight))
67 for x in slice_status.keys():
68 if (slice_status[x] == status_data) and (x in color_status):
69 color = color_status[x]
72 painter.fillPath(path, color)
73 painter.setPen(QColor.fromRgb(0, 0, 0))
74 painter.drawText(textRect, Qt.AlignVCenter, QString(data))
78 class SliceView(QTableView):
79 def __init__(self, mode=0, parent=None):
80 QTableView.__init__(self, parent)
83 self.setSelectionBehavior(QAbstractItemView.SelectRows)
84 self.setSelectionMode(QAbstractItemView.SingleSelection)
85 self.setAlternatingRowColors(True)
86 self.setAttribute(Qt.WA_MacShowFocusRect, 0)
87 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
88 self.setToolTip("Double click on a row to change its status.")
90 self.setItemDelegateForColumn(0, SliceNameDelegate(self))
92 def keyPressEvent(self, event):
93 if (event.key() == Qt.Key_Space):
94 self.toggleSelection()
96 QTableView.keyPressEvent(self, event)
98 def selectionChanged(self, selected, deselected):
99 QTableView.selectionChanged(self, selected, deselected)
100 if (self.mode & MODE_SELECT_SINGLE) != 0:
102 self.toggleSelection()
104 def mouseDoubleClickEvent(self, event):
105 self.toggleSelection()
107 def unselectAll(self):
108 index = self.currentIndex()
109 model = index.model()
110 for row in range(0, model.rowCount()):
111 status_index = model.index(row, MEMBERSHIP_STATUS_COLUMN, index.parent())
112 model.setData(status_index, QString(slice_status['out']))
114 #model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"),
115 # model.index(0, MEMBERSHIP_STATUS_COLUMN, index.parent()),
116 # model.index(model.rowCount(), MEMBERSHIP_STATUS_COLUMN, index.parent()))
118 def toggleSelection(self):
119 index = self.currentIndex()
120 model = index.model()
121 status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
122 status_data = status_index.data().toString()
123 node_index = model.index(index.row(), NAME_COLUMN, index.parent())
124 node_data = node_index.data().toString()
126 if status_data == slice_status['in']:
127 model.setData(status_index, QString(slice_status['out']))
129 model.setData(status_index, QString(slice_status['in']))
131 model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), node_index, node_index)
133 def currentChanged(self, current, previous):
134 model = current.model()
135 node_index = model.index(current.row(), 0, current.parent())
136 node_data = node_index.data().toString()
138 class SliceModel(QStandardItemModel):
139 def __init__(self, rows=0, columns=4, parent=None, mode=MODE_AUTHORITY_SLICES):
140 QStandardItemModel.__init__(self, rows, columns, parent)
143 def updateModel(self):
146 if (self.mode & MODE_AUTHORITY_SLICES) != 0:
147 slice_names = SfiData().getAuthorityHrns(type="slice")
148 else: # MODE_USER_SLICES
149 slice_names = SfiData().getUserSliceHrns()
151 rootItem = self.invisibleRootItem()
153 for name in slice_names:
154 rootItem.appendRow([self.readOnlyItem(name),
155 self.readOnlyItem(slice_status["out"])])
157 headers = QStringList() << "Slice Name" << "Status"
158 self.setHorizontalHeaderLabels(headers)
160 def readOnlyItem(self, x):
161 item = QStandardItem(QString(x))
162 item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
165 def getSelectedSlices(self):
167 item = self.invisibleRootItem()
168 children = item.rowCount()
169 for row in range(0, children):
170 childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
171 childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
173 if (childStatus == slice_status['in']):
174 slices.append(childName)
178 class SlicePickerWindow(QDialog):
179 def __init__(self, mode=MODE_AUTHORITY_SLICES, parent=None):
180 super(SlicePickerWindow, self).__init__(parent)
184 self.setWindowTitle("Slice Picker")
186 sliceLabel = QLabel("Slices:")
187 self.sliceView = SliceView(mode=self.mode)
189 self.status = QLabel("")
190 self.status.setMaximumWidth(640)
192 self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
193 self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
195 layout = QVBoxLayout()
196 layout.addWidget(sliceLabel)
197 layout.addWidget(self.sliceView)
198 layout.addWidget(self.status)
199 layout.addWidget(self.buttonBox)
200 self.setLayout(layout)
202 self.connect(self.buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
203 self.connect(self.buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))
205 self.sliceModel = SliceModel(mode=mode)
210 self.slices = self.sliceModel.getSelectedSlices()
214 def setStatus(self, x):
215 self.status.setText(x)
218 if (self.mode & MODE_AUTHORITY_SLICES) != 0:
219 self.refreshAuthority()
223 def refreshUser(self):
224 self.process = SfiProcess(self)
225 self.connect(self.process, SIGNAL('finished()'), self.getUserRecordFinished)
227 self.process.getRecord(hrn=config.getUser(), filename=config.getUserRecordFile())
228 self.setStatus("Refreshing user record. This will take a moment...")
230 def getUserRecordFinished(self):
231 self.disconnect(self.process, SIGNAL('finished()'), self.getUserRecordFinished)
233 faultString = self.process.getFaultString()
235 self.setStatus("<font color='green'>Slice list refreshed.</font>")
236 self.updateSliceView()
238 self.setStatus("<font color='red'>User rec refresh error: %s</font>" % (faultString))
240 def refreshAuthority(self):
241 self.process = SfiProcess(self)
242 self.connect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
244 self.process.listRecords(config.getAuthority(), None)
245 self.setStatus("Refreshing slice list. This will take a moment...")
247 def getAuthorityRecordFinished(self):
248 self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
250 faultString = self.process.getFaultString()
252 self.setStatus("<font color='green'>Slice list refreshed.</font>")
253 self.updateSliceView()
255 self.setStatus("<font color='red'>Authority rec refresh error: %s</font>" % (faultString))
257 def updateSliceView(self):
258 self.sliceModel.updateModel()
260 self.sliceView.setModel(self.sliceModel)
261 self.sliceView.resizeColumnToContents(0)