Newer
Older
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 controllers.base_controller import BaseController
from model.distribution import Distribution
from model.team import Team
Jakub Štercl
committed
from utils.drag_drop_table_unassigned import DragDropTableUnassigned
from utils.editable_title_widget import EditableTitle
from utils.members_drag_drop_table import MembersDragDropTable
from windows import distribution_overview
Jakub Štercl
committed
class DistributionOverview(BaseController, QWidget, distribution_overview.Ui_Form):
def __init__(self, main_window, teams, group, 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 parent: parent widget for qt
"""
super(DistributionOverview, self).__init__(parent)
self.setupUi(self)
self.main_window = main_window
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)
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)
self.distribution_name = self.tr("Nepojmenované rozdělení")
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):
Jakub Štercl
committed
"""
create Distribution instance and save it to database
"""
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_)
start = timer()
distribution.saveToDb()
print('total time:', timer() - start)
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()
print(pic.size())
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') as f:
f.write(self.distribution_name + '\n')
for table in self.teamTables:
team = table.getAllData()
f.write(table.name + ': ')
for member in team:
f.write(member.name + ', ')
f.write('\n')
Jakub Štercl
committed
@pyqtSlot()
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)