From ae60da81455602ac8e28aad46b99cb6d18f26897 Mon Sep 17 00:00:00 2001
From: "Collin A. Schmitz" <caschmitz@aps.anl.gov>
Date: Fri, 24 Mar 2017 00:00:45 +0000
Subject: [PATCH] Implemented manage users tab.  Parent storage for user
 dictionary added.

---
 .../aps_beamline_tools/gui/addExperiment.py   |  23 ++-
 .../dm/aps_beamline_tools/gui/dmStationUi.py  |  13 ++
 .../aps_beamline_tools/gui/experimentsTab.py  |   4 +-
 .../aps_beamline_tools/gui/manageUsersTab.py  | 173 +++++++++++++++++-
 4 files changed, 199 insertions(+), 14 deletions(-)

diff --git a/src/python/dm/aps_beamline_tools/gui/addExperiment.py b/src/python/dm/aps_beamline_tools/gui/addExperiment.py
index 16a6c054..2d579d1c 100644
--- a/src/python/dm/aps_beamline_tools/gui/addExperiment.py
+++ b/src/python/dm/aps_beamline_tools/gui/addExperiment.py
@@ -40,7 +40,7 @@ class AddExperimentTab(QWidget):
         grid.addItem(QSpacerItem(20, 1000, QSizePolicy.Minimum, QSizePolicy.Expanding), 3, 1, 5, 1)
 
         grid.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum), 3, 4)
-        self.detailBtn = QPushButton('Proposal Details', self)
+        self.detailBtn = QPushButton('Show Details', self)
         self.detailBtn.clicked.connect(self.toggleDetails)
         self.detailBtn.setFixedSize(150, 100)
         grid.addWidget(self.detailBtn, 3, 5)
@@ -56,7 +56,7 @@ class AddExperimentTab(QWidget):
         grid.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding), 6, 5)
 
         modBtn = QPushButton('Continue Manually', self)
-        modBtn.clicked.connect(lambda: self.setTab(0))
+        modBtn.clicked.connect(lambda: self.setTab(5))
         modBtn.setFixedSize(150, 100)
         grid.addWidget(modBtn, 7, 5)
 
@@ -93,14 +93,17 @@ class AddExperimentTab(QWidget):
         table.resizeRowToContents(row)
 
     def startProposal(self):
-        row = self.tableWidget.currentRow()
-        name = self.tableWidget.item(row, 0).text()
-        print "Starting " + name
-        self.setTab(0)
+        id = self.tableWidget.item(self.tableWidget.currentRow(), 0).data(Qt.UserRole)
+        proposal = self.experimentPropApi.getBeamlineProposal(id)
+        self.parent.currentUsers = proposal
+        self.setTab(5)
 
     # Resizes the horizontal headers to fit the screen
     def resizeTable(self, width):
-        totalWidths = sum(self.colWidths)
+        try:
+            totalWidths = sum(self.colWidths)
+        except AttributeError:
+            return
         if self.detailsTable.verticalScrollBar().isVisible():
             newSize = [column * (width - 204) / totalWidths for column in self.colWidths]
         else:
@@ -109,15 +112,15 @@ class AddExperimentTab(QWidget):
             self.detailsTable.horizontalHeader().resizeSection(i, column)
 
     def toggleDetails(self):
-        if self.detailBtn.isChecked():
+        if self.detailBtn.text() == 'Hide Details':
             self.tableWidget.show()
             self.detailsTable.hide()
-            self.detailBtn.setChecked(False)
+            self.detailBtn.setText('Show Details')
         else:
             self.tableWidget.hide()
             self.proposalDetails()
             self.detailsTable.show()
-            self.detailBtn.setChecked(True)
+            self.detailBtn.setText('Hide Details')
 
     def proposalDetails(self):
         id = self.tableWidget.item(self.tableWidget.currentRow(), 0).data(Qt.UserRole)
diff --git a/src/python/dm/aps_beamline_tools/gui/dmStationUi.py b/src/python/dm/aps_beamline_tools/gui/dmStationUi.py
index c9def909..90e78c84 100755
--- a/src/python/dm/aps_beamline_tools/gui/dmStationUi.py
+++ b/src/python/dm/aps_beamline_tools/gui/dmStationUi.py
@@ -15,6 +15,7 @@ from daqsTab import DaqsTab
 from uploadsTab import UploadsTab
 from initialTab import InitialTab
 from addExperiment import AddExperimentTab
+from manageUsersTab import ManageUsersTab
 
 
 class DmStationUi(QMainWindow):
@@ -25,6 +26,9 @@ class DmStationUi(QMainWindow):
 
         self.setWindowTitle('DM Station: %s' % self.stationName)
         self.setGeometry(0, 0, 800, 400)
+
+        # Variable to hold the user instances
+        self.currentUsers = {}  ####HOW DO I MAKE THIS AN INSTANCE OF A PROPOSAL WITH NO DATA
  
         # Create a stacked layout to connect the various pages
         self.stackedLayout = QStackedLayout()
@@ -36,6 +40,7 @@ class DmStationUi(QMainWindow):
         self.daqsTab = DaqsTab(self.stationName, self)
         self.uploadsTab = UploadsTab(self.stationName, self)
         self.addExperimentTab = AddExperimentTab(self.stationName, self)
+        self.manageUsersTab = ManageUsersTab(self.stationName, self)
  
         # Add the windows to the stack.
         self.stackedLayout.addWidget(self.initialTab.initialTabWidget)
@@ -43,6 +48,7 @@ class DmStationUi(QMainWindow):
         self.stackedLayout.addWidget(self.daqsTab.daqsTabWidget)
         self.stackedLayout.addWidget(self.uploadsTab.uploadsTabWidget)
         self.stackedLayout.addWidget(self.addExperimentTab.addExperimentTabWidget)
+        self.stackedLayout.addWidget(self.manageUsersTab.manageUsersTabWidget)
 
         # Set a central widget to hold everything
         self.centralWidget = QWidget()
@@ -82,6 +88,8 @@ class DmStationUi(QMainWindow):
             UploadsTab.resizeTable(self.uploadsTab, windowSize)
         elif currentIndex == 4:
             AddExperimentTab.resizeTable(self.addExperimentTab, windowSize)
+        elif currentIndex == 5:
+            ManageUsersTab.resizeTable(self.manageUsersTab, windowSize)
 
     def currentChanged(self, index):
         newIndex = index
@@ -91,6 +99,11 @@ class DmStationUi(QMainWindow):
             DaqsTab.resizeTable(self.daqsTab, self.geometry().width())
         elif newIndex == 3:
             UploadsTab.resizeTable(self.uploadsTab, self.geometry().width())
+        elif newIndex == 4:
+            AddExperimentTab.resizeTable(self.addExperimentTab, self.geometry().width())
+        elif newIndex == 5:
+            ManageUsersTab.updateUsers(self.manageUsersTab)
+            ManageUsersTab.resizeTable(self.manageUsersTab, self.geometry().width())
 
     def getTab(self):
         return self.stackedLayout.currentIndex()
diff --git a/src/python/dm/aps_beamline_tools/gui/experimentsTab.py b/src/python/dm/aps_beamline_tools/gui/experimentsTab.py
index 50591082..0d0df005 100644
--- a/src/python/dm/aps_beamline_tools/gui/experimentsTab.py
+++ b/src/python/dm/aps_beamline_tools/gui/experimentsTab.py
@@ -39,15 +39,17 @@ class ExperimentsTab(QWidget):
         addBtn = QPushButton('Add Experiment', self)
         addBtn.clicked.connect(lambda: self.setTab(4))
         addBtn.setMinimumWidth(150)
+        addBtn.setFixedHeight(40)
         grid.addWidget(addBtn, 4, 1)
         grid.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding), 4, 2)
         modBtn = QPushButton('Modify Selected', self)
         modBtn.clicked.connect(lambda: self.setTab(5))
         modBtn.setMinimumWidth(150)
+        modBtn.setFixedHeight(40)
         grid.addWidget(modBtn, 4, 3)
         grid.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding), 4, 4)
 
-        grid.addItem(QSpacerItem(20, 40, QSizePolicy.Expanding), 5, 0)
+        grid.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding), 5, 0)
 
         self.experimentsTabWidget = QWidget()
         self.experimentsTabWidget.setLayout(grid)
diff --git a/src/python/dm/aps_beamline_tools/gui/manageUsersTab.py b/src/python/dm/aps_beamline_tools/gui/manageUsersTab.py
index fd470b81..80a409fc 100644
--- a/src/python/dm/aps_beamline_tools/gui/manageUsersTab.py
+++ b/src/python/dm/aps_beamline_tools/gui/manageUsersTab.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 from PyQt4.QtGui import QGridLayout, QSpacerItem, QSizePolicy, QPushButton, QWidget, \
-    QFont, QLabel, QTableWidget, QTableWidgetItem, QColor, QAbstractItemView
+    QFont, QLabel, QTableWidget, QTableWidgetItem, QColor, QAbstractItemView, QComboBox
 from PyQt4.QtCore import Qt
 from dmApiFactory import DmApiFactory
 
@@ -11,5 +11,172 @@ class ManageUsersTab(QWidget):
         super(ManageUsersTab, self).__init__(parent)
         self.stationName = stationName
         self.parent = parent
-        self.experimentDsApi = DmApiFactory.getInstance().getExperimentDsApi()
-        self.experimentsTabLayout()
\ No newline at end of file
+        self.experimentPropApi = DmApiFactory.getInstance().getBeamlineProposalApi()
+        self.userApi = DmApiFactory.getInstance().getUserDsApi()
+        self.manageUsersTabLayout()
+
+    # Sets up the tab's layout, each block is a row
+    def manageUsersTabLayout(self):
+        grid = QGridLayout()
+
+        labelFont = QFont('Arial', 18, QFont.Bold)
+        lbl = QLabel(self.stationName + ' User Management', self)
+        lbl.setAlignment(Qt.AlignCenter)
+        lbl.setFont(labelFont)
+        grid.addWidget(lbl, 0, 0, 1, 7)
+
+        backBtn = QPushButton('Back', self)
+        backBtn.clicked.connect(lambda: self.setTab(1))
+        backBtn.setMinimumWidth(100)
+        grid.addWidget(backBtn, 1, 5, 1, 2, Qt.AlignCenter)
+
+        grid.addItem(QSpacerItem(750, 40, QSizePolicy.Expanding, QSizePolicy.Minimum), 2, 0)
+        grid.addItem(QSpacerItem(950, 40, QSizePolicy.Expanding, QSizePolicy.Minimum), 2, 2, 1, 5)
+
+        currentLabel = QLabel('Current Users', self)
+        currentLabel.setAlignment(Qt.AlignCenter)
+        grid.addWidget(currentLabel, 3, 0)
+        self.userDropdown = QComboBox(self)
+        self.userDropdown.setMaximumWidth(400)
+        self.updateDropdown()
+        grid.addWidget(self.userDropdown, 3, 2, 1, 5, Qt.AlignCenter)
+
+        self.currentUserTable = QTableWidget()
+        self.availableUserTable = QTableWidget()
+        grid.addWidget(self.currentUserTable, 4, 0, 1, 1)
+        moveUserBtn = QPushButton('<->', self)
+        moveUserBtn.setFixedSize(40, 40)
+        moveUserBtn.clicked.connect(self.moveUsers)
+        grid.addWidget(moveUserBtn, 4, 1)
+        grid.addWidget(self.availableUserTable, 4, 2, 1, 5)
+        grid.addItem(QSpacerItem(20, 1000, QSizePolicy.Minimum, QSizePolicy.Expanding), 4, 3, 1, 1)
+
+        startDaqBtn = QPushButton('Start DAQ', self)
+        startDaqBtn.clicked.connect(lambda: self.setTab(0))
+        startDaqBtn.setMinimumWidth(150)
+        startDaqBtn.setMaximumWidth(200)
+        startDaqBtn.setFixedHeight(40)
+        grid.addWidget(startDaqBtn, 5, 0, Qt.AlignCenter)
+
+        startUploadBtn = QPushButton('Start Upload', self)
+        startUploadBtn.clicked.connect(lambda: self.setTab(0))
+        startUploadBtn.setMinimumWidth(150)
+        startUploadBtn.setMaximumWidth(200)
+        startUploadBtn.setFixedHeight(40)
+        grid.addWidget(startUploadBtn, 5, 2, 1, 5, Qt.AlignCenter)
+
+        grid.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum), 6, 0)
+
+        self.manageUsersTabWidget = QWidget()
+        self.manageUsersTabWidget.setLayout(grid)
+
+    def updateDropdown(self):
+        self.proposalList = self.experimentPropApi.listBeamlineProposals()
+        self.userDropdown.addItem('All Users', -1)
+        for proposal in self.proposalList:
+            self.userDropdown.addItem(proposal['title'], proposal['id'])
+
+    # Resizes the horizontal headers to fit the screen
+    def resizeTable(self, width):
+        totalWidths = sum(self.colWidths)
+        if self.availableUserTable.verticalScrollBar().isVisible():
+            newSize = [column * (width - 490) / totalWidths for column in self.colWidths]
+        else:
+            newSize = [column * (width - 480) / totalWidths for column in self.colWidths]
+        for i, column in enumerate(newSize):
+            self.availableUserTable.horizontalHeader().resizeSection(i, column)
+
+        if self.currentUserTable.verticalScrollBar().isVisible():
+            newSize = [column * (width - 490) / totalWidths for column in self.colWidths]
+        else:
+            newSize = [column * (width - 480) / totalWidths for column in self.colWidths]
+        for i, column in enumerate(newSize):
+            self.currentUserTable.horizontalHeader().resizeSection(i, column)
+
+    # Used to change between tabs
+    def setTab(self, tab):
+        self.parent.stackedLayout.setCurrentIndex(tab)
+
+    # Expands the given row to fit the size of its content
+    def expandRow(self, row, column, table):
+        table.resizeRowToContents(row)
+
+    def updateUsers(self):
+        # Setup the available users table
+        id = self.userDropdown.itemData(self.userDropdown.currentIndex(), Qt.UserRole)
+        if id != -1:
+            proposal = self.experimentPropApi.getBeamlineProposal(id)
+            self.availableUserTable.setRowCount(len(proposal['experimenters']))
+            allUsers = proposal['experimenters']
+        else:
+            allUsers = self.userApi.getUsers()
+            self.availableUserTable.setRowCount(len(allUsers))
+        self.availableUserTable.setColumnCount(4)
+        self.colWidths = (70, 70, 70, 125)
+        for i, size in enumerate(self.colWidths):
+            self.availableUserTable.horizontalHeader().resizeSection(i, size)
+        self.availableUserTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
+        self.availableUserTable.setHorizontalHeaderLabels('Badge;First Name;Last Name;Email;'.split(';'))
+        self.availableUserTable.cellDoubleClicked.connect(lambda row, column: self.expandRow(row, column, self.availableUserTable))
+
+        i = 0
+        currentIDs = [x['id'] for x in self.parent.currentUsers['experimenters']]
+        for experimenter in allUsers:
+            if experimenter['id'] in currentIDs:
+                self.availableUserTable.removeRow(i)
+                continue
+            try:
+                rowBadge = QTableWidgetItem(experimenter['badge'])
+            except KeyError:
+                continue
+            rowFirstName = QTableWidgetItem(experimenter['firstName'])
+            rowLastName = QTableWidgetItem(experimenter['lastName'])
+            try:
+                rowEmail = QTableWidgetItem(experimenter['email'])
+            except KeyError:
+                rowEmail = QTableWidgetItem('')
+            self.availableUserTable.setItem(i, 0, rowBadge)
+            self.availableUserTable.setItem(i, 1, rowFirstName)
+            self.availableUserTable.setItem(i, 2, rowLastName)
+            self.availableUserTable.setItem(i, 3, rowEmail)
+            if (i % 2) == 0:
+                rowBadge.setBackground(QColor.fromRgb(230, 241, 245))
+                rowFirstName.setBackground(QColor.fromRgb(230, 241, 245))
+                rowLastName.setBackground(QColor.fromRgb(230, 241, 245))
+                rowEmail.setBackground(QColor.fromRgb(230, 241, 245))
+            i += 1
+
+        # Set up the current users table
+        self.currentUserTable.setRowCount(len(self.parent.currentUsers['experimenters']))
+        self.currentUserTable.setColumnCount(4)
+        for i, size in enumerate(self.colWidths):
+            self.currentUserTable.horizontalHeader().resizeSection(i, size)
+        self.currentUserTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
+        self.currentUserTable.setHorizontalHeaderLabels('Badge;First Name;Last Name;Email;'.split(';'))
+        self.currentUserTable.cellDoubleClicked.connect(lambda row, column: self.expandRow(row, column, self.currentUserTable))
+
+        i = 0
+        for experimenter in self.parent.currentUsers['experimenters']:
+            rowBadge = QTableWidgetItem(experimenter['badge'])
+            rowFirstName = QTableWidgetItem(experimenter['firstName'])
+            rowLastName = QTableWidgetItem(experimenter['lastName'])
+            try:
+                rowEmail = QTableWidgetItem(experimenter['email'])
+            except KeyError:
+                rowEmail = QTableWidgetItem('')
+            self.currentUserTable.setItem(i, 0, rowBadge)
+            self.currentUserTable.setItem(i, 1, rowFirstName)
+            self.currentUserTable.setItem(i, 2, rowLastName)
+            self.currentUserTable.setItem(i, 3, rowEmail)
+            if (i % 2) == 0:
+                rowBadge.setBackground(QColor.fromRgb(230, 241, 245))
+                rowFirstName.setBackground(QColor.fromRgb(230, 241, 245))
+                rowLastName.setBackground(QColor.fromRgb(230, 241, 245))
+                rowEmail.setBackground(QColor.fromRgb(230, 241, 245))
+            i += 1
+
+    def moveUsers(self):
+        temp = self.availableUserTable.selectedItems()[0].row()
+        temp2 = self.availableUserTable.item(temp, 0)
+        selectedAvailable = [x.row(0).text() for x in self.availableUserTable.selectedItems()]
+        currentAvailable = self.currentUserTable.item(self.currentUserTable.currentRow(), 0)
-- 
GitLab