def paintSection(self, painter, rect, logicalIndex): painter.save() QHeaderView.paintSection(self, painter, rect, logicalIndex) painter.restore() if logicalIndex == self.overlayIndex: painter.setOpacity(CustomHeader.OVERLAY_OPACITY) painter.fillRect(rect,self.parent().appState.getColorForValue(0.0,self.parent().horizontalHeaderItem(logicalIndex).text()))
def mouseReleaseEvent(self, event): if event.button() == Qt.RightButton: table = self.parent() attr = table.horizontalHeaderItem(table.column(table.itemAt(event.pos()))).text() table.appState.showAttributeMenu(attr) else: QHeaderView.mouseReleaseEvent(self,event)
def __init__(self,parent): global dao super(FindOrderDialog,self).__init__(parent) title = _("Find order") self.setWindowTitle(title) top_layout = QVBoxLayout() self.title_widget = TitleWidget(title,self) top_layout.addWidget(self.title_widget) hlayout = QHBoxLayout() hlayout.addWidget(QLabel(_("Search"))) self.search_criteria = QLineEdit() self.search_criteria.setObjectName("search_criteria") hlayout.addWidget(self.search_criteria) top_layout.addLayout(hlayout) self.search_results_view = QTableView() self.headers_view = QHeaderView(Qt.Orientation.Horizontal) self.header_model = make_header_model([_("Preorder Nr"),_("Order Nr"),_("Customer Nr"),_("Customer"),_("Order Part")]) self.headers_view.setModel(self.header_model) # qt's doc : The view does *not* take ownership (bt there's something with the selecion mode self.search_results_model = QStandardItemModel() self.search_results_view.setModel(self.search_results_model) self.search_results_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.search_results_view.setHorizontalHeader(self.headers_view) self.search_results_view.verticalHeader().hide() # self.search_results_view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.search_results_view.horizontalHeader().setResizeMode(3, QHeaderView.Stretch) self.search_results_view.horizontalHeader().setResizeMode(4, QHeaderView.Stretch) self.search_results_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.buttons = QDialogButtonBox() self.buttons.addButton( QDialogButtonBox.StandardButton.Cancel) self.buttons.addButton( QDialogButtonBox.Ok) self.buttons.button(QDialogButtonBox.Ok).setObjectName("go_search") top_layout.addWidget(self.search_results_view) top_layout.setStretch(2,1000) top_layout.addWidget(self.buttons) self.setLayout(top_layout) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.search_results_view.activated.connect(self.row_activated) self.search_criteria.returnPressed.connect(self.search_criteria_submitted) self.setMinimumSize(800,640)
def __init__(self, orientation, parent=None): QHeaderView.__init__(self, orientation, parent=None) self.setClickable(True) self.setMovable(True) self.overlayIndex = None
class PresenceOverviewWidget(HorsePanel): @Slot(QModelIndex) def cell_entered(self, ndx): employee_id = self._employee_id_on_row(ndx) if not employee_id: self._show_totals_day_off(None) elif employee_id: chrono.chrono_start() employee = None for i in self.employees: if i.employee_id == employee_id: employee = i break self.detail_subframe.set_title(employee.fullname) self._show_totals_day_off(employee_id) d = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, ndx.column()))) chrono.chrono_click("Retrieveing data") tars = dao.task_action_report_dao.get_reports_for_employee_id_on_date( employee_id, d) work_timetracks = dao.timetrack_dao.all_work_for_employee_date_manual( employee_id, d) presence_timetracks = dao.timetrack_dao.all_presence_for_employee_date_managed_by_code_full( employee_id, d) # employee = dao.employee_dao.find_by_id(employee_id) special_activities = dao.special_activity_dao.find_on_day( employee_id, d) chrono.chrono_click("Redrawing") self.time_report_view.redraw(datetime(d.year, d.month, d.day, 6, 0), tars, employee_id, work_timetracks, presence_timetracks, special_activities, view_title=_("Work on {}").format( date_to_dmy(d, full_month=True))) session().close( ) # FIXME Put his one line above; but that's tough ! SQLA doesn't help us much here ! chrono.chrono_click("Session closed") # for event_type, duration in self.day_event_totals[employee_id].items(): # mainlog.debug("{}{}".format(event_type, duration)) self._toggle_days_off_actions() def _employee_id_on_row(self, row_or_ndx): r = row_or_ndx if type(r) != int: r = row_or_ndx.row() return self._table_model.data(self._table_model.index(r, 0), Qt.UserRole) DAY_EVENT_PALETTE = { DayEventType.holidays: (Qt.GlobalColor.white, Qt.GlobalColor.red), DayEventType.day_off: (Qt.GlobalColor.white, Qt.GlobalColor.darkRed), DayEventType.unpaid_day_off: (Qt.GlobalColor.black, Qt.GlobalColor.magenta), DayEventType.free_day: (Qt.GlobalColor.white, Qt.GlobalColor.darkMagenta), DayEventType.overtime: (Qt.GlobalColor.black, Qt.GlobalColor.green), DayEventType.recuperation: (Qt.GlobalColor.white, Qt.GlobalColor.darkGreen), DayEventType.unemployment: (Qt.GlobalColor.white, Qt.GlobalColor.blue), DayEventType.unemployment_short: (Qt.GlobalColor.white, Qt.GlobalColor.darkBlue), DayEventType.work_accident: (Qt.GlobalColor.black, Qt.GlobalColor.yellow), DayEventType.sick_leave: (Qt.GlobalColor.white, Qt.GlobalColor.darkYellow) } MONTH_EVENT_COLUMN = 2 YEAR_EVENT_COLUMN = 3 def _make_total_days_off_panel(self): widget = QFrame() widget.setObjectName('HorseRegularFrame') widget.setFrameShape(QFrame.Panel) widget.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout() #layout.addWidget(QLabel(_("Days off to date"))) self.day_off_total_duration_labels = dict() self.day_off_month_duration_labels = dict() self.day_off_labels = dict() self._day_off_table_model = QStandardItemModel(10, 3) self._day_off_table_model.setHorizontalHeaderLabels( [None, None, _("This\nmonth"), _("Before")]) self.day_off_table_view = QTableView(None) self.day_off_table_view.setModel(self._day_off_table_model) # self.day_off_table_view.setHorizontalHeader(self.headers_view) self.day_off_table_view.verticalHeader().hide() self.day_off_table_view.setAlternatingRowColors(True) self.day_off_table_view.setEditTriggers( QAbstractItemView.NoEditTriggers) self.day_off_table_view.hide() row = 0 for det in DayEventType.symbols(): ndx = self._day_off_table_model.index(row, 0) self._day_off_table_model.setData(ndx, det.description, Qt.DisplayRole) ndx = self._day_off_table_model.index(row, 1) fg, bg = self.DAY_EVENT_PALETTE[det] self._day_off_table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) self._day_off_table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._day_off_table_model.setData(ndx, DayEventType.short_code(det), Qt.DisplayRole) row += 1 layout.addWidget(self.day_off_table_view) grid = QGridLayout() self.days_off_layout = grid grid.setColumnStretch(3, 1) row = 0 grid.addWidget(QLabel(_('Year')), row, self.YEAR_EVENT_COLUMN) grid.addWidget(QLabel(_('Month')), row, self.MONTH_EVENT_COLUMN) row += 1 for det in DayEventType.symbols(): self.day_off_total_duration_labels[det] = QLabel("-") self.day_off_month_duration_labels[det] = QLabel("-") self.day_off_labels[det] = QLabel(det.description) hlayout = QHBoxLayout() sl = QLabel() fg, bg = self.DAY_EVENT_PALETTE[det] def to_html_rgb(color): i = color.red() * 256 * 256 + color.green() * 256 + color.blue( ) return "#{:06X}".format(i) p = QPalette() p.setColor(QPalette.Window, QColor(bg)) p.setColor(QPalette.WindowText, QColor(fg)) sl.setPalette(p) sl.setAlignment(Qt.AlignCenter) sl.setStyleSheet("border: 2px solid black; background: {}".format( to_html_rgb(QColor(bg)))) t = DayEventType.short_code(det) mainlog.debug(t) sl.setAutoFillBackground(True) sl.setText(t) grid.addWidget(sl, row, 0) grid.addWidget(self.day_off_labels[det], row, 1) grid.addWidget(self.day_off_total_duration_labels[det], row, self.YEAR_EVENT_COLUMN) grid.addWidget(self.day_off_month_duration_labels[det], row, self.MONTH_EVENT_COLUMN) hlayout.addStretch() row += 1 layout.addLayout(grid) layout.addStretch() self.day_off_table_view.resizeColumnsToContents() # self.day_off_table_view.setMinimumWidth( self.day_off_table_view.width()) # self.day_off_table_view.resize( self.day_off_table_view.minimumWidth(), # self.day_off_table_view.minimumHeight(),) widget.setLayout(layout) return widget def _show_totals_day_off(self, employee_id): mainlog.debug("_show_totals_day_off : {}".format(employee_id)) def form_layout_row_set_visible(layout, row_ndx, is_visible): for i in range(layout.columnCount()): l = layout.itemAtPosition(row_ndx, i) if l and l.widget(): l.widget().setVisible(is_visible) det_to_show = dict() row = 0 for det in DayEventType.symbols(): yearly = 0 if employee_id in self.all_events_in_year: if det in self.all_events_in_year[employee_id]: yearly = nice_round( self.all_events_in_year[employee_id][det]) monthly = 0 if employee_id in self.day_event_totals: if det in self.day_event_totals[employee_id]: monthly = nice_round( self.day_event_totals[employee_id][det]) # ndx = self._day_off_table_model.index(row,self.YEAR_EVENT_COLUMN) # self._day_off_table_model.setData(ndx, v, Qt.DisplayRole) if yearly or monthly: det_to_show[det] = {'monthly': monthly, 'yearly': yearly} if det_to_show: # If there are some days spent on some counters, then we display # those counters *only* mainlog.debug("_show_totals_day_off : showing some events ".format( str(det_to_show))) row = 0 for det in DayEventType.symbols(): if det in det_to_show: monthly = det_to_show[det]['monthly'] yearly = det_to_show[det]['yearly'] form_layout_row_set_visible(self.days_off_layout, row + 1, True) self.day_off_total_duration_labels[det].setText(yearly or '-') self.day_off_month_duration_labels[det].setText(monthly or '-') else: form_layout_row_set_visible(self.days_off_layout, row + 1, False) else: # If there are no days spent on any counter, then we display # all counters at the 0 mark. mainlog.debug("_show_totals_day_off : showing no event") row = 0 for det in DayEventType.symbols(): form_layout_row_set_visible(self.days_off_layout, row + 1, True) row += 1 # self.day_off_table_view.resizeColumnsToContents() self.days_off_panel.parent().update() @Slot() def refresh_action(self): global dao # mainlog.debug("refresh action started") self.hours_per_pers_subframe.set_title(date_to_my( self.base_date, True)) chrono.chrono_start() all_events_in_month = people_admin_service.events_for_month( self.base_date) employee_with_events = [ event.employee_id for event in all_events_in_month ] # mainlog.debug(all_events_in_month) self.all_events_in_year = people_admin_service.events_for_year( self.base_date.year) self.all_presences = all_presences = dao.employee_dao.presence_overview_for_month( self.base_date) all_correction_times = dict() for s in dao.month_time_synthesis_dao.load_all_synthesis( self.base_date.year, self.base_date.month): all_correction_times[s.employee_id] = s.correction_time special_activities = dao.special_activity_dao.find_on_month( self.base_date) employees = list( filter( lambda e: e.is_active or e.employee_id in all_presences or e. employee_id in all_correction_times or e.employee_id in special_activities or e.employee_id in employee_with_events, dao.employee_dao.list_overview())) self.employees = employees chrono.chrono_click() day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] t_start = datetime(self.base_date.year, self.base_date.month, 1) t_end = datetime(self.base_date.year, self.base_date.month, day_max, 23, 59, 59, 999999) self._table_model.setRowCount(len(employees)) self._table_model.setColumnCount(1 + day_max + 3) headers = QStandardItemModel(1, 1 + day_max + 3) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(day_max): headers.setHeaderData(i + 1, Qt.Orientation.Horizontal, "{}".format(i + 1)) headers.setHeaderData(day_max + 1, Qt.Orientation.Horizontal, _("Correction")) headers.setHeaderData(day_max + 2, Qt.Orientation.Horizontal, _("Total")) headers.setHeaderData(day_max + 3, Qt.Orientation.Horizontal, _("Days off")) self.headers_view.setModel( headers) # qt's doc : The view does *not* take ownership self.header_model = headers self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership # Compute all mondays indices monday = 0 if t_start.weekday() > 0: monday = 7 - t_start.weekday() all_mondays = [] while monday < day_max: all_mondays.append(monday) monday += 7 today = date.today() # mainlog.debug("Running on employees") for row in range(self._table_model.rowCount()): # Clear the line for col in range(0, 32): ndx = self._table_model.index(row, col) self._table_model.setData(ndx, None, Qt.BackgroundRole) self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData(ndx, None, Qt.DisplayRole) self._table_model.setData(ndx, None, Qt.UserRole) self._table_model.setData(ndx, None, Qt.UserRole + 1) # else: # self._table_model.setData(ndx,None,Qt.BackgroundRole) # else: # self._table_model.setData(ndx,None,Qt.DisplayRole) # self._table_model.setData(ndx,None,Qt.BackgroundRole) # Mark mondays for col in all_mondays: # col + 1 to account for the employee column self._table_model.setData( self._table_model.index(row, col + 1), QBrush(QColor(230, 230, 255)), Qt.BackgroundRole) # Mark today if today.month == self.base_date.month and today.year == self.base_date.year: self._table_model.setData( self._table_model.index(row, today.day), QBrush(QColor(255, 255, 128)), Qt.BackgroundRole) row = 0 for employee in employees: # employees are sorted self._table_model.setData(self._table_model.index(row, 0), employee.fullname, Qt.DisplayRole) # FIXME Use a delegate self._table_model.setData(self._table_model.index(row, 0), employee.employee_id, Qt.UserRole) # FIXME Use a delegate correction = 0 if employee.employee_id in all_correction_times: correction = all_correction_times[employee.employee_id] self._table_model.setData( self._table_model.index(row, day_max + 1), duration_to_hm(correction, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 1), None, Qt.DisplayRole) presence = 0 if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: import functools presence = functools.reduce( lambda acc, s: acc + s, all_presences[employee.employee_id], 0) presence += correction if presence != 0: self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData( self._table_model.index(row, day_max + 2), duration_to_hm(presence, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 2), None, Qt.DisplayRole) if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: for b in range(len(all_presences[employee.employee_id])): ndx = self._table_model.index(row, b + 1) p = all_presences[employee.employee_id][b] if p > 0: self._table_model.setData( ndx, duration_to_hm(p, short_unit=True), Qt.DisplayRole) self._table_model.setData(ndx, p, Qt.UserRole) if p >= 4 and p <= 8: # Regular work load self._table_model.setData( ndx, QBrush(QColor(192, 255, 192)), Qt.BackgroundRole) elif p > 8 or (p < 4 and p > 0): # Problematic work load self._table_model.setData( ndx, QBrush(QColor(255, 192, 192)), Qt.BackgroundRole) if employee.employee_id in special_activities: sa_of_employee = special_activities[employee.employee_id] for sa in sa_of_employee: start = max(t_start, sa.start_time) end = min(t_end, sa.end_time) for i in range(start.day, end.day + 1): ndx = self._table_model.index(row, i) self._table_model.setData(ndx, QBrush(QColor(255, 128, 0)), Qt.BackgroundRole) # self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight | Qt.AlignVCenter,Qt.TextAlignmentRole) row += 1 # Display day events employee_id_to_row = dict() # little accelerator for row in range(len(employees)): employee_id_to_row[employees[row].employee_id] = row # Compute days off totals and show them self.day_event_totals = dict([(e.employee_id, dict()) for e in employees]) for day_event in all_events_in_month: # mainlog.debug("employee_id = {}".format(day_event.employee_id)) # if day_event.employee_id not in self.day_event_totals: # mainlog.debug(self.day_event_totals) t = self.day_event_totals[day_event.employee_id] if day_event.event_type not in t: t[day_event.event_type] = day_event.duration else: t[day_event.event_type] += day_event.duration for employee in employees: # employees are sorted t = self.day_event_totals[employee.employee_id] mainlog.debug(t) total_off = sum(t.values()) mainlog.debug(total_off) row = employee_id_to_row[employee.employee_id] mainlog.debug(row) if total_off: self._table_model.setData( self._table_model.index(row, day_max + 3), nice_round(total_off), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 3), None, Qt.DisplayRole) # Show days off for day_event in all_events_in_month: row = employee_id_to_row[day_event.employee_id] col = day_event.date.day fg = bg = None if day_event.event_type in self.DAY_EVENT_PALETTE: fg, bg = self.DAY_EVENT_PALETTE[day_event.event_type] else: fg, bg = Qt.GlobalColor.red, Qt.GlobalColor.gray ndx = self._table_model.index(row, col) self._table_model.setData(ndx, day_event.day_event_id, Qt.UserRole + 1) # The problem here is to nicely blend the fact # that you can have a day event mixed with actual work # the very same day. Here's a poor man solution. active_time = self._table_model.data(ndx, Qt.UserRole) if not active_time: self._table_model.setData( ndx, DayEventType.short_code(day_event.event_type), Qt.DisplayRole) self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) else: self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) self._table_model.setData( ndx, duration_to_hm(active_time, short_unit=True) + DayEventType.short_code(day_event.event_type), Qt.DisplayRole) chrono.chrono_click() #for i in range(len(all_mondays)): self.table_view.resizeColumnsToContents() # mainlog.debug("Reset selection") ndx = self.table_view.currentIndex() self.table_view.selectionModel().clear() # self.table_view.selectionModel().clearSelection() # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(), ndx.column()), QItemSelectionModel.Select) self.cell_entered(self.table_view.currentIndex()) @Slot() def edit_tars(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) d = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, ndx.column()))) dialog = TimeReportingScannerDialog(self) dialog.set_data(datetime(d.year, d.month, d.day, 6, 0), employee_id) dialog.exec_() if dialog.result() == QDialog.Accepted: # pub.sendMessage('time_report.changed') self.timetrack_changed.emit() self.refresh_action() @Slot() def show_actions(self): button = self.action_menu.parent() p = button.mapToGlobal(QPoint(0, button.height())) self.action_menu.exec_(p) @Slot() def delete_holidays(self): ndx = self.table_view.currentIndex() employee_id = self._employee_id_on_row(ndx) d = date(self.base_date.year, self.base_date.month, ndx.column()) if dao.special_activity_dao.delete_by_employee_and_date( employee_id, d): self.refresh_panel() @Slot() def create_holidays(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) left_col = 1000 right_col = 0 for ndx in self.table_view.selectionModel().selectedIndexes(): c = ndx.column() left_col = min(c, left_col) right_col = max(c, right_col) d_start = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, left_col))) d_end = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, right_col))) dialog = HolidaysDialog(self) sa = SpecialActivity() sa.employee_id = employee_id sa.reporter_id = user_session.user_id sa.encoding_date = date.today() sa.start_time = datetime(d_start.year, d_start.month, d_start.day, 6, 0) sa.end_time = datetime(d_end.year, d_end.month, d_end.day, 14, 0) dialog.setup(sa, dao.employee_dao.find_by_id(employee_id).fullname) # dialog.set_data(employee,self.base_date,c) dialog.exec_() if dialog.result() == QDialog.Accepted: dao.special_activity_dao.save(sa) self.refresh_action() @Slot() def edit_month_correction(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) if employee_id: employee = dao.employee_dao.find_by_id(employee_id) c = dao.month_time_synthesis_dao.load_correction_time( employee_id, self.base_date.year, self.base_date.month) dialog = MonthTimeCorrectionDialog(self) dialog.set_data(employee.fullname, self.base_date, c) dialog.exec_() if dialog.result() == QDialog.Accepted: c = dao.month_time_synthesis_dao.save(employee_id, self.base_date.year, self.base_date.month, dialog.correction_time) self.refresh_action() @Slot() def month_today(self): self.base_date = date.today() self.refresh_action() @Slot() def month_before(self): m = self.base_date.month if m > 1: self.base_date = date(self.base_date.year, m - 1, 1) else: self.base_date = date(self.base_date.year - 1, 12, 1) self.refresh_action() @Slot() def month_after(self): m = self.base_date.month if self.base_date.year < date.today().year + 1 \ or m < date.today().month: if m < 12: self.base_date = date(self.base_date.year, m + 1, 1) else: self.base_date = date(self.base_date.year + 1, 1, 1) self.refresh_action() @Slot() def edit_timetrack_no_ndx(self): ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: self.edit_timetrack(ndx) else: showWarningBox(_("Can't edit"), _("You must first select a day/person.")) timetrack_changed = Signal() @Slot(QModelIndex) def edit_timetrack(self, ndx): global dao global user_session if ndx.column() >= 1: edit_date = date( self.base_date.year, self.base_date.month, ndx.column()) # +1 already in because of employee's names employee_id = self._employee_id_on_row(ndx) tars = dao.task_action_report_dao.get_reports_for_employee_id_on_date( employee_id, edit_date) if len(tars) == 0: d = EditTimeTracksDialog(self, dao, edit_date) d.set_employee_and_date(employee_id, edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() self.timetrack_changed.emit() d.deleteLater() else: edit_date = datetime(self.base_date.year, self.base_date.month, ndx.column(), hour=6) from koi.TimeReportingScanner import TimeReportingScannerDialog d = TimeReportingScannerDialog(self) d.set_data(edit_date, employee_id) # or 16 d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() self.timetrack_changed.emit() d.deleteLater() @Slot() def editTaskActionReports(self): if not user_session.has_any_roles(['TimeTrackModify']): return m = self.base_date.month ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: edit_date = date( self.base_date.year, m, ndx.column()) # +1 already in because of employee's names employee = self._table_model.data( self._table_model.index(ndx.row(), 0), Qt.UserRole) # FIXME Use a delegate d = EditTaskActionReportsDialog(dao, self, edit_date) d.set_employee_date(employee, edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() d.deleteLater() else: showWarningBox(_("Can't edit"), _("You must first select a day/person.")) # @Slot(QModelIndex) # def timetrack_changed(self,ndx): # selected_timetrack = self.controller.model.object_at(ndx) # # Update the colors in the timetrack views # # to show what action reports correspond to the # # selected timetrack # self.controller_actions.model.current_timetrack = selected_timetrack # self.controller_actions.model.beginResetModel() # self.controller_actions.model.endResetModel() # # Make sure the first of the action reports is shown in the # # table # action_reports = self.controller_actions.model.objects # for i in range(len(action_reports)-1,-1,-1): # if action_reports[i] and action_reports[i].timetrack == selected_timetrack: # self.controller_actions.view.scrollTo(self.controller_actions.model.index(i,0)) # break def _make_table_header(self): pass def __init__(self, parent, find_order_action_slot): super(PresenceOverviewWidget, self).__init__(parent) self.set_panel_title(_("Presence overview")) self.base_date = date.today() headers = QStandardItemModel(1, 31 + 3) self._table_model = QStandardItemModel(1, 31 + 3, None) self.headers_view = QHeaderView(Qt.Orientation.Horizontal, self) self.header_model = headers self.headers_view.setResizeMode(QHeaderView.ResizeToContents) self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership self.table_view = TableViewSignaledEvents(None) self.table_view.setModel(self._table_model) self.table_view.setHorizontalHeader(self.headers_view) self.table_view.verticalHeader().hide() self.table_view.setAlternatingRowColors(True) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setContextMenuPolicy(Qt.CustomContextMenu) self.table_view.customContextMenuRequested.connect( self.popup_context_menu) self.copy_action = QAction(_("Copy order parts"), self.table_view) self.copy_action.triggered.connect(self.copy_slot) self.copy_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_C)) self.copy_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.copy_action) self.select_all_action = QAction(_("Select all"), self.table_view) self.select_all_action.triggered.connect(self.select_all_slot) self.select_all_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_A)) self.select_all_action.setShortcutContext( Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.select_all_action) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectItems) # self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) navbar = NavBar(self, [(_("Month before"), self.month_before), (_("Today"), self.month_today), (_("Action"), self.show_actions), (_("Month after"), self.month_after), (_("Find"), find_order_action_slot)]) self.action_menu = QMenu(navbar.buttons[2]) navbar.buttons[2].setObjectName("specialMenuButton") navbar.buttons[4].setObjectName("specialMenuButton") self._make_days_off_menu_and_action_group() list_actions = [ # (_("Edit"),self.edit_tars, None, None), (_("Edit"), self.edit_timetrack_no_ndx, None, None), (_("Month correction"), self.edit_month_correction, None, [RoleType.modify_monthly_time_track_correction]), (self.days_off_menu, None), (self.copy_action, None), (self.select_all_action, None) ] # (_("Insert holidays"),self.create_holidays, None, None), # (_("Delete holidays"),self.delete_holidays, None, None) ] populate_menu(self.action_menu, self, list_actions) # mainlog.debug("tile widget") self.title_box = TitleWidget(_("Presence Overview"), self, navbar) self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget(self.title_box) self.hours_per_pers_subframe = SubFrame(_("Overview"), self.table_view, self) self.vlayout.addWidget(self.hours_per_pers_subframe) self.time_report_view = TimeReportView(self) self.days_off_panel = self._make_total_days_off_panel() vbox = QVBoxLayout() vbox.addWidget(self.days_off_panel) vbox.addStretch() vbox.setStretch(0, 0) vbox.setStretch(1, 1) hlayout = QHBoxLayout() hlayout.addWidget(self.time_report_view) hlayout.addLayout(vbox) hlayout.setStretch(0, 1) self.detail_subframe = SubFrame(_("Day"), hlayout, self) self.vlayout.addWidget(self.detail_subframe) self.setLayout(self.vlayout) # dbox = QVBoxLayout() # dbox.addWidget(QLabel("kjkljkj")) # self.total_active_hours = LabeledValue(_("Total activity")) # dbox.addWidget(self.total_active_hours) # hbox = QHBoxLayout() # hbox.addWidget(self.table_view) # hbox.addLayout(dbox) # self.selection_model = self.table_view.selectionModel() # mainlog.debug(m) #sm = QItemSelectionModel(self.table_view.model()) #sm.setModel(self.table_view.model()) # self.table_view.setSelectionModel(self.selection_model) self.table_view.selectionModel().currentChanged.connect( self.cell_entered) self.table_view.doubleClickedCell.connect(self.edit_timetrack) def _selection_to_period(self): left_col = 1000 right_col = 0 for ndx in self.table_view.selectionModel().selectedIndexes(): c = ndx.column() left_col = min(c, left_col) right_col = max(c, right_col) d_start = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, left_col))) d_end = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, right_col))) return d_start, d_end def _toggle_days_off_actions(self): day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] ndx = self.table_view.currentIndex() can_add = can_remove = False if ndx.column() >= 1 and ndx.column() <= day_max: day_event_id = ndx.data(Qt.UserRole + 1) can_add = True # if not day_event_id: # day = ndx.column() - 1 # # employee_id = self._employee_id_on_row(ndx) # if employee_id in self.all_presences: # if not self.all_presences[employee_id][day]: # can_add = True # else: # can_add = True # else: # can_add = True can_remove = day_event_id is not None self.days_off_add_submenu.setEnabled(can_add) for actions in self.days_off_action_group.actions(): actions.setEnabled(can_add) self.day_off_remove_action.setEnabled(can_remove) def _add_day_off(self, action): if action.data() != 'Remove': day_event_type, day_event_duration = action.data() day_event_type = DayEventType.from_str(day_event_type) mainlog.debug("selected action {} {}".format( day_event_type, day_event_duration)) ndx = self.table_view.currentIndex() day_event_id = ndx.data(Qt.UserRole + 1) # if day_event_id: # showWarningBox(_("There's already a day off here")) # return employee_id = self._employee_id_on_row(ndx) if employee_id in self.all_presences: day = ndx.column() - 1 mainlog.debug("_add_day_off : employee_id={}, day={}".format( employee_id, day)) mainlog.debug(self.all_presences[employee_id]) mainlog.debug(type(self.all_presences[employee_id])) # if self.all_presences[employee_id][day]: # showWarningBox(_("One can't add day off where there is activity")) # return else: mainlog.debug( "_add_day_off : employee_id={} not yet known".format( employee_id)) day_event = DayEvent() day_event.employee_id = employee_id day_event.event_type = day_event_type day, last_day = self._selection_to_period() if day_event_duration in (0.5, 1): days_durations = [(day, day_event_duration)] else: days_durations = [] day, last_day = self._selection_to_period() while day <= last_day: days_durations.append( (day, 1)) # One full work day on the day day += timedelta(1) # mainlog.debug(days_durations) mainlog.debug("Creating day event of type {}".format( day_event.event_type)) try: people_admin_service.set_event_on_days(day_event, days_durations) except ServerException as ex: showErrorBox(ex.translated_message) self.refresh_action() def _remove_day_off(self): # Grab all the selected events event_ids = [] for ndx in self.table_view.selectionModel().selectedIndexes(): day_event_id = ndx.data(Qt.UserRole + 1) if day_event_id: mainlog.debug("Removing event: {}".format(day_event_id)) event_ids.append(day_event_id) # Remove them if event_ids: people_admin_service.remove_events(event_ids) self.refresh_action() def _make_days_off_menu_and_action_group(self): # We use a action group to be able to use the data() of actions # when action is tigerred # Call this ONLY ONCE because there are signal/slot connections. self.days_off_menu = QMenu(_("Day off")) self.days_off_add_submenu = QMenu(_("Set day off")) self.days_off_action_group = QActionGroup(self) for det in DayEventType.symbols(): a_one = QAction(_("Set one day"), self.days_off_action_group) a_one.setData((det.value, 1)) a_half = QAction(_("Set half day"), self.days_off_action_group) a_half.setData((det.value, 0.5)) a_period = QAction(_("Set period"), self.days_off_action_group) a_period.setData((det.value, 2)) self.days_off_action_group.addAction(a_one) self.days_off_action_group.addAction(a_half) self.days_off_action_group.addAction(a_period) m = QMenu(_("Set time off for {}").format(det.description)) m.addAction(a_one) m.addAction(a_half) m.addAction(a_period) self.days_off_add_submenu.addMenu(m) self.days_off_action_group.triggered.connect(self._add_day_off) self.day_off_remove_action = QAction(_("Remove day off"), self) self.day_off_remove_action.triggered.connect(self._remove_day_off) # Now we have the actions, we build the menu self.days_off_menu.addMenu(self.days_off_add_submenu) self.days_off_menu.addAction(self.day_off_remove_action) @Slot(QPoint) def popup_context_menu(self, position): self.days_off_menu.exec_(QCursor.pos()) @Slot() def select_all_slot(self): m = self.table_view.model() all = QItemSelection(m.index(0, 0), m.index(m.rowCount() - 1, m.columnCount() - 1)) self.table_view.selectionModel().select(all, QItemSelectionModel.Select) @Slot() def copy_slot(self): # Collect the rows indices indices = self.table_view.selectedIndexes() if not indices: return min_row = max_row = indices[0].row() min_col = max_col = indices[0].column() def min_max(minimum, v, maximum): if v < minimum: return v, maximum elif v > maximum: return minimum, v else: return minimum, maximum for ndx in self.table_view.selectedIndexes(): min_row, max_row = min_max(min_row, ndx.row(), max_row) min_col, max_col = min_max(min_col, ndx.column(), max_col) mainlog.debug("Copy from {},{} to {},{}".format( min_row, min_col, max_row, max_col)) day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] s = "" for r in range(min_row, max_row + 1): d = [] for c in range(min_col, max_col + 1): ndx = self._table_model.item(r, c) if c == 0 or c > day_max: d.append(ndx.data(Qt.DisplayRole) or "") else: t = ndx.data(Qt.UserRole + 1) # Day off if t: t = ndx.data(Qt.DisplayRole) else: hours = ndx.data(Qt.UserRole) # Activity hours if hours is not None: t = str(hours).replace('.', ',') else: t = "" d.append(t) s += "\t".join(d) + u"\n" QApplication.clipboard().setText(s)
def __init__(self, parent, find_order_action_slot): super(PresenceOverviewWidget, self).__init__(parent) self.set_panel_title(_("Presence overview")) self.base_date = date.today() headers = QStandardItemModel(1, 31 + 3) self._table_model = QStandardItemModel(1, 31 + 3, None) self.headers_view = QHeaderView(Qt.Orientation.Horizontal, self) self.header_model = headers self.headers_view.setResizeMode(QHeaderView.ResizeToContents) self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership self.table_view = TableViewSignaledEvents(None) self.table_view.setModel(self._table_model) self.table_view.setHorizontalHeader(self.headers_view) self.table_view.verticalHeader().hide() self.table_view.setAlternatingRowColors(True) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setContextMenuPolicy(Qt.CustomContextMenu) self.table_view.customContextMenuRequested.connect( self.popup_context_menu) self.copy_action = QAction(_("Copy order parts"), self.table_view) self.copy_action.triggered.connect(self.copy_slot) self.copy_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_C)) self.copy_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.copy_action) self.select_all_action = QAction(_("Select all"), self.table_view) self.select_all_action.triggered.connect(self.select_all_slot) self.select_all_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_A)) self.select_all_action.setShortcutContext( Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.select_all_action) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectItems) # self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) navbar = NavBar(self, [(_("Month before"), self.month_before), (_("Today"), self.month_today), (_("Action"), self.show_actions), (_("Month after"), self.month_after), (_("Find"), find_order_action_slot)]) self.action_menu = QMenu(navbar.buttons[2]) navbar.buttons[2].setObjectName("specialMenuButton") navbar.buttons[4].setObjectName("specialMenuButton") self._make_days_off_menu_and_action_group() list_actions = [ # (_("Edit"),self.edit_tars, None, None), (_("Edit"), self.edit_timetrack_no_ndx, None, None), (_("Month correction"), self.edit_month_correction, None, [RoleType.modify_monthly_time_track_correction]), (self.days_off_menu, None), (self.copy_action, None), (self.select_all_action, None) ] # (_("Insert holidays"),self.create_holidays, None, None), # (_("Delete holidays"),self.delete_holidays, None, None) ] populate_menu(self.action_menu, self, list_actions) # mainlog.debug("tile widget") self.title_box = TitleWidget(_("Presence Overview"), self, navbar) self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget(self.title_box) self.hours_per_pers_subframe = SubFrame(_("Overview"), self.table_view, self) self.vlayout.addWidget(self.hours_per_pers_subframe) self.time_report_view = TimeReportView(self) self.days_off_panel = self._make_total_days_off_panel() vbox = QVBoxLayout() vbox.addWidget(self.days_off_panel) vbox.addStretch() vbox.setStretch(0, 0) vbox.setStretch(1, 1) hlayout = QHBoxLayout() hlayout.addWidget(self.time_report_view) hlayout.addLayout(vbox) hlayout.setStretch(0, 1) self.detail_subframe = SubFrame(_("Day"), hlayout, self) self.vlayout.addWidget(self.detail_subframe) self.setLayout(self.vlayout) # dbox = QVBoxLayout() # dbox.addWidget(QLabel("kjkljkj")) # self.total_active_hours = LabeledValue(_("Total activity")) # dbox.addWidget(self.total_active_hours) # hbox = QHBoxLayout() # hbox.addWidget(self.table_view) # hbox.addLayout(dbox) # self.selection_model = self.table_view.selectionModel() # mainlog.debug(m) #sm = QItemSelectionModel(self.table_view.model()) #sm.setModel(self.table_view.model()) # self.table_view.setSelectionModel(self.selection_model) self.table_view.selectionModel().currentChanged.connect( self.cell_entered) self.table_view.doubleClickedCell.connect(self.edit_timetrack)
class TimeTracksOverviewWidget(QWidget): @Slot(QModelIndex) def cell_entered(self,ndx): chrono = datetime.now() employee = self.employees[ndx.row()] a = max(1,ndx.column()) d = date(self.base_date.year,self.base_date.month,min(calendar.monthrange(self.base_date.year,self.base_date.month)[1], max(1,ndx.column()))) # print employee, d # Fill in the timetracks report panel ---------------------------- # First we read the timetrackss and their associated OrderPart t_start = datetime(d.year,d.month,d.day,0,0,0,0) t_end = datetime(d.year,d.month,d.day,23,59,59,999999) # FIXME not abstract enough # FIXME This should be in the DAO tt = session().query(TimeTrack,OrderPart).\ join(TaskOnOperation).join(Operation).join(ProductionFile).join(OrderPart).\ filter(and_(TimeTrack.employee == employee, TimeTrack.start_time >= t_start, TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all() tt += session().query(TimeTrack,Order).join(TaskOnOrder).join(Order).filter(and_(TimeTrack.employee == employee, TimeTrack.start_time >= t_start, TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all() tt += session().query(TimeTrack,OperationDefinition).join(TaskOnNonBillable).join(OperationDefinition).filter(and_(TimeTrack.employee == employee, TimeTrack.start_time >= t_start, TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all() # Fill in the report panel --------------------------------------- self.hours_on_day_subframe.set_title(_("Hours worked on the {} by {}").format(date_to_s(d,True),employee.fullname)) self.controller.model._buildModelFromObjects(map(lambda o : o[0],tt)) # dao.timetrack_dao.all_for_employee(employee)) # self.controller.model.row_protect_func = lambda obj,row: obj is not None and obj.managed_by_code ndx = 0 for row in self.controller.model.table: if row[1]: row[0] = tt[ndx][1] # First column becomes the order ndx += 1 self.controller.view.resizeColumnsToContents() # Fill in the time report panel --------------------------------- self.pointage_timestamp_prototype.set_fix_date(d) self.controller_actions.model._buildModelFromObjects( dao.task_action_report_dao.get_reports_for_employee_on_date(employee,d)) @Slot() def refresh_action(self): global dao self.title_box.set_title(_("Time Records Overview - {}").format(date_to_my(self.base_date,True))) self.employees = dao.employee_dao.all() day_max = calendar.monthrange(self.base_date.year,self.base_date.month)[1] t_start = datetime(self.base_date.year,self.base_date.month,1) t_end = datetime(self.base_date.year,self.base_date.month,day_max,23,59,59,999999) self._table_model.setRowCount( len(self.employees)) self._table_model.setColumnCount( 1+day_max) headers = QStandardItemModel(1, 1+day_max) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(day_max): headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1)) self.headers_view.setModel(headers) # qt's doc : The view does *not* take ownership self.header_model = headers row = 0 for employee in self.employees: # mainlog.debug(u"refresh action employee {}".format(employee)) self._table_model.setData(self._table_model.index(row,0),employee.fullname,Qt.DisplayRole) # FIXME Use a delegate self._table_model.setData(self._table_model.index(row,0),employee,Qt.UserRole) # FIXME Use a delegate tracks = session().query(TimeTrack).filter(and_(TimeTrack.employee_id == employee.employee_id, TimeTrack.start_time >= t_start,TimeTrack.start_time <= t_end)).all() # One bucket per day buckets = [0] * day_max for t in tracks: mainlog.debug("Bucket {}".format(t)) buckets[t.start_time.day - 1] += t.duration for b in range(len(buckets)): if buckets[b] != 0: self._table_model.setData(self._table_model.index(row,b+1),duration_to_s(buckets[b]),Qt.DisplayRole) else: self._table_model.setData(self._table_model.index(row,b+1),None,Qt.DisplayRole) if buckets[b] >= 0: # Clear the background self._table_model.setData(self._table_model.index(row,b+1),None,Qt.BackgroundRole) else: self._table_model.setData(self._table_model.index(row,b+1),QBrush(QColor(255,128,128)),Qt.TextColorRole) self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight,Qt.TextAlignmentRole) row += 1 # Compute all mondays indices monday = 0 if t_start.weekday() > 0: monday = 7 - t_start.weekday() all_mondays = [] while monday < day_max: all_mondays.append(monday) monday += 7 today = date.today() for row in range(len(self.employees)): # Mark mondays for col in all_mondays: # col + 1 to account for the employee column self._table_model.setData(self._table_model.index(row,col + 1),QBrush(QColor(230,230,255)),Qt.BackgroundRole) # Mark today if today.month == self.base_date.month and today.year == self.base_date.year: self._table_model.setData(self._table_model.index(row,today.day),QBrush(QColor(255,255,128)),Qt.BackgroundRole) #for i in range(len(all_mondays)): self.table_view.resizeColumnsToContents() # mainlog.debug("Reset selection") ndx = self.table_view.currentIndex() self.table_view.selectionModel().clear() # self.table_view.selectionModel().clearSelection() # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.cell_entered(self.table_view.currentIndex()) @Slot() def month_today(self): self.base_date = date.today() self.refresh_action() @Slot() def month_before(self): m = self.base_date.month if m > 1: self.base_date = date(self.base_date.year,m - 1,self.base_date.day) else: self.base_date = date(self.base_date.year - 1,12,self.base_date.day) self.refresh_action() @Slot() def month_after(self): m = self.base_date.month if self.base_date.year < date.today().year or m < date.today().month: if m < 12: self.base_date = date(self.base_date.year,m + 1,self.base_date.day) else: self.base_date = date(self.base_date.year + 1,1,self.base_date.day) self.refresh_action() @Slot() def edit_timetrack_no_ndx(self): ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: self.edit_timetrack(ndx) else: showWarningBox(_("Can't edit"),_("You must first select a day/person.")) @Slot(QModelIndex) def edit_timetrack(self,ndx): global dao global user_session if not user_session.has_any_roles(['TimeTrackModify']): return m = self.base_date.month edit_date = date(self.base_date.year,m,ndx.column()) # +1 already in because of employee's names employee = self._table_model.data(self._table_model.index(ndx.row(),0),Qt.UserRole) # FIXME Use a delegate d = EditTimeTracksDialog(self,dao,edit_date) d.set_employee_and_date(employee,edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() d.deleteLater() @Slot() def editTaskActionReports(self): if not user_session.has_any_roles(['TimeTrackModify']): return m = self.base_date.month ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: edit_date = date(self.base_date.year,m,ndx.column()) # +1 already in because of employee's names employee = self._table_model.data(self._table_model.index(ndx.row(),0),Qt.UserRole) # FIXME Use a delegate d = EditTaskActionReportsDialog(dao,self,edit_date) d.set_employee_date(employee, edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() d.deleteLater() else: showWarningBox(_("Can't edit"),_("You must first select a day/person.")) @Slot(QModelIndex) def timetrack_changed(self,ndx): selected_timetrack = self.controller.model.object_at(ndx) # Update the colors in the timetrack views # to show what action reports correspond to the # selected timetrack self.controller_actions.model.current_timetrack = selected_timetrack self.controller_actions.model.beginResetModel() self.controller_actions.model.endResetModel() # Make sure the first of the action reports is shown in the # table action_reports = self.controller_actions.model.objects for i in range(len(action_reports)-1,-1,-1): if action_reports[i] and action_reports[i].timetrack == selected_timetrack: self.controller_actions.view.scrollTo(self.controller_actions.model.index(i,0)) break def __init__(self,parent): super(TimeTracksOverviewWidget,self).__init__(parent) self.base_date = date.today() headers = QStandardItemModel(1, 31 + 1) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(31): headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1)) self._table_model = QStandardItemModel(1, 31+1, None) self.headers_view = QHeaderView(Qt.Orientation.Horizontal,self) self.header_model = headers self.headers_view.setResizeMode(QHeaderView.ResizeToContents) self.headers_view.setModel(self.header_model) # qt's doc : The view does *not* take ownership self.table_view = QTableView(None) self.table_view.setModel(self._table_model) self.table_view.setHorizontalHeader(self.headers_view) self.table_view.verticalHeader().hide() self.table_view.setAlternatingRowColors(True) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) navbar = NavBar(self, [ (_("Month before"), self.month_before), (_("Today"),self.month_today), (_("Month after"), self.month_after)]) self.title_box = TitleWidget(_("Time Records Overview"),self,navbar) self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget(self.title_box) self.setLayout(self.vlayout) self.hours_per_pers_subframe = SubFrame(_("Hours worked per person"), self.table_view, self) self.vlayout.addWidget(self.hours_per_pers_subframe) hlayout = QHBoxLayout() prototype = [] prototype.append( OrderPartOnTaskPrototype(None, _('Order Part'))) prototype.append( TaskOnOrderPartPrototype('task', _('Task'),on_date=date.today())) prototype.append( DurationPrototype('duration',_('Duration'))) prototype.append( TimestampPrototype('start_time',_('Start time'),fix_date=date.today())) prototype.append( DatePrototype('encoding_date',_('Recorded at'),editable=False)) self.controller = PrototypeController(self,prototype) self.controller.setModel(TrackingProxyModel(self,prototype)) self.controller.view.setColumnWidth(1,300) self.controller.view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.controller.view.horizontalHeader().setResizeMode(1,QHeaderView.Stretch) navbar = NavBar(self, [ (_("Edit"), self.edit_timetrack_no_ndx)]) self.hours_on_day_subframe = SubFrame(_("Total times on day"), self.controller.view, self,navbar) hlayout.addWidget(self.hours_on_day_subframe) prototype = [] # prototype.append( EmployeePrototype('reporter', _('Description'), dao.employee_dao.all())) prototype.append( TaskDisplayPrototype('task', _('Task'))) self.pointage_timestamp_prototype = TimestampPrototype('time',_('Hour'),editable=False,fix_date=date.today()) prototype.append( self.pointage_timestamp_prototype) prototype.append( TaskActionTypePrototype('kind',_('Action'))) prototype.append( TextLinePrototype('origin_location',_('Origin'))) prototype.append( TextLinePrototype('editor',_('Editor'),editable=False,default='master')) self.controller_actions = PrototypeController(self,prototype) self.controller_actions.setModel(ActionReportModel(self,prototype)) navbar = NavBar(self, [ (_("Edit"), self.editTaskActionReports)]) hlayout.addWidget(SubFrame(_("Time records"),self.controller_actions.view,self,navbar)) self.controller_actions.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.controller_actions.view.doubleClicked.connect(self.editTaskActionReports) self.controller_actions.view.horizontalHeader().setResizeMode(0,QHeaderView.Stretch) self.controller_actions.view.horizontalHeader().setResizeMode(3,QHeaderView.ResizeToContents) self.controller_actions.view.horizontalHeader().setResizeMode(4,QHeaderView.ResizeToContents) self.vlayout.addLayout(hlayout) self.vlayout.setStretch(0,0) self.vlayout.setStretch(1,300) self.vlayout.setStretch(2,200) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) #self.table_view.entered.connect(self.cell_entered) self.table_view.selectionModel().currentChanged.connect(self.cell_entered) self.table_view.doubleClicked.connect(self.edit_timetrack) self.controller.view.selectionModel().currentChanged.connect(self.timetrack_changed) self.controller.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.refresh_action()
def __init__(self,parent): super(TimeTracksOverviewWidget,self).__init__(parent) self.base_date = date.today() headers = QStandardItemModel(1, 31 + 1) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(31): headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1)) self._table_model = QStandardItemModel(1, 31+1, None) self.headers_view = QHeaderView(Qt.Orientation.Horizontal,self) self.header_model = headers self.headers_view.setResizeMode(QHeaderView.ResizeToContents) self.headers_view.setModel(self.header_model) # qt's doc : The view does *not* take ownership self.table_view = QTableView(None) self.table_view.setModel(self._table_model) self.table_view.setHorizontalHeader(self.headers_view) self.table_view.verticalHeader().hide() self.table_view.setAlternatingRowColors(True) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) navbar = NavBar(self, [ (_("Month before"), self.month_before), (_("Today"),self.month_today), (_("Month after"), self.month_after)]) self.title_box = TitleWidget(_("Time Records Overview"),self,navbar) self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget(self.title_box) self.setLayout(self.vlayout) self.hours_per_pers_subframe = SubFrame(_("Hours worked per person"), self.table_view, self) self.vlayout.addWidget(self.hours_per_pers_subframe) hlayout = QHBoxLayout() prototype = [] prototype.append( OrderPartOnTaskPrototype(None, _('Order Part'))) prototype.append( TaskOnOrderPartPrototype('task', _('Task'),on_date=date.today())) prototype.append( DurationPrototype('duration',_('Duration'))) prototype.append( TimestampPrototype('start_time',_('Start time'),fix_date=date.today())) prototype.append( DatePrototype('encoding_date',_('Recorded at'),editable=False)) self.controller = PrototypeController(self,prototype) self.controller.setModel(TrackingProxyModel(self,prototype)) self.controller.view.setColumnWidth(1,300) self.controller.view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.controller.view.horizontalHeader().setResizeMode(1,QHeaderView.Stretch) navbar = NavBar(self, [ (_("Edit"), self.edit_timetrack_no_ndx)]) self.hours_on_day_subframe = SubFrame(_("Total times on day"), self.controller.view, self,navbar) hlayout.addWidget(self.hours_on_day_subframe) prototype = [] # prototype.append( EmployeePrototype('reporter', _('Description'), dao.employee_dao.all())) prototype.append( TaskDisplayPrototype('task', _('Task'))) self.pointage_timestamp_prototype = TimestampPrototype('time',_('Hour'),editable=False,fix_date=date.today()) prototype.append( self.pointage_timestamp_prototype) prototype.append( TaskActionTypePrototype('kind',_('Action'))) prototype.append( TextLinePrototype('origin_location',_('Origin'))) prototype.append( TextLinePrototype('editor',_('Editor'),editable=False,default='master')) self.controller_actions = PrototypeController(self,prototype) self.controller_actions.setModel(ActionReportModel(self,prototype)) navbar = NavBar(self, [ (_("Edit"), self.editTaskActionReports)]) hlayout.addWidget(SubFrame(_("Time records"),self.controller_actions.view,self,navbar)) self.controller_actions.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.controller_actions.view.doubleClicked.connect(self.editTaskActionReports) self.controller_actions.view.horizontalHeader().setResizeMode(0,QHeaderView.Stretch) self.controller_actions.view.horizontalHeader().setResizeMode(3,QHeaderView.ResizeToContents) self.controller_actions.view.horizontalHeader().setResizeMode(4,QHeaderView.ResizeToContents) self.vlayout.addLayout(hlayout) self.vlayout.setStretch(0,0) self.vlayout.setStretch(1,300) self.vlayout.setStretch(2,200) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) #self.table_view.entered.connect(self.cell_entered) self.table_view.selectionModel().currentChanged.connect(self.cell_entered) self.table_view.doubleClicked.connect(self.edit_timetrack) self.controller.view.selectionModel().currentChanged.connect(self.timetrack_changed) self.controller.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.refresh_action()
def mousePressEvent(self, event): self.isOn = not self.isOn self.updateSection(0) print(event) QHeaderView.mousePressEvent(self, event)
def __init__(self, orientation, parent=None): QHeaderView.__init__(self, orientation, parent)
class FindOrderDialog(QDialog): def __init__(self,parent): global dao super(FindOrderDialog,self).__init__(parent) title = _("Find order") self.setWindowTitle(title) top_layout = QVBoxLayout() self.title_widget = TitleWidget(title,self) top_layout.addWidget(self.title_widget) hlayout = QHBoxLayout() hlayout.addWidget(QLabel(_("Search"))) self.search_criteria = QLineEdit() self.search_criteria.setObjectName("search_criteria") hlayout.addWidget(self.search_criteria) top_layout.addLayout(hlayout) self.search_results_view = QTableView() self.headers_view = QHeaderView(Qt.Orientation.Horizontal) self.header_model = make_header_model([_("Preorder Nr"),_("Order Nr"),_("Customer Nr"),_("Customer"),_("Order Part")]) self.headers_view.setModel(self.header_model) # qt's doc : The view does *not* take ownership (bt there's something with the selecion mode self.search_results_model = QStandardItemModel() self.search_results_view.setModel(self.search_results_model) self.search_results_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.search_results_view.setHorizontalHeader(self.headers_view) self.search_results_view.verticalHeader().hide() # self.search_results_view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.search_results_view.horizontalHeader().setResizeMode(3, QHeaderView.Stretch) self.search_results_view.horizontalHeader().setResizeMode(4, QHeaderView.Stretch) self.search_results_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.buttons = QDialogButtonBox() self.buttons.addButton( QDialogButtonBox.StandardButton.Cancel) self.buttons.addButton( QDialogButtonBox.Ok) self.buttons.button(QDialogButtonBox.Ok).setObjectName("go_search") top_layout.addWidget(self.search_results_view) top_layout.setStretch(2,1000) top_layout.addWidget(self.buttons) self.setLayout(top_layout) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.search_results_view.activated.connect(self.row_activated) self.search_criteria.returnPressed.connect(self.search_criteria_submitted) self.setMinimumSize(800,640) def find_by_text(self,text): text = text.strip() try: too_many_results, res = dao.order_part_dao.find_ids_by_text(text.strip()) if too_many_results: showWarningBox(_("Too many results"),_("The query you've given brought back too many results. Only a part of them is displayed. Consider refining your query"),object_name="too_many_results") return dao.order_part_dao.find_by_ids(res) except DataException as de: if de.code == DataException.CRITERIA_IS_EMPTY: showErrorBox(_("Error in the filter !"), _("The filter can't be empty"),object_name="filter_is_empty") elif de.code == DataException.CRITERIA_IS_TOO_SHORT: showErrorBox(_("Error in the filter !"), _("The filter is too short"),object_name="filter_is_too_short") elif de.code == DataException.CRITERIA_IS_TOO_LONG: showErrorBox(_("Error in the filter !"), _("The filter is too long"),object_name="filter_is_too_long") return [] # order_part_match = [] # matches = [] # super_matches = [] # import re # re_order_part_identifier = re.compile("^([0-9]+)([A-Z]+)$") # re_label_identifier = re.compile("^[0-9]+$") # if re_order_part_identifier.match(text.upper()): # # Look for an exact (and unique) match on the order part full identifier # p = dao.order_part_dao.find_by_full_id(text.upper()) # if p: # # Mimick SQLAlchemy's KeyTuples # # FIXME It seems that I use something that's internal to SQLA # # Search SQLA's doc for KeyedTuple to find about collections.namedtuple() # from sqlalchemy.util._collections import KeyedTuple # kt = KeyedTuple([p.order_id, p.order.preorder_label, p.order.accounting_label, p.order.customer_order_name, p.order.customer.fullname, p.order.creation_date, p.description, p.order_part_id, p.label], # labels=['order_id','preorder_label','accounting_label','customer_order_name','fullname','creation_date','description','order_part_id','label']) # order_part_match = [ kt ] # if re_label_identifier.match(text): # for r in dao.order_dao.find_by_labels(int(text)): # super_matches.append(r) # for r in dao.order_dao.find_by_customer_name(text): # # mainlog.debug('customer name match on {}'.format(text)) # matches.append(r) # for r in dao.order_dao.find_by_customer_order_name(text): # # mainlog.debug('customer name match on {}'.format(text)) # matches.append(r) # for r in dao.order_part_dao.find_by_description(text): # matches.append(r) # # Finally we order the matches to bring the most relevant # # first. The "most relevant" is really a business order. # return order_part_match + super_matches + \ # sorted(matches, lambda a,b: - cmp(a.order_id,b.order_id)) def _search_results_to_array(self,search_results): array = [] for res in search_results: # mainlog.debug("_search_results_to_array {}".format(res.creation_date)) i = QStandardItem(res.preorder_part_label) row = [i, QStandardItem(res.accounting_part_label), QStandardItem(res.customer_order_name), QStandardItem(res.fullname)] if 'order_part_id' in res.__dict__: # It's an order part i.setData( res.order_part_id, Qt.UserRole) i.setData( 'order_part', Qt.UserRole+1) row.append( QStandardItem(res.description)) else: # It's an order i.setData( res.order_id, Qt.UserRole) i.setData( 'order', Qt.UserRole+1) row.append( QStandardItem()) array.append(row) return array def load_search_results(self,text=None): global dao if text is None: text = self.search_criteria.text() db_results = self.find_by_text(text) array = self._search_results_to_array(db_results) self.search_results_model.removeRows(0,self.search_results_model.rowCount()) for row in array: self.search_results_model.appendRow(row) mainlog.debug("Loaded model : {}".format(self.search_results_model.rowCount())) self.search_results_view.resizeColumnsToContents() if self.search_results_model.rowCount() > 0: self.search_results_view.setCurrentIndex(self.search_results_model.index(0,0)) self.search_results_view.setFocus(Qt.OtherFocusReason) if self.search_results_model.rowCount() == 1: self.accept() def selected_item(self): mainlog.debug("FindOrder.selected_item") ndx = self.search_results_view.currentIndex() if ndx.isValid(): ndx = self.search_results_view.model().index( ndx.row(), 0) item = ndx.data(Qt.UserRole) item_type = ndx.data(Qt.UserRole+1) if item_type == 'order': mainlog.debug("FindOrder.selected_item order_id={}".format(item)) return dao.order_dao.find_by_id(item) elif item_type == 'order_part': mainlog.debug("FindOrder.selected_item order_part_id={}".format(item)) return dao.order_part_dao.find_by_id(item) else: mainlog.error("Unsupported item type {}".format(item_type)) else: mainlog.error("Invalid index") return None @Slot() def accept(self): # mainlog.debug("accept") # self.load_search_results() # mainlog.debug("accept - done") return super(FindOrderDialog,self).accept() @Slot() def reject(self): return super(FindOrderDialog,self).reject() @Slot() def search_criteria_submitted(self): mainlog.debug("search_criteria_submitted") self.load_search_results() @Slot(QModelIndex) def row_activated(self,ndx): mainlog.debug("row_activated") self.accept() def keyPressEvent(self,event): # The goal here is to make sure the accept signal is called only # if the user clicks on the "OK" button /with the mouse/ and, # not with the keyboard if event.key() in (Qt.Key_Enter, Qt.Key_Return): return else: super(FindOrderDialog,self).keyPressEvent(event)