예제 #1
0
 def dropEvent(self, e):
     """Accept drop events."""
     model = QStandardItemModel()
     model.dropMimeData(
         e.mimeData(), Qt.CopyAction, 0, 0, QModelIndex())
     name = model.item(0).text()
     item = None
     if name in ['And', 'Or', 'Nand', 'Nor', 'Not', 'Xor', 'Xnor']:
         item = CircuitItem(
             getattr(engine.gates, name + 'Gate')(None, self.mainCircuit))
     elif name == 'RSFlipFlop':
         item = CircuitItem(RSFlipFlop(None, self.mainCircuit))
     elif name == 'JKFlipFlop':
         item = CircuitItem(JKFlipFlop(None, self.mainCircuit))
     elif name == self.str_I:
         item = PlugItem(Plug(True, None, self.mainCircuit))
     elif name == self.str_O:
         item = PlugItem(Plug(False, None, self.mainCircuit))
     elif name == self.str_Clock:
         if not self.clockPlug:
             self.clockPlug = Clock(self.mainCircuit)
             self.clockPlug.clkThread.set_extern(self.clockUpdate)
             item = PlugItem(self.clockPlug)
         else:
             self.write(self.str_onlyOneClock)
     elif model.item(0, 1).text() == 'user':
         c = Circuit(None, self.mainCircuit)
         f = open(filePath('user/') + name + '.crc', 'rb')
         children = pickle.load(f)
         f.close()
         for child in children:
             if isinstance(child[0], Plug):
                 child[0].owner = c
                 if child[0].isInput:
                     c.inputList.append(child[0])
                 else:
                     c.outputList.append(child[0])
             elif isinstance(child[0], Circuit):
                 child[0].owner = c
                 c.circuitList.append(child[0])
         c.category = name
         item = CircuitItem(c)
     if item:
         # Fixes the default behaviour of centering the first
         # item added to scene.
         if not len(self.scene().items()):
             self.scene().setSceneRect(0, 0, 1, 1)
         else:
             self.scene().setSceneRect(0, 0, 0, 0)
         self.scene().addItem(item)
         item.setupPaint()
         item.setPos(
             closestGridPoint(item.mapFromScene(self.mapToScene(e.pos()))))
         for i in self.scene().selectedItems():
             i.setSelected(False)
         item.setSelected(True)
         self.timer.start()
예제 #2
0
    def testRefCount(self):
        model = QStandardItemModel(5, 5)
        items = []
        for r in range(5):
            row = []
            for c in range(5):
                row.append(QStandardItem("%d,%d" % (r,c)) )
                self.assertEqual(sys.getrefcount(row[c]), 2)

            model.insertRow(r, row)

            for c in range(5):
                ref_after = sys.getrefcount(row[c])
                # check if the ref count was incremented after insertRow
                self.assertEqual(ref_after, 3)

            items.append(row)
            row = None

        for r in range(3):
            my_row = model.takeRow(0)
            my_row = None
            for c in range(5):
                # only rest 1 reference
                self.assertEqual(sys.getrefcount(items[r][c]), 2)

        my_i = model.item(0,0)
        # ref(my_i) + parent_ref + items list ref
        self.assertEqual(sys.getrefcount(my_i), 4)

        model.clear()
        # ref(my_i)
        self.assertEqual(sys.getrefcount(my_i), 3)
예제 #3
0
    def testRefCount(self):
        model = QStandardItemModel(5, 5)
        items = []
        for r in range(5):
            row = []
            for c in range(5):
                row.append(QStandardItem("%d,%d" % (r,c)) )
                self.assertEqual(sys.getrefcount(row[c]), 2)

            model.insertRow(r, row)

            for c in range(5):
                ref_after = sys.getrefcount(row[c])
                # check if the ref count was incremented after insertRow
                self.assertEqual(ref_after, 3)

            items.append(row)
            row = None

        for r in range(3):
            my_row = model.takeRow(0)
            my_row = None
            for c in range(5):
                # only rest 1 reference
                self.assertEqual(sys.getrefcount(items[r][c]), 2)

        my_i = model.item(0,0)
        # ref(my_i) + parent_ref + items list ref
        self.assertEqual(sys.getrefcount(my_i), 4)

        model.clear()
        # ref(my_i)
        self.assertEqual(sys.getrefcount(my_i), 3)
예제 #4
0
class BrowserWindow(QMainWindow):

    MO_ROLE = Qt.UserRole+1

    def __init__(self, conn):
        super(BrowserWindow, self).__init__()
        self._conn = conn
        self._resolver = AsyncResolver()
        self._resolver.object_resolved.connect(self._data_resolved)
        self._resolver.start()
        self._init_models()
        self._init_gui()
        self._init_data()
        self._init_connections()

    def __del__(self):
        self._resolver.stop_work()
        self._resolver.terminate()

    def _init_models(self):
        self._hierarchy_model = QStandardItemModel()
        self._hierarchy_model.setColumnCount(2)
        self._hierarchy_model.setHorizontalHeaderLabels(['class', 'dn'])
        self._details_model = QStandardItemModel()
        self._details_model.setColumnCount(2)
        self._details_model.setHorizontalHeaderLabels(['Property', 'Value'])

    def _init_gui(self):
        self._widget = QSplitter(self, Qt.Horizontal)
        self._hierarchy_view = QTreeView(self._widget)
        self._details_view = QTableView(self._widget)

        self._widget.addWidget(self._hierarchy_view)
        self._widget.addWidget(self._details_view)
        self._widget.setStretchFactor(0, 2)
        self._widget.setStretchFactor(1, 1)
        self.setCentralWidget(self._widget)

        self._hierarchy_view.setModel(self._hierarchy_model)
        self._details_view.setModel(self._details_model)

        self._hierarchy_view.expanded.connect(self._mo_item_expand)

    def _init_data(self):
        item = self._row_for_mo(self._conn.resolve_dn(''))
        self._hierarchy_model.insertRow(0, item)

    def _init_connections(self):
        self.connect(self._resolver,
                        SIGNAL('object_resolved(QVariant)'),
                     self,
                        SLOT('_data_resolved(QVariant)'))
        self._hierarchy_view.activated.connect(self._item_activated)
        #self.connect(self._hierarchy_view.selectionModel(),
        #                SIGNAL('currentChanged(QModelIndex,QModelIndex)'),
        #             self,
        #                SLOT('_current_changed(QModelIndex, QModelIndex)'))
        self.connect(self._hierarchy_view.selectionModel(),
                        SIGNAL('activated(QModelIndex)'),
                     self,
                        SLOT('_item_activated(QModelIndex)'))


    def _row_for_mo(self, mo):
        row = [QStandardItem(mo.ucs_class), QStandardItem(mo.dn)]
        for item in row:
            item.setEditable(False)
        row[0].appendColumn([QStandardItem('Loading...')])
        row[0].setData(mo, self.MO_ROLE)
        return row

    def _add_mo_in_tree(self, mo, index=QtCore.QModelIndex()):
        item = None
        if index.isValid():
            item = self._hierarchy_model.itemFromIndex(index)
        else:
            item = self._get_item_for_dn(self._parent_dn(mo.dn))
        if item:
            item.appendColumn([self._row_for_mo(mo)[0]])
        self.auto_width()

    def _add_mos_in_tree(self, mos, index=QtCore.QModelIndex()):
        item = None
        if index.isValid():
            item = self._hierarchy_model.itemFromIndex(index)
        else:
            if not mos:
                return
            item = self._get_item_for_dn(self._parent_dn(mos[0].dn))
        while item.columnCount():
            item.removeColumn(0)
        items = map(self._row_for_mo, mos)
        if items:
            for x in xrange(len(items[0])):
                item.appendColumn([row[x] for row in items])
        self.auto_width()

    @staticmethod
    def _parent_dn(dn):
        parent_dn, _, rn = dn.rpartition('/')
        return parent_dn

    def _get_item_for_dn(self, dn):
        parent_dn = dn
        items = self._hierarchy_model.findItems(parent_dn, column=1)
        if items:
            return self._hierarchy_model.item(items[0].row())
        return None

    @QtCore.Slot('_data_resolved(QVariant)')
    def _data_resolved(self, datav):
        print 'Data resolved: ', datav
        index, data = datav
        if isinstance(data, UcsmObject):
            self._add_mo_in_tree(data, index=index)
        else:
            self._add_mos_in_tree(data, index=index)

    @QtCore.Slot('_current_changed(QModelIndex,QModelIndex)')
    def _current_changed(self, curr, prev):
        self._item_activated(curr)

    @QtCore.Slot('_item_activated(QModelIndex)')
    def _item_activated(self, index):
        print 'Activated: %s data %s' % (index, index.data(self.MO_ROLE))
        if index.sibling(0, 0).isValid():
            index = index.sibling(0, 0)
            data = index.data(self.MO_ROLE)
            self.set_detail_object(data)

    def _mo_item_expand(self, index):
        obj = index.data(self.MO_ROLE)
        print 'Expanded object: %s' % obj
        try:
            self._resolver.add_task(lambda: (index,
                                        self._conn.resolve_children(obj.dn)))
        except (KeyError, AttributeError):
            QtGui.QMessageBox.critical(0, 'Error', 'Object does not have dn')

    def auto_width(self):
        for view in [self._hierarchy_view, self._details_view]:
            for col in xrange(view.model().columnCount()):
                view.resizeColumnToContents(col)

    def set_detail_object(self, object):
        self._details_model.removeRows(0, self._details_model.rowCount())
        for k, v in object.attributes.iteritems():
            row = [QStandardItem(k), QStandardItem(v)]
            for item in row:
                item.setEditable(False)
            self._details_model.appendRow(row)
        self.auto_width()
예제 #5
0
class DialogLookup(QtGui.QDialog):
    def __init__(self, lookup):
        super().__init__()

        self._lookup = lookup
        self._model = QStandardItemModel()  # (4, 4)

        self.initUI()
        self.initDB()

    def initUI(self):
        global _compatible

        self.result = userCancelled

        # create our window
        # define window		xLoc,yLoc,xDim,yDim
        self.setGeometry(250, 250, 640, 480)
        self.setWindowTitle(translate('Rocket', "Component lookup..."))
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)

        searchLabel = QtGui.QLabel(translate('Rocket', "Search"), self)

        self._searchInput = QtGui.QLineEdit(self)
        self._searchInput.setFixedWidth(80)
        self._searchInput.textEdited.connect(self.onSearch)

        lookupTypeLabel = QtGui.QLabel(translate('Rocket', "Component"), self)

        self._lookupTypeCombo = QtGui.QComboBox(self)
        self._lookupTypeCombo.addItems(_compatible[self._lookup])
        self._lookupTypeCombo.setCurrentText(self._lookup)
        self._lookupTypeCombo.currentTextChanged.connect(self.onLookupType)

        self._dbTable = QtGui.QTableView(self)
        self._dbTable.setModel(self._model)
        self._dbTable.setSelectionBehavior(QtGui.QTableView.SelectRows)
        self._dbTable.setSelectionMode(QtGui.QTableView.SingleSelection)
        self._dbTable.setSortingEnabled(True)
        self._dbTable.doubleClicked.connect(self.onTableDoubleClick)

        # cancel button
        cancelButton = QtGui.QPushButton('Cancel', self)
        cancelButton.clicked.connect(self.onCancel)
        cancelButton.setAutoDefault(True)

        # OK button
        okButton = QtGui.QPushButton('OK', self)
        okButton.setDefault(True)
        okButton.clicked.connect(self.onOk)

        layout = QVBoxLayout()
        line = QHBoxLayout()
        line.addWidget(searchLabel)
        line.addWidget(self._searchInput)
        line.addStretch()
        line.addWidget(lookupTypeLabel)
        line.addWidget(self._lookupTypeCombo)
        layout.addLayout(line)

        layout.addWidget(self._dbTable)

        line = QHBoxLayout()
        line.addStretch()
        line.addWidget(okButton)
        line.addWidget(cancelButton)
        layout.addLayout(line)

        self.setLayout(layout)

        # now make the window visible
        self.show()

    def initDB(self):
        self._connection = sqlite3.connect(
            "file:" + FreeCAD.getUserAppDataDir() +
            "Mod/Rocket/Resources/parts/Parts.db?mode=ro",
            uri=True)
        self._connection.row_factory = sqlite3.Row
        self._updateModel()

    def onLookupType(self, value):
        self._updateModel()

    def onSearch(self, value):
        rows = []
        value = str(value).strip()
        if len(value) > 0:
            for column in range(self._model.columnCount()):
                items = self._model.findItems(value, Qt.MatchContains, column)
                for item in items:
                    row = item.row()
                    if not row in rows:
                        rows.append(row)

            for row in range(self._model.rowCount()):
                if row in rows:
                    self._dbTable.showRow(row)
                else:
                    self._dbTable.hideRow(row)
        else:
            for row in range(self._model.rowCount()):
                self._dbTable.showRow(row)

    def onTableDoubleClick(self, selected):
        self.result = self._getSelected(selected.row())
        self.close()

    def onCancel(self):
        self.result = {}
        self.close()

    def onOk(self):
        selected = self._dbTable.selectedIndexes()
        if len(selected) > 0:
            row = selected[0].row()
            self.result = self._getSelected(row)
        else:
            self.result = {}
        self.close()

    def _getSelectedBodyTube(self, row):
        try:
            index = int(self._model.item(row, 0).text())
            cone = getBodyTube(self._connection, index)
            return cone
        except NotFoundError:
            _err(translate('Rocket', "Body tube not found"))
        except MultipleEntryError:
            _err(translate('Rocket', "Multiple identical entries found"))
        return {}

    def _getSelectedNose(self, row):
        try:
            index = int(self._model.item(row, 0).text())
            cone = getNoseCone(self._connection, index)
            return cone
        except NotFoundError:
            _err(translate('Rocket', "Nose cone not found"))
        except MultipleEntryError:
            _err(translate('Rocket', "Multiple identical entries found"))
        return {}

    def _getSelectedTransition(self, row):
        try:
            index = int(self._model.item(row, 0).text())
            tran = getTransition(self._connection, index)
            return tran
        except NotFoundError:
            _err(translate('Rocket', "Transition not found"))
        except MultipleEntryError:
            _err(translate('Rocket', "Multiple identical entries found"))
        return {}

    def _getSelected(self, row):
        queryType = str(self._lookupTypeCombo.currentText())
        if queryType == COMPONENT_TYPE_ANY:
            query = self._lookup
        else:
            query = queryType

        if query in [
                COMPONENT_TYPE_BODYTUBE, COMPONENT_TYPE_COUPLER,
                COMPONENT_TYPE_ENGINEBLOCK, COMPONENT_TYPE_LAUNCHLUG,
                COMPONENT_TYPE_CENTERINGRING, COMPONENT_TYPE_BULKHEAD
        ]:
            return self._getSelectedBodyTube(row)
        elif query == COMPONENT_TYPE_NOSECONE:
            return self._getSelectedNose(row)
        elif query == COMPONENT_TYPE_TRANSITION:
            return self._getSelectedTransition(row)
        # elif query == COMPONENT_TYPE_PARACHUTE:
        #     pass
        # elif query == COMPONENT_TYPE_STREAMER:
        #     pass
        return {}

    def _itemWithDimension(self, value, dim):
        return self._newItem(_valueWithUnits(value, dim))

    def _newItem(self, text):
        item = QStandardItem(text)
        item.setEditable(False)
        return item

    def _queryBodyTube(self, queryType):
        rows = listBodyTubes(self._connection, queryType)

        self._model.setRowCount(len(rows))
        if queryType == COMPONENT_TYPE_BULKHEAD:
            self._model.setColumnCount(7)
        else:
            self._model.setColumnCount(8)
        self._dbTable.hideColumn(0)  # This holds index for lookups
        self._dbTable.setVerticalHeader(None)

        # Add the column headers
        self._model.setHorizontalHeaderItem(
            1, self._newItem(translate('Rocket', "Type")))
        self._model.setHorizontalHeaderItem(
            2, self._newItem(translate('Rocket', "Manufacturer")))
        self._model.setHorizontalHeaderItem(
            3, self._newItem(translate('Rocket', "Part Number")))
        self._model.setHorizontalHeaderItem(
            4, self._newItem(translate('Rocket', "Description")))
        self._model.setHorizontalHeaderItem(
            5, self._newItem(translate('Rocket', "Outer Diameter")))
        if queryType == COMPONENT_TYPE_BULKHEAD:
            self._model.setHorizontalHeaderItem(
                6, self._newItem(translate('Rocket', "Length")))
        else:
            self._model.setHorizontalHeaderItem(
                6, self._newItem(translate('Rocket', "Inner Diameter")))
            self._model.setHorizontalHeaderItem(
                7, self._newItem(translate('Rocket', "Length")))

        rowCount = 0
        for row in rows:
            self._model.setItem(rowCount, 0,
                                self._newItem(str(row["body_tube_index"])))
            self._model.setItem(rowCount, 1, self._newItem(str(row["type"])))
            self._model.setItem(rowCount, 2,
                                self._newItem(str(row["manufacturer"])))
            self._model.setItem(rowCount, 3,
                                self._newItem(str(row["part_number"])))
            self._model.setItem(rowCount, 4,
                                self._newItem(str(row["description"])))
            self._model.setItem(
                rowCount, 5,
                self._newItem(
                    self._itemWithDimension(row["outer_diameter"],
                                            row["outer_diameter_units"])))
            if queryType == COMPONENT_TYPE_BULKHEAD:
                self._model.setItem(
                    rowCount, 6,
                    self._newItem(
                        self._itemWithDimension(row["length"],
                                                row["length_units"])))
            else:
                self._model.setItem(
                    rowCount, 6,
                    self._newItem(
                        self._itemWithDimension(row["inner_diameter"],
                                                row["inner_diameter_units"])))
                self._model.setItem(
                    rowCount, 7,
                    self._newItem(
                        self._itemWithDimension(row["length"],
                                                row["length_units"])))

            rowCount += 1

    def _queryNoseCone(self):
        rows = listNoseCones(self._connection)

        self._model.setRowCount(len(rows))
        self._model.setColumnCount(9)
        self._dbTable.hideColumn(0)  # This holds index for lookups
        self._dbTable.setVerticalHeader(None)

        # Add the column headers
        self._model.setHorizontalHeaderItem(
            1, self._newItem(translate('Rocket', "Manufacturer")))
        self._model.setHorizontalHeaderItem(
            2, self._newItem(translate('Rocket', "Part Number")))
        self._model.setHorizontalHeaderItem(
            3, self._newItem(translate('Rocket', "Description")))
        self._model.setHorizontalHeaderItem(
            4, self._newItem(translate('Rocket', "Diameter")))
        self._model.setHorizontalHeaderItem(
            5, self._newItem(translate('Rocket', "Length")))
        self._model.setHorizontalHeaderItem(
            6, self._newItem(translate('Rocket', "Shoulder Diameter")))
        self._model.setHorizontalHeaderItem(
            7, self._newItem(translate('Rocket', "Shoulder Length")))
        self._model.setHorizontalHeaderItem(
            8, self._newItem(translate('Rocket', "Shape")))

        rowCount = 0
        for row in rows:
            self._model.setItem(rowCount, 0,
                                self._newItem(str(row["nose_index"])))
            self._model.setItem(rowCount, 1,
                                self._newItem(str(row["manufacturer"])))
            self._model.setItem(rowCount, 2,
                                self._newItem(str(row["part_number"])))
            self._model.setItem(rowCount, 3,
                                self._newItem(str(row["description"])))
            self._model.setItem(
                rowCount, 4,
                self._newItem(
                    self._itemWithDimension(row["diameter"],
                                            row["diameter_units"])))
            self._model.setItem(
                rowCount, 5,
                self._newItem(
                    self._itemWithDimension(row["length"],
                                            row["length_units"])))
            self._model.setItem(
                rowCount, 6,
                self._newItem(
                    self._itemWithDimension(row["shoulder_diameter"],
                                            row["shoulder_diameter_units"])))
            self._model.setItem(
                rowCount, 7,
                self._newItem(
                    self._itemWithDimension(row["shoulder_length"],
                                            row["shoulder_length_units"])))
            self._model.setItem(rowCount, 8, self._newItem(str(row["shape"])))

            rowCount += 1

    def _queryTransition(self):
        rows = listTransitions(self._connection)

        self._model.setRowCount(len(rows))
        self._model.setColumnCount(12)
        self._dbTable.hideColumn(0)  # This holds index for lookups
        self._dbTable.setVerticalHeader(None)

        # Add the column headers
        self._model.setHorizontalHeaderItem(
            1, self._newItem(translate('Rocket', "Manufacturer")))
        self._model.setHorizontalHeaderItem(
            2, self._newItem(translate('Rocket', "Part Number")))
        self._model.setHorizontalHeaderItem(
            3, self._newItem(translate('Rocket', "Description")))
        self._model.setHorizontalHeaderItem(
            4, self._newItem(translate('Rocket', "Fore Diameter")))
        self._model.setHorizontalHeaderItem(
            5, self._newItem(translate('Rocket', "Aft Diameter")))
        self._model.setHorizontalHeaderItem(
            6, self._newItem(translate('Rocket', "Length")))
        self._model.setHorizontalHeaderItem(
            7, self._newItem(translate('Rocket', "Fore Shoulder Diameter")))
        self._model.setHorizontalHeaderItem(
            8, self._newItem(translate('Rocket', "Fore Shoulder Length")))
        self._model.setHorizontalHeaderItem(
            9, self._newItem(translate('Rocket', "Aft Shoulder Diameter")))
        self._model.setHorizontalHeaderItem(
            10, self._newItem(translate('Rocket', "Aft Shoulder Length")))
        self._model.setHorizontalHeaderItem(
            11, self._newItem(translate('Rocket', "Shape")))

        rowCount = 0
        for row in rows:
            self._model.setItem(rowCount, 0,
                                self._newItem(str(row["transition_index"])))
            self._model.setItem(rowCount, 1,
                                self._newItem(str(row["manufacturer"])))
            self._model.setItem(rowCount, 2,
                                self._newItem(str(row["part_number"])))
            self._model.setItem(rowCount, 3,
                                self._newItem(str(row["description"])))
            self._model.setItem(
                rowCount, 4,
                self._newItem(
                    self._itemWithDimension(
                        row["fore_outside_diameter"],
                        row["fore_outside_diameter_units"])))
            self._model.setItem(
                rowCount, 5,
                self._newItem(
                    self._itemWithDimension(
                        row["aft_outside_diameter"],
                        row["aft_outside_diameter_units"])))
            self._model.setItem(
                rowCount, 6,
                self._newItem(
                    self._itemWithDimension(row["length"],
                                            row["length_units"])))
            self._model.setItem(
                rowCount, 7,
                self._newItem(
                    self._itemWithDimension(
                        row["fore_shoulder_diameter"],
                        row["fore_shoulder_diameter_units"])))
            self._model.setItem(
                rowCount, 8,
                self._newItem(
                    self._itemWithDimension(
                        row["fore_shoulder_length"],
                        row["fore_shoulder_length_units"])))
            self._model.setItem(
                rowCount, 9,
                self._newItem(
                    self._itemWithDimension(
                        row["aft_shoulder_diameter"],
                        row["aft_shoulder_diameter_units"])))
            self._model.setItem(
                rowCount, 10,
                self._newItem(
                    self._itemWithDimension(row["aft_shoulder_length"],
                                            row["aft_shoulder_length_units"])))
            self._model.setItem(rowCount, 11, self._newItem(str(row["shape"])))

            rowCount += 1

    def _updateModel(self):
        queryType = str(self._lookupTypeCombo.currentText())
        if queryType == COMPONENT_TYPE_ANY:
            query = self._lookup
        else:
            query = queryType

        if query in [
                COMPONENT_TYPE_BODYTUBE, COMPONENT_TYPE_COUPLER,
                COMPONENT_TYPE_ENGINEBLOCK, COMPONENT_TYPE_LAUNCHLUG,
                COMPONENT_TYPE_CENTERINGRING, COMPONENT_TYPE_BULKHEAD
        ]:
            self._queryBodyTube(queryType)
        elif query == COMPONENT_TYPE_NOSECONE:
            self._queryNoseCone()
        elif query == COMPONENT_TYPE_TRANSITION:
            self._queryTransition()
        # elif query == COMPONENT_TYPE_PARACHUTE:
        #     pass
        # elif query == COMPONENT_TYPE_STREAMER:
        #     pass

    def update(self):
        # Update the SQL query
        pass
예제 #6
0
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)