fixes for rec.get
[sface.git] / sface / screens / userscreen.py
index 53c279f..4eb7793 100644 (file)
@@ -5,21 +5,77 @@ import pickle
 from PyQt4.QtCore import *
 from PyQt4.QtGui import *
 
 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.config import config
 from sface.sfiprocess import SfiProcess
 from sface.screens.sfascreen import SfaScreen
+from sface.sfidata import SfiData
 
 NAME_COLUMN = 0
 
 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"}
 
 
 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)
 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.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):
     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())
         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()
         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):
 
 class UsersWidget(QWidget):
     def __init__(self, parent):
@@ -81,8 +229,6 @@ class UsersWidget(QWidget):
         toplayout.addWidget(searchbox, 0, Qt.AlignRight)
 
         self.userView = UserView()
         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)
 
         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.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)
 
         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.updateView()
 
     def submitFinished(self):
-        self.setStatus("<font color='green'>Slice data submitted.</font>")
-        QTimer.singleShot(1000, self.refresh)
+        self.disconnect(self.process, SIGNAL('finished()'), self.submitFinished)
+
+        faultString = self.process.getFaultString()
+        if not faultString:
+            self.setStatus("<font color='green'>Slice user data submitted.</font>")
+            QTimer.singleShot(1000, self.refresh)
+        else:
+            self.setStatus("<font color='red'>Slice user submit failed: %s</font>" % (faultString))
 
     def getSliceRecordFinished(self):
 
     def getSliceRecordFinished(self):
-        self.setStatus("<font color='green'>Authority data refreshed.</font>", timeout=5000)
-        self.refreshAuthority()
+        self.disconnect(self.process, SIGNAL('finished()'), self.getSliceRecordFinished)
+
+        faultString = self.process.getFaultString()
+        if not faultString:
+            self.setStatus("<font color='green'>Slice record refreshed.</font>")
+            self.refreshAuthority()
+        else:
+            self.setStatus("<font color='red'>Slice rec refresh error: %s</font>" % (faultString))
 
     def getAuthorityRecordFinished(self):
 
     def getAuthorityRecordFinished(self):
-        self.setStatus("<font color='green'>Slice data refreshed.</font>", 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("<font color='green'>User data refreshed.</font>")
+            self.updateView()
+            #self.parent().signalAll("usersUpdated")
+        else:
+            self.setStatus("<font color='red'>Authority rec refresh error: %s</font>" % (faultString))
 
     def setStatus(self, msg, timeout=None):
         self.parent().setStatus(msg, timeout)
 
     def setStatus(self, msg, timeout=None):
         self.parent().setStatus(msg, timeout)
@@ -161,8 +298,8 @@ class UsersWidget(QWidget):
         if self.checkRunningProcess():
             return
 
         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("<font color=red>No change in slice data. Not submitting!</font>", timeout=3000)
 
         if not change:
             self.setStatus("<font color=red>No change in slice data. Not submitting!</font>", timeout=3000)
@@ -171,7 +308,6 @@ class UsersWidget(QWidget):
         rec_file = config.getSliceRecordFile()
         file(rec_file, "w").write(rec.save_to_string())
 
         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)
         self.connect(self.process, SIGNAL('finished()'), self.submitFinished)
 
         self.process.updateRecord(rec_file)
@@ -186,73 +322,26 @@ class UsersWidget(QWidget):
             self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
             return
 
             self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
             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.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.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...")
 
         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:
         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)
 
         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 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)
 
     def __init__(self, parent):
         SfaScreen.__init__(self, parent)