5 from PyQt4.QtCore import *
6 from PyQt4.QtGui import *
8 from sfa.util.record import SfaRecord, SliceRecord, AuthorityRecord, UserRecord
9 from sface.config import config
10 from sface.sfiprocess import SfiProcess
11 from sface.screens.sfascreen import SfaScreen
15 MEMBERSHIP_STATUS_COLUMN = 1
16 SERVER_MEMBERSHIP_STATUS_COLUMN = 2
18 user_status = { "in": "Already Selected",
19 "out": "Not Selected",
21 "remove": "To be Removed"}
23 class UserView(QTableView):
24 def __init__(self, parent=None):
25 QTableView.__init__(self, parent)
27 self.setSelectionBehavior(QAbstractItemView.SelectRows)
28 self.setSelectionMode(QAbstractItemView.SingleSelection)
29 self.setAlternatingRowColors(True)
30 self.setAttribute(Qt.WA_MacShowFocusRect, 0)
31 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
32 self.setToolTip("Double click on a row to change its status.")
34 def keyPressEvent(self, event):
35 if (event.key() == Qt.Key_Space):
36 self.toggleSelection()
38 QTableView.keyPressEvent(self, event)
40 def mouseDoubleClickEvent(self, event):
41 self.toggleSelection()
43 def toggleSelection(self):
44 index = self.currentIndex()
46 status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
47 status_data = status_index.data().toString()
48 server_status_data = model.index(index.row(), SERVER_MEMBERSHIP_STATUS_COLUMN, index.parent()).data().toString()
49 node_index = model.index(index.row(), NAME_COLUMN, index.parent())
50 node_data = node_index.data().toString()
53 if status_data == user_status['in']:
54 model.setData(status_index, QString(user_status['remove']))
55 elif status_data == user_status['out']:
56 model.setData(status_index, QString(user_status['add']))
57 elif status_data in (user_status['add'], user_status['remove']):
58 if server_status_data == user_status["in"]:
59 model.setData(status_index, QString(user_status['in']))
61 model.setData(status_index, QString(user_status['out']))
63 model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), node_index, node_index)
65 def currentChanged(self, current, previous):
66 model = current.model()
67 node_index = model.index(current.row(), 0, current.parent())
68 node_data = node_index.data().toString()
69 self.emit(SIGNAL('hostnameClicked(QString)'), node_data)
71 def hideUnusableColumns(self):
72 self.hideColumn(SERVER_MEMBERSHIP_STATUS_COLUMN)
74 class UserModel(QStandardItemModel):
75 def __init__(self, rows=0, columns=4, parent=None):
76 QStandardItemModel.__init__(self, rows, columns, parent)
78 def updateModel(self, sliceRec):
85 #for pi in sliceRec.get_field("PI", default=[]):
87 # if not name in added_persons:
88 # slice_persons.append({"name": name, "role": "PI", "member": user_status["in"]})
89 # added_persons.append(name)
91 for researcher in sliceRec.get_field("researcher", default=[]):
92 name = str(researcher)
93 if not name in added_persons:
94 slice_persons.append({"name": name, "role": "researcher", "member": user_status["in"]})
95 added_persons.append(name)
98 while (os.path.exists(config.getAuthorityListFile(i))):
99 rec = self.readUserRecord(i)
101 name = str(rec.get_name())
102 if not name in added_persons:
103 slice_persons.append({"name": name, "role": "", "member": user_status["out"]})
104 added_persons.append(name)
107 rootItem = self.invisibleRootItem()
109 for person in slice_persons:
110 rootItem.appendRow([self.readOnlyItem(person["name"]),
111 self.readOnlyItem(person["member"]),
112 self.readOnlyItem(person["member"])])
114 headers = QStringList() << "User Name" << "Status" << "ServerStatus"
115 self.setHorizontalHeaderLabels(headers)
117 def readOnlyItem(self, x):
118 item = QStandardItem(QString(x))
119 item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
122 def updateRecord(self, slicerec):
125 item = self.invisibleRootItem()
126 children = item.rowCount()
127 for row in range(0, children):
128 childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
129 childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
131 if (childStatus == user_status['add']):
132 researcher = slicerec.get_field("researcher", [])
133 researcher.append(childName)
134 slicerec["researcher"] = researcher
136 elif (childStatus == user_status['remove']):
137 if childName in slicerec.get_field("PI"):
138 slicerec.get_field("PI").remove(childName)
139 if childName in slicerec.get_field("researcher"):
140 slicerec.get_field("researcher").remove(childName)
145 def getResearchers(self):
147 item = self.invisibleRootItem()
148 children = item.rowCount()
149 for row in range(0, children):
150 childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
151 childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
153 if (childStatus == user_status['add']) or (childStatus == user_status['in']):
154 researchers.append(childName)
158 def readUserRecord(self, i):
159 rec_file = config.getAuthorityListFile(i)
160 if os.path.exists(rec_file):
161 xml = open(rec_file).read()
163 rec.load_from_string(xml)
167 class UsersWidget(QWidget):
168 def __init__(self, parent):
169 QWidget.__init__(self, parent)
171 self.process = SfiProcess(self)
173 self.slicename = QLabel("", self)
174 self.updateSliceName()
175 self.slicename.setScaledContents(False)
176 searchlabel = QLabel ("Search: ", self)
177 searchlabel.setScaledContents(False)
178 searchbox = QLineEdit(self)
179 searchbox.setAttribute(Qt.WA_MacShowFocusRect, 0)
181 toplayout = QHBoxLayout()
182 toplayout.addWidget(self.slicename, 0, Qt.AlignLeft)
183 toplayout.addStretch()
184 toplayout.addWidget(searchlabel, 0, Qt.AlignRight)
185 toplayout.addWidget(searchbox, 0, Qt.AlignRight)
187 self.userView = UserView()
189 refresh = QPushButton("Refresh", self)
190 refresh.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
191 submit = QPushButton("Submit", self)
192 submit.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
194 bottomlayout = QHBoxLayout()
195 bottomlayout.addWidget(refresh, 0, Qt.AlignLeft)
196 bottomlayout.addStretch()
197 bottomlayout.addWidget(submit, 0, Qt.AlignRight)
199 layout = QVBoxLayout()
200 layout.addLayout(toplayout)
201 layout.addWidget(self.userView)
202 layout.addLayout(bottomlayout)
203 self.setLayout(layout)
204 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
206 self.userModel = UserModel(parent=self)
208 self.connect(refresh, SIGNAL('clicked()'), self.refresh)
209 self.connect(submit, SIGNAL('clicked()'), self.submit)
213 def submitFinished(self):
214 self.setStatus("<font color='green'>Slice data submitted.</font>")
215 QTimer.singleShot(1000, self.refresh)
217 def getSliceRecordFinished(self):
218 self.setStatus("<font color='green'>Authority data refreshed.</font>", timeout=5000)
219 self.refreshAuthority()
221 def getAuthorityRecordFinished(self):
222 self.setStatus("<font color='green'>Slice data refreshed.</font>", timeout=5000)
224 #self.parent().signalAll("usersUpdated")
226 def readSliceRecord(self):
227 rec_file = config.getSliceRecordFile()
228 if os.path.exists(rec_file):
229 xml = open(rec_file).read()
231 rec.load_from_string(xml)
235 def readAuthorityRecord(self):
236 rec_file = config.getAuthorityRecordFile()
237 if os.path.exists(rec_file):
238 xml = open(rec_file).read()
239 rec = AuthorityRecord()
240 rec.load_from_string(xml)
244 def setStatus(self, msg, timeout=None):
245 self.parent().setStatus(msg, timeout)
247 def checkRunningProcess(self):
248 if self.process.isRunning():
249 self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
254 if self.checkRunningProcess():
257 rec = self.readSliceRecord()
258 change = self.userModel.updateRecord(rec)
261 self.setStatus("<font color=red>No change in slice data. Not submitting!</font>", timeout=3000)
264 rec_file = config.getSliceRecordFile()
265 file(rec_file, "w").write(rec.save_to_string())
267 self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
268 self.connect(self.process, SIGNAL('finished()'), self.submitFinished)
270 self.process.updateRecord(rec_file)
271 self.setStatus("Sending slice record. This will take some time...")
274 if not config.getSlice():
275 self.setStatus("<font color='red'>Slice not set yet!</font>")
278 if self.process.isRunning():
279 self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
282 self.disconnect(self.process, SIGNAL('finished()'), self.submitFinished)
283 self.connect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished)
285 self.process.getSliceRecord()
286 self.setStatus("Refreshing slice record. This will take some time...")
288 def refreshAuthority(self):
289 self.disconnect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished)
290 self.connect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
292 self.process.listRecords(config.getAuthority(), "user", config.getAuthorityListFile())
293 self.setStatus("Refreshing user records. This will take some time...")
295 def updateView(self):
296 sliceRec = self.readSliceRecord()
299 # wait until we've resolved the slicerecord before displaying
300 # anything to the user.
301 self.userModel.clear()
303 self.userModel.updateModel(sliceRec)
305 self.userView.setModel(self.userModel)
306 self.userView.hideColumn(SERVER_MEMBERSHIP_STATUS_COLUMN)
307 self.userView.resizeColumnToContents(0)
309 def updateSliceName(self):
310 self.slicename.setText("Slice : %s" % (config.getSlice() or "None"))
315 class UserScreen(SfaScreen):
316 def __init__(self, parent):
317 SfaScreen.__init__(self, parent)
319 slice = UsersWidget(self)
320 self.init(slice, "Users", "OneLab SFA crawler")
322 def configurationChanged(self):
323 self.widget.updateSliceName()
324 self.widget.updateView()