Skip to content
Snippets Groups Projects
distribution_overview_controller.py 10.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • from PyQt5.QtCore import pyqtSlot, QPoint
    
    from PyQt5.QtGui import QPainter, QPicture
    from PyQt5.QtPrintSupport import QPrintDialog
    
    from PyQt5.QtWidgets import QDialog, QMenu, QFileDialog, QWidget, QMessageBox
    
    Jakub Štercl's avatar
    Jakub Štercl committed
    from utils.widgets.drag_drop_table_unassigned import DragDropTableUnassigned
    from utils.widgets.editable_title_widget import EditableTitle
    from utils.widgets.members_drag_drop_table import MembersDragDropTable
    
    from controllers.base_controller import BaseController
    
    from model.distribution import Distribution
    
    from model.member import Member
    
    from model.team import Team
    
    Jakub Štercl's avatar
    Jakub Štercl committed
    from utils.widgets.print_widget import PrintWidget
    
    from windows import distribution_overview
    
    
    class DistributionOverview(BaseController, QWidget, distribution_overview.Ui_Form):
    
        def __init__(self, main_window, teams, group, distribution_name=None, parent=None):
    
            """
            :param main_window: MainWindow that this belongs to 
            :param teams: dictionary of teams {"team name": [Member1, Member2, ...], ...}
            :param group: Group that has been distributed in those teams
    
            :param distribution_name: name of distribution to be displayed
    
            super(DistributionOverview, self).__init__(parent)
            self.setupUi(self)
            self.main_window = main_window
    
            self.group = group
    
            self.teamTables = []
    
            for i, team_name in enumerate(teams):
                table = MembersDragDropTable(i, teams[team_name], team_name, self)
                table.model.sourceModel().droppedMemberFrom.connect(self.removeMember)
                table.deleteClicked.connect(self.removeTeam)
    
                table.contextMenuRequested.connect(self.onContextMenuRequested)
    
                self.teamTables.append(table)
                self.gridTeams.addWidget(table, i // 2, i % 2)
    
                -1,
                self.getUnassigned(teams),
    
                self
            )
            self.tableOthers.model.sourceModel().droppedMemberFrom.connect(self.removeMember)
            self.tableOthers.contextMenuRequested.connect(self.onContextMenuRequested)
            self.gridTeams.addWidget(self.tableOthers, len(self.teamTables) // 2, len(self.teamTables) % 2)
    
    
            if distribution_name is None:
                self.distribution_name = self.tr("Nepojmenované rozdělení")
            else:
                self.distribution_name = distribution_name
    
    Jakub Štercl's avatar
    Jakub Štercl committed
            title = EditableTitle(self.distribution_name)
            self.layoutName.replaceWidget(self.titleWidget, title)
            self.titleWidget = title
        
            # signals
    
            self.btnAddTeam.clicked.connect(self.addTeam)
            self.btnSave.clicked.connect(self.save)
    
            self.btnPrint.clicked.connect(self.printDistribution)
    
    Jakub Štercl's avatar
    Jakub Štercl committed
            self.titleWidget.textConfirmed.connect(self.changeDistName)
    
    
        def getUnassigned(self, teams):
            """
            :param teams: teams in distribution (dict) 
            :return: list of unassigned members from group
            """
            res = []
            for member in self.group.members:
                for team in teams.values():
                    if member in team:
                        break
                else:
                    res.append(member)
            return res
    
    
    Jakub Štercl's avatar
    Jakub Štercl committed
        @pyqtSlot(str)
        def changeDistName(self, name):
    
            """
            pyqt slot that changes name of distribution
            :param name: new distribution name
            """
    
    Jakub Štercl's avatar
    Jakub Štercl committed
            self.distribution_name = name
            
    
        @pyqtSlot()
        def addTeam(self):
    
            """
            add new empty team to the table of teams 
            """
    
            table_id = len(self.teamTables)
    
            table = MembersDragDropTable(table_id, [], "Tým " + str(table_id + 1), self)
    
            table.model.sourceModel().droppedMemberFrom.connect(self.removeMember)
            table.deleteClicked.connect(self.removeTeam)
            self.teamTables.append(table)
    
            self.gridTeams.replaceWidget(self.tableOthers, table)
            self.gridTeams.addWidget(self.tableOthers, len(self.teamTables) // 2, len(self.teamTables) % 2 )
    
    
        @pyqtSlot(int, int)
        def removeMember(self, member_id, table_id):
    
            """
            remove member from target table (table represents team)
            :param member_id: id of the member that should be removed
            :param table_id: id of table that we should remove the member from (or -1 for 'unassigned'
            """
    
            if table_id == -1:
                self.tableOthers.removeMember(member_id)
            else:
                self.teamTables[table_id].removeMember(member_id)
    
    
        @pyqtSlot(int)
        def removeTeam(self, table_id):
    
            """
            remove table (represents team) from the screen, only removes it if the table is empty
            :param table_id: id of table that should be removed
            """
    
            if self.teamTables[table_id].isEmpty():
                self.teamTables[table_id].hide()
    
                self.gridTeams.replaceWidget(self.teamTables[len(self.teamTables) - 1],self.tableOthers)
    
                for i in range(len(self.teamTables) - 1, table_id, -1):
                    self.gridTeams.replaceWidget(self.teamTables[i-1], self.teamTables[i])
                    self.teamTables[i].id_ -= 1
                self.teamTables.pop(table_id)
            else:
    
                msg = QMessageBox(self)
                msg.setIcon(QMessageBox.Critical)
    
                msg.setWindowTitle("Chyba")
                msg.setText("Nelze smazat neprázdný tým!")
    
        def save(self, return_after=True):
    
            """
            create Distribution instance and save it to database
    
            :param return_after: indicates if, after saving, we want to exit the screen
    
            teams = []
            for table in self.teamTables:
                team = Team(table.id_, table.name, table.getAllData())
                teams.append(team)
    
    Jakub Štercl's avatar
    Jakub Štercl committed
            distribution = Distribution(self.distribution_name, teams, self.group.id_)
    
            distribution.saveToDb()
    
            self.saved = True
            if return_after is True:
                self.main_window.reset()
    
    
        @pyqtSlot()
        def printDistribution(self):
    
            dialog = QPrintDialog()
            if dialog.exec_() != QDialog.Accepted:
                return
    
    Jakub Štercl's avatar
    Jakub Štercl committed
            widget = PrintWidget(self.distribution_name, self.teamTables)
    
    
            # first we print into QPicture, that way we can rescale without a big resolution loss
            pic = QPicture()
            pic_painter = QPainter(pic)
            widget.render(pic_painter, flags=widget.DrawChildren)
            pic_painter.end()
            pic.setBoundingRect(widget.rect())
    
            printer = dialog.printer()
            painter = QPainter()
    
            painter.begin(printer)
    
    
            # rescale the picture to page and print
            x_scale = printer.pageRect().width() / pic.width()
            y_scale = printer.pageRect().height() / pic.height()
    
            scale = min([x_scale, y_scale])
    
            painter.translate(printer.paperRect().x() + printer.pageRect().width() / 2,
                              printer.paperRect().y() + printer.pageRect().height() / 2)
            painter.scale(scale, scale)
    
            painter.translate(-pic.width() / 2, -pic.height() / 2)
            painter.drawPicture(0, 0, pic)
    
            painter.end()
    
    
            """
            show file choose dialog, then export distribution to file
            """
    
            file, options = QFileDialog.getSaveFileName(self, self.tr("Exportovat do"))
            if file == '':
                return
    
            with open(file, 'w', encoding='utf-8') as f:
    
                    f.write(table.name + ', ')
    
            msg = QMessageBox(self)
            msg.setWindowTitle("Hotovo")
            msg.setText("Rozdělení exportováno")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
    
    
        @pyqtSlot(Member, int, QPoint)
    
        def onContextMenuRequested(self, member, from_table_id, point):
            """
            construct and display context menu allowing to move members from a team to different one
    
            :param member: member that the user is pointing at
            :param from_table_id: id of table that the member is in
            :param point: point on screen, so that we show the menu where the user right clicked
    
            """
            menu = QMenu(self.sender())
            submenu = menu.addMenu(self.tr("Přesunout do týmu:"))
            for table in self.teamTables:
                if table.id_ != from_table_id:
                    submenu.addAction(table.name, lambda i=table.id_: self.moveMember(member, from_table_id, i))
    
            if from_table_id != -1:
                menu.addSeparator()
                menu.addAction(self.tr("Vyřadit z rozdělení"), lambda: self.moveMember(member, from_table_id, -1))
            menu.exec_(point)
    
        def moveMember(self, member, from_table_id, to_table_id):
    
            """
            move member from one table (team) to another
            :param member: member that we're moving
            :param from_table_id: id of table in which the member currently is
            :param to_table_id: id of target table
            """
    
            self.removeMember(member.id_, from_table_id)
            if to_table_id == -1:
                self.tableOthers.insertMember(member)
            else:
                self.teamTables[to_table_id].insertMember(member)
    
        def returningToPrevious(self):
    
            """
            give user option to save
            """
    
            if not self.saved:
                msg = QMessageBox(self)
                msg.setWindowTitle(self.tr("Uložit?"))
                msg.setText(self.tr("Chcete rozdělení uložit?"))
                msg.setInformativeText(self.tr("Pokud rozdělení neuložíte, nebude rozdělení v historii"
                                               ", ani se nebude započítávat do historie členů."))
                btn_discard = msg.addButton(self.tr("Neukládat"), QMessageBox.NoRole)
                btn_save = msg.addButton(self.tr("Uložit"), QMessageBox.YesRole)
                msg.exec_()
                if msg.clickedButton() == btn_save:
                    self.save(False)