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