Newer
Older
from PyQt5.QtCore import pyqtSlot, QPoint
Jakub Štercl
committed
from PyQt5.QtGui import QPainter, QPicture
from PyQt5.QtPrintSupport import QPrintDialog
Jakub Štercl
committed
from PyQt5.QtWidgets import QDialog, QMenu, QFileDialog, QWidget, QMessageBox
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
Jakub Štercl
committed
from controllers.base_controller import BaseController
from model.member import Member
from windows import distribution_overview
Jakub Štercl
committed
class DistributionOverview(BaseController, QWidget, distribution_overview.Ui_Form):
def __init__(self, main_window, teams, group, distribution_name=None, parent=None):
Jakub Štercl
committed
"""
: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
Jakub Štercl
committed
:param parent: parent widget for qt
"""
super(DistributionOverview, self).__init__(parent)
self.setupUi(self)
self.main_window = main_window
self.saved = False
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)
Jakub Štercl
committed
self.tableOthers = DragDropTableUnassigned(
-1,
self.getUnassigned(teams),
Jakub Štercl
committed
self.tr("Nezařazeni"),
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
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
committed
self.btnExport.clicked.connect(self.exportToFile)
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
committed
"""
pyqt slot that changes name of distribution
:param name: new distribution name
"""
@pyqtSlot()
def addTeam(self):
Jakub Štercl
committed
"""
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):
Jakub Štercl
committed
"""
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):
Jakub Štercl
committed
"""
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:
Jakub Štercl
committed
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Critical)
msg.setWindowTitle("Chyba")
msg.setText("Nelze smazat neprázdný tým!")
Jakub Štercl
committed
msg.setStandardButtons(QMessageBox.Ok)
msg.exec_()
@pyqtSlot()
def save(self, return_after=True):
Jakub Štercl
committed
"""
create Distribution instance and save it to database
:param return_after: indicates if, after saving, we want to exit the screen
Jakub Štercl
committed
"""
print(return_after)
teams = []
for table in self.teamTables:
team = Team(table.id_, table.name, table.getAllData())
teams.append(team)
distribution = Distribution(self.distribution_name, teams, self.group.id_)
self.saved = True
if return_after is True:
self.main_window.reset()
@pyqtSlot()
def printDistribution(self):
Jakub Štercl
committed
"""
show print dialog, then print the distribution
"""
dialog = QPrintDialog()
if dialog.exec_() != QDialog.Accepted:
return
Jakub Štercl
committed
widget = PrintWidget(self.distribution_name, self.teamTables)
Jakub Štercl
committed
# 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()
Jakub Štercl
committed
# 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)
Jakub Štercl
committed
painter.translate(-pic.width() / 2, -pic.height() / 2)
painter.drawPicture(0, 0, pic)
Jakub Štercl
committed
@pyqtSlot()
def exportToFile(self):
Jakub Štercl
committed
"""
show file choose dialog, then export distribution to file
"""
Jakub Štercl
committed
file, options = QFileDialog.getSaveFileName(self, self.tr("Exportovat do"))
if file == '':
return
with open(file, 'w', encoding='utf-8') as f:
Jakub Štercl
committed
for table in self.teamTables:
team = table.getAllData()
Jakub Štercl
committed
for member in team:
f.write(member.name + ', ')
f.write('\n')
msg = QMessageBox(self)
msg.setWindowTitle("Hotovo")
msg.setText("Rozdělení exportováno")
msg.setStandardButtons(QMessageBox.Ok)
msg.exec_()
Jakub Štercl
committed
@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
Jakub Štercl
committed
: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):
Jakub Štercl
committed
"""
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)