X-Git-Url: http://git.onelab.eu/?p=sface.git;a=blobdiff_plain;f=sface%2Fscreens%2Fuserscreen.py;h=4eb7793093d84ff1948ecfd0de7934a6ed2fe26d;hp=53c279fb1a46429f3dea2741777565cc8831a56c;hb=e48c173fad6fa65c628294830f19a913bd9b3d1d;hpb=7ea27c8a5bb47cce1d9cc5a9c6e40d56ed11026d diff --git a/sface/screens/userscreen.py b/sface/screens/userscreen.py index 53c279f..4eb7793 100644 --- a/sface/screens/userscreen.py +++ b/sface/screens/userscreen.py @@ -5,21 +5,77 @@ import pickle from PyQt4.QtCore import * from PyQt4.QtGui import * -from sfa.util.record import SfaRecord, SliceRecord, AuthorityRecord, UserRecord from sface.config import config from sface.sfiprocess import SfiProcess from sface.screens.sfascreen import SfaScreen +from sface.sfidata import SfiData NAME_COLUMN = 0 -ROLE_COLUMN = 1 -MEMBERSHIP_STATUS_COLUMN = 2 -SERVER_MEMBERSHIP_STATUS_COLUMN = 3 +#ROLE_COLUMN = 1 +MEMBERSHIP_STATUS_COLUMN = 1 +SERVER_MEMBERSHIP_STATUS_COLUMN = 2 + +# maximum length of a name to display before clipping +NAME_MAX_LEN = 48 user_status = { "in": "Already Selected", "out": "Not Selected", "add": "To be Added", "remove": "To be Removed"} +color_status = { "in": QColor.fromRgb(0, 250, 250), + "add": QColor.fromRgb(0, 250, 0), + "remove": QColor.fromRgb(250, 0, 0) } + + +class UserNameDelegate(QStyledItemDelegate): + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + + def displayText(self, value, locale): + data = str(QStyledItemDelegate.displayText(self, value, locale)) + if (len(data)>NAME_MAX_LEN): + data = data[:(NAME_MAX_LEN-3)] + "..." + return QString(data) + + def paint(self, painter, option, index): + model = index.model() + data = str(self.displayText(index.data(), QLocale())) + status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent()) + status_data = status_index.data().toString() + + fm = QFontMetrics(option.font) + rect = QRect(option.rect) + + rect.setHeight(rect.height() - 2) + rect.setWidth(fm.width(QString(data)) + 6) + rect.setX(rect.x() + 5) + rect.setY(rect.y() - 1) + + textRect = QRect(option.rect) + textRect.setWidth(fm.width(QString(data)) + 6) + textRect.setX(rect.x()) + + x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width() + + path = QPainterPath() + path.addRoundedRect(x - 1, y + 1, w, h, 4, 4) + + painter.save() + painter.setRenderHint(QPainter.Antialiasing) + + if option.state & QStyle.State_Selected: + painter.fillRect(option.rect, option.palette.color(QPalette.Active, QPalette.Highlight)) + + for x in user_status.keys(): + if (user_status[x] == status_data) and (x in color_status): + painter.fillPath(path, color_status[x]) + + painter.setPen(QColor.fromRgb(0, 0, 0)) + painter.drawText(textRect, Qt.AlignVCenter, QString(data)) + + painter.restore() + class UserView(QTableView): def __init__(self, parent=None): QTableView.__init__(self, parent) @@ -31,7 +87,18 @@ class UserView(QTableView): self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setToolTip("Double click on a row to change its status.") + self.setItemDelegateForColumn(0, UserNameDelegate(self)) + + def keyPressEvent(self, event): + if (event.key() == Qt.Key_Space): + self.toggleSelection() + else: + QTableView.keyPressEvent(self, event) + def mouseDoubleClickEvent(self, event): + self.toggleSelection() + + def toggleSelection(self): index = self.currentIndex() model = index.model() status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent()) @@ -57,8 +124,89 @@ class UserView(QTableView): model = current.model() node_index = model.index(current.row(), 0, current.parent()) node_data = node_index.data().toString() - self.emit(SIGNAL('hostnameClicked(QString)'), node_data) + def hideUnusableColumns(self): + self.hideColumn(SERVER_MEMBERSHIP_STATUS_COLUMN) + +class UserModel(QStandardItemModel): + def __init__(self, rows=0, columns=4, parent=None): + QStandardItemModel.__init__(self, rows, columns, parent) + + def updateModel(self, sliceRec): + self.clear() + + added_persons = [] + slice_persons = [] + + if sliceRec: + #for pi in sliceRec.get("PI", []): + # name = str(pi) + # if not name in added_persons: + # slice_persons.append({"name": name, "role": "PI", "member": user_status["in"]}) + # added_persons.append(name) + + for researcher in sliceRec.get("researcher", []): + name = str(researcher) + if not name in added_persons: + slice_persons.append({"name": name, "role": "researcher", "member": user_status["in"]}) + added_persons.append(name) + + userNames = SfiData().getAuthorityHrns(type="user") + for name in userNames: + if not name in added_persons: + slice_persons.append({"name": name, "role": "", "member": user_status["out"]}) + added_persons.append(name) + + rootItem = self.invisibleRootItem() + + for person in slice_persons: + rootItem.appendRow([self.readOnlyItem(person["name"]), + self.readOnlyItem(person["member"]), + self.readOnlyItem(person["member"])]) + + headers = QStringList() << "User Name" << "Status" << "ServerStatus" + self.setHorizontalHeaderLabels(headers) + + def readOnlyItem(self, x): + item = QStandardItem(QString(x)) + item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) + return item + + def updateRecord(self, slicerec): + change = False + + item = self.invisibleRootItem() + children = item.rowCount() + for row in range(0, children): + childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString()) + childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString()) + + if (childStatus == user_status['add']): + researcher = slicerec.get("researcher", []) + researcher.append(childName) + slicerec["researcher"] = researcher + change = True + elif (childStatus == user_status['remove']): + if childName in slicerec.get("PI"): + slicerec.get("PI").remove(childName) + if childName in slicerec.get("researcher"): + slicerec.get("researcher").remove(childName) + change = True + + return change + + def getResearchers(self): + researchers = [] + item = self.invisibleRootItem() + children = item.rowCount() + for row in range(0, children): + childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString()) + childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString()) + + if (childStatus == user_status['add']) or (childStatus == user_status['in']): + researchers.append(childName) + + return researchers class UsersWidget(QWidget): def __init__(self, parent): @@ -81,8 +229,6 @@ class UsersWidget(QWidget): toplayout.addWidget(searchbox, 0, Qt.AlignRight) self.userView = UserView() - #self.userView.setSelectionBehavior(QAbstractItemView.SelectRows) - #self.userView.setSelectionMode(QAbstractItemView.SingleSelection) refresh = QPushButton("Refresh", self) refresh.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) @@ -101,7 +247,7 @@ class UsersWidget(QWidget): self.setLayout(layout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - self.userModel = QStandardItemModel(0, 4, self) + self.userModel = UserModel(parent=self) self.connect(refresh, SIGNAL('clicked()'), self.refresh) self.connect(submit, SIGNAL('clicked()'), self.submit) @@ -109,44 +255,35 @@ class UsersWidget(QWidget): self.updateView() def submitFinished(self): - self.setStatus("Slice data submitted.") - QTimer.singleShot(1000, self.refresh) + self.disconnect(self.process, SIGNAL('finished()'), self.submitFinished) + + faultString = self.process.getFaultString() + if not faultString: + self.setStatus("Slice user data submitted.") + QTimer.singleShot(1000, self.refresh) + else: + self.setStatus("Slice user submit failed: %s" % (faultString)) def getSliceRecordFinished(self): - self.setStatus("Authority data refreshed.", timeout=5000) - self.refreshAuthority() + self.disconnect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished) + + faultString = self.process.getFaultString() + if not faultString: + self.setStatus("Slice record refreshed.") + self.refreshAuthority() + else: + self.setStatus("Slice rec refresh error: %s" % (faultString)) def getAuthorityRecordFinished(self): - self.setStatus("Slice data refreshed.", timeout=5000) - self.updateView() - #self.parent().signalAll("usersUpdated") + self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished) - def readSliceRecord(self): - rec_file = config.getSliceRecordFile() - if os.path.exists(rec_file): - xml = open(rec_file).read() - rec = SliceRecord() - rec.load_from_string(xml) - return rec - return None - - def readAuthorityRecord(self): - rec_file = config.getAuthorityRecordFile() - if os.path.exists(rec_file): - xml = open(rec_file).read() - rec = AuthorityRecord() - rec.load_from_string(xml) - return rec - return None - - def readUserRecord(self, i): - rec_file = config.getAuthorityListFile(i) - if os.path.exists(rec_file): - xml = open(rec_file).read() - rec = UserRecord() - rec.load_from_string(xml) - return rec - return None + faultString = self.process.getFaultString() + if not faultString: + self.setStatus("User data refreshed.") + self.updateView() + #self.parent().signalAll("usersUpdated") + else: + self.setStatus("Authority rec refresh error: %s" % (faultString)) def setStatus(self, msg, timeout=None): self.parent().setStatus(msg, timeout) @@ -161,8 +298,8 @@ class UsersWidget(QWidget): if self.checkRunningProcess(): return - rec = self.readSliceRecord() - change = self.process_table(rec) + rec = SfiData().getSliceRecord() + change = self.userModel.updateRecord(rec) if not change: self.setStatus("No change in slice data. Not submitting!", timeout=3000) @@ -171,7 +308,6 @@ class UsersWidget(QWidget): rec_file = config.getSliceRecordFile() file(rec_file, "w").write(rec.save_to_string()) - self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished) self.connect(self.process, SIGNAL('finished()'), self.submitFinished) self.process.updateRecord(rec_file) @@ -186,73 +322,26 @@ class UsersWidget(QWidget): self.setStatus("There is already a process running. Please wait.") return - self.disconnect(self.process, SIGNAL('finished()'), self.submitFinished) self.connect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished) self.process.getSliceRecord() self.setStatus("Refreshing slice record. This will take some time...") def refreshAuthority(self): - self.disconnect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished) self.connect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished) - self.process.listRecords(config.getAuthority(), "user", config.getAuthorityListFile()) + self.process.listRecords(config.getAuthority(), None) self.setStatus("Refreshing user records. This will take some time...") - def addTableItem(self, table, row, col, val, data=None, readonly=True): - item = QTableWidgetItem(str(val)) - if readonly: - item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) - if data: - if not isinstance(data, str): - data = pickle.dumps(data) - item.setData(Qt.UserRole, QVariant(data)) - table.setItem(row, col, item) - - def updateModel(self): - self.userModel.clear() + def updateView(self): + sliceRec = SfiData().getSliceRecord() - sliceRec = self.readSliceRecord() if not sliceRec: - return None - - added_persons = [] - slice_persons = [] - - for pi in sliceRec.get_field("PI"): - name = str(pi) - if not name in added_persons: - slice_persons.append({"name": name, "role": "PI", "member": user_status["in"]}) - added_persons.append(name) - for researcher in sliceRec.get_field("researcher"): - name = str(researcher) - if not name in added_persons: - slice_persons.append({"name": name, "role": "researcher", "member": user_status["in"]}) - added_persons.append(name) - - i=1 - while (os.path.exists(config.getAuthorityListFile(i))): - rec = self.readUserRecord(i) - if rec: - name = str(rec.get_name()) - if not name in added_persons: - slice_persons.append({"name": name, "role": "", "member": user_status["out"]}) - added_persons.append(name) - i=i+1 - - rootItem = self.userModel.invisibleRootItem() - - for person in slice_persons: - rootItem.appendRow([QStandardItem(QString(person["name"])), - QStandardItem(QString(person["role"])), - QStandardItem(QString(person["member"])), - QStandardItem(QString(person["member"]))]) - - headers = QStringList() << "User Name" << "Role" << "Status" << "ServerStatus" - self.userModel.setHorizontalHeaderLabels(headers) - - def updateView(self): - self.updateModel() + # wait until we've resolved the slicerecord before displaying + # anything to the user. + self.userModel.clear() + else: + self.userModel.updateModel(sliceRec) self.userView.setModel(self.userModel) self.userView.hideColumn(SERVER_MEMBERSHIP_STATUS_COLUMN) @@ -261,33 +350,10 @@ class UsersWidget(QWidget): def updateSliceName(self): self.slicename.setText("Slice : %s" % (config.getSlice() or "None")) - def nodeSelectionChanged(self, hostname): - self.parent().nodeSelectionChanged(hostname) - - def process_table(self, slicerec): - change = False - - item = self.userModel.invisibleRootItem() - children = item.rowCount() - for row in range(0, children): - childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString()) - childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString()) - if (childStatus == user_status['add']): - slicerec.get_field("researcher").append(childName) - change = True - elif (childStatus == user_status['remove']): - if childName in slicerec.get_field("PI"): - slicerec.get_field("PI").remove(childName) - if childName in slicerec.get_field("researcher"): - slicerec.get_field("researcher").remove(childName) - change = True - - print "XXX", slicerec.get_field("researcher") - return change -class MainScreen(SfaScreen): +class UserScreen(SfaScreen): def __init__(self, parent): SfaScreen.__init__(self, parent)