Esempio n. 1
0
class QDoublePushButton(QPushButton):
    """加入了双击事件的按钮"""
    doubleClicked = pyqtSignal()
    clicked = pyqtSignal()

    def __init__(self, *args, **kwargs):
        QPushButton.__init__(self, *args, **kwargs)
        self.timer = QTimer()
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.clicked.emit)
        super().clicked.connect(self.checkDoubleClick)

    def checkDoubleClick(self):
        if self.timer.isActive():
            self.doubleClicked.emit()
            self.timer.stop()
        else:
            self.timer.start(250)
Esempio n. 2
0
class WinForm(QWidget):
    def __init__(self, parent=None):
        super(WinForm, self).__init__(parent)
        self.setWindowTitle("QTimer demo")
        self.listFile = QListWidget()
        self.label = QLabel("显示当前时间")
        self.startButton = QPushButton("开始")
        self.endButton = QPushButton("结束")
        layout = QGridLayout(self)

        # 初始化定时器
        self.timer = QTimer(self)
        # 显示时间
        self.timer.timeout.connect(
            self.showTime)  # timeout 信号连接到特定的槽,当定时器超时,发出 timeout 信号

        layout.addWidget(self.label, 0, 0, 1, 2)
        layout.addWidget(self.startButton, 1, 0)
        layout.addWidget(self.endButton, 1, 1)

        self.startButton.clicked.connect(self.start_timer)
        self.endButton.clicked.connect(self.end_timer)

        self.setLayout(layout)

    def showTime(self):
        # 获取当前系统时间
        time = QDateTime.currentDateTime()
        # 设置时间格式
        timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.label.setText(timeDisplay)

    def start_timer(self):
        # 设置时间间隔并启动定时器
        self.timer.start(1000)  # start 内设置时间间隔,启动或重新启动计时器,如果计时器在运行,则重启
        self.startButton.setEnabled(False)
        self.endButton.setEnabled(True)

    def end_timer(self):
        self.timer.stop()  # 停止计时器
        self.startButton.setEnabled(True)
        self.endButton.setEnabled(False)
class ProgressBar(QProgressBar):
    def __init__(self, *args, **kwargs):
        super(ProgressBar, self).__init__(*args, **kwargs)
        self.setValue(0)
        if self.minimum() != self.maximum():
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.onTimeout)
            self.timer.start(100)

    def start(self):
        self.timer.start(100)

    def stop(self):
        self.timer.stop()

    def onTimeout(self):
        if self.value() >= 100:
            self.timer.stop()
            self.timer.deleteLater()
            del self.timer
            return
        self.setValue(self.value() + 1)
class ChangeKeyDialog(QDialog):
    def __init__(
        self,
        parent=None,
        buttons=None,
        exercises=None,
        index: int = None,
    ):
        super(ChangeKeyDialog, self).__init__(parent)
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        widget = QWidget()
        keyLayout = QVBoxLayout()
        widget.setStyleSheet("""
        QWidget{
            border-radius: 12px;
            border: 1px solid grey;
            background-color: #b5b5b5;
            color: white;
            font-size: 40px;
        }
        """)
        # widget.setFixedSize(100, 100)
        self.currentKeyLabel = QLabel('W')
        keyLayout.addWidget(self.currentKeyLabel)
        keyLayout.setAlignment(self.currentKeyLabel, Qt.Alignment.AlignCenter)
        widget.setLayout(keyLayout)

        label = QLabel("Press a key to swap")
        emptyKey = QPushButton('Use empty slot')
        emptyKey.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
        emptyKey.clicked.connect(self.useEmpty)

        acceptKey = QPushButton('Accept')
        acceptKey.clicked.connect(self.accept)
        acceptKey.setFocusPolicy(Qt.FocusPolicy.ClickFocus)

        layout.addWidget(label)
        layout.addWidget(widget)
        actions = QHBoxLayout()
        actions.addWidget(emptyKey)
        actions.addWidget(acceptKey)
        layout.addLayout(actions)
        layout.setAlignment(widget, Qt.Alignment.AlignCenter)
        self.buttons = buttons
        self.exercises = exercises
        self.index = index

        self.monitor = KeyMonitor()
        self.monitor.start_monitoring()
        self.currentKey = self.monitor.currentKey

        self.timer = QTimer()
        self.timer.timeout.connect(self.onTimeout)
        self.timer.start()
        print("Dialog init done!")

    def accept(self):
        currentKeyScheme = [e.assigned_key for e in self.exercises]
        print(self.exercises[self.index].assigned_key)

        # Check if pressed key is among
        if self.currentKey in currentKeyScheme:
            for name, key in SUPPORTED_KEYS.items(
            ):  # for name, age in dictionary.iteritems():  (for Python 2.x)
                if key == self.currentKey:
                    old_exercise = None
                    old_button = None
                    for exercise, button in zip(self.exercises, self.buttons):
                        if exercise.assigned_key == (
                                name, key) and button.text() == name:
                            old_exercise = exercise
                            old_button = button

                    # Set new keys and labels
                    if old_exercise is not None and old_button is not None:
                        self.exercises[
                            self.index].assigned_key, old_exercise.assigned_key = old_exercise.assigned_key, \
                                                                                  self.exercises[
                                                                                      self.index].assigned_key
                        old_label = old_button.text()
                        old_button.setText(self.buttons[self.index].text())
                        self.buttons[self.index].setText(old_label)
                        print("old key:", old_exercise.assigned_key)
                        print("new key:",
                              self.exercises[self.index].assigned_key)
                        self.timer.stop()
                        self.close()
        else:
            self.exercises[self.index].assigned_key = self.currentKey
            print(
                "pos:",
                list(SUPPORTED_KEYS.keys())[list(
                    SUPPORTED_KEYS.values()).index(self.currentKey[1])])
            self.buttons[self.index].setText(
                list(SUPPORTED_KEYS.keys())[list(
                    SUPPORTED_KEYS.values()).index(self.currentKey[1])])
            self.timer.stop()
            self.close()

    def useEmpty(self):
        self.currentKey = ("Empty", None)
        self.exercises[self.index].assigned_key = self.currentKey
        self.buttons[self.index].setText(self.currentKey[0])
        self.timer.stop()
        self.close()

    def onTimeout(self):
        if self.monitor is not None:
            if self.monitor.currentKey in list(SUPPORTED_KEYS.values()):
                if type(self.monitor.currentKey) is KeyCode:
                    self.currentKeyLabel.setText(self.monitor.currentKey.char)
                else:
                    self.currentKeyLabel.setText(str(self.monitor.currentKey))
                name = list(SUPPORTED_KEYS.keys())[list(
                    SUPPORTED_KEYS.values()).index(self.monitor.currentKey)]
                self.currentKey = (name, self.monitor.currentKey)

    def writeExerciseKeyMap(self):
        with open(os.getcwd() + MAPPED_KEYS_PATH + self.subject + '.json',
                  'w') as fp:
            json.dump(self.exercises, fp)

    # static method to create the dialog and return (date, time, accepted)
    @staticmethod
    def getSwapper(parent=None):
        dialog = ChangeKeyDialog(parent)
        result = dialog.exec()
        return result == QDialog.DialogCode.Accepted
Esempio n. 5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupTrayicon()
        self.setupVariables()
        self.setupUi()
        self.setupConnections()
        self.show()

    def setupVariables(self):
        settings = QSettings()
        self.workEndTime = QTime(
            int(settings.value(workHoursKey, 0)),
            int(settings.value(workMinutesKey, 25)),
            int(settings.value(workSecondsKey, 0)),
        )
        self.restEndTime = QTime(
            int(settings.value(restHoursKey, 0)),
            int(settings.value(restMinutesKey, 5)),
            int(settings.value(restSecondsKey, 0)),
        )
        self.timeFormat = "hh:mm:ss"
        self.time = QTime(0, 0, 0, 0)
        self.workTime = QTime(0, 0, 0, 0)
        self.restTime = QTime(0, 0, 0, 0)
        self.totalTime = QTime(0, 0, 0, 0)
        self.currentMode = Mode.work
        self.maxRepetitions = -1
        self.currentRepetitions = 0

    def setupConnections(self):
        """ Create button connections """
        self.startButton.clicked.connect(self.startTimer)
        self.startButton.clicked.connect(
            lambda: self.startButton.setDisabled(True))
        self.startButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(False))
        self.startButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(self.pauseTimer)
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.pauseButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setText("continue"))
        self.resetButton.clicked.connect(self.resetTimer)
        self.resetButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.resetButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.resetButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.startButton.setText("start"))
        self.acceptTaskButton.pressed.connect(self.insertTask)
        self.deleteTaskButton.pressed.connect(self.deleteTask)
        """ Create spinbox  connections """
        self.workHoursSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workMinutesSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workSecondsSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.restHoursSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restMinutesSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restSecondsSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.repetitionsSpinBox.valueChanged.connect(self.updateMaxRepetitions)
        """ Create combobox connections """
        self.modeComboBox.currentTextChanged.connect(self.updateCurrentMode)
        """ Create tablewidget connections """
        self.tasksTableWidget.cellDoubleClicked.connect(
            self.markTaskAsFinished)

    def setupUi(self):
        self.size_policy = QSizePolicy(QSizePolicy.Policy.Expanding,
                                       QSizePolicy.Policy.Expanding)
        """ Create tabwidget """
        self.tabWidget = QTabWidget()
        """ Create tab widgets """
        timerWidget = self.setupTimerTab()
        tasksWidget = self.setupTasksTab()
        statisticsWidget = self.setupStatisticsTab()
        """ add tab widgets to tabwidget"""
        self.timerTab = self.tabWidget.addTab(timerWidget, makeIcon("timer"),
                                              "Timer")
        self.tasksTab = self.tabWidget.addTab(tasksWidget, makeIcon("tasks"),
                                              "Tasks")
        self.statisticsTab = self.tabWidget.addTab(statisticsWidget,
                                                   makeIcon("statistics"),
                                                   "Statistics")
        """ Set mainwindows central widget """
        self.setCentralWidget(self.tabWidget)

    def setupTimerTab(self):
        settings = QSettings()
        self.timerContainer = QWidget(self)
        self.timerContainerLayout = QVBoxLayout(self.timerContainer)
        self.timerContainer.setLayout(self.timerContainerLayout)
        """ Create work groupbox"""
        self.workGroupBox = QGroupBox("Work")
        self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox)
        self.workGroupBox.setLayout(self.workGroupBoxLayout)
        self.workHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(workHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.workMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workMinutesKey, 25)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.workSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        """ Create rest groupbox"""
        self.restGroupBox = QGroupBox("Rest")
        self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox)
        self.restGroupBox.setLayout(self.restGroupBoxLayout)
        self.restHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(restHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.restMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restMinutesKey, 5)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.restSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        self.restGroupBoxLayout.addWidget(self.restHoursSpinBox)
        self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox)
        self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox)
        """ Create other groupbox"""
        self.otherGroupBox = QGroupBox("Other")
        self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox)
        self.otherGroupBox.setLayout(self.otherGroupBoxLayout)
        self.repetitionsLabel = QLabel("Repetitions")
        self.repetitionsSpinBox = QSpinBox(
            minimum=0,
            maximum=10000,
            value=0,
            sizePolicy=self.size_policy,
            specialValueText="∞",
        )
        self.modeLabel = QLabel("Mode")
        self.modeComboBox = QComboBox(sizePolicy=self.size_policy)
        self.modeComboBox.addItems(["work", "rest"])
        self.otherGroupBoxLayout.addWidget(self.repetitionsLabel)
        self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox)
        self.otherGroupBoxLayout.addWidget(self.modeLabel)
        self.otherGroupBoxLayout.addWidget(self.modeComboBox)
        """ Create timer groupbox"""
        self.lcdDisplayGroupBox = QGroupBox("Time")
        self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox)
        self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout)
        self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy)
        self.timeDisplay.setFixedHeight(100)
        self.timeDisplay.display("00:00:00")
        self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay)
        """ Create pause, start and reset buttons"""
        self.buttonContainer = QWidget()
        self.buttonContainerLayout = QHBoxLayout(self.buttonContainer)
        self.buttonContainer.setLayout(self.buttonContainerLayout)
        self.startButton = self.makeButton("start", disabled=False)
        self.resetButton = self.makeButton("reset")
        self.pauseButton = self.makeButton("pause")
        """ Add widgets to container """
        self.workGroupBoxLayout.addWidget(self.workHoursSpinBox)
        self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox)
        self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox)
        self.timerContainerLayout.addWidget(self.workGroupBox)
        self.timerContainerLayout.addWidget(self.restGroupBox)
        self.timerContainerLayout.addWidget(self.otherGroupBox)
        self.timerContainerLayout.addWidget(self.lcdDisplayGroupBox)
        self.buttonContainerLayout.addWidget(self.pauseButton)
        self.buttonContainerLayout.addWidget(self.startButton)
        self.buttonContainerLayout.addWidget(self.resetButton)
        self.timerContainerLayout.addWidget(self.buttonContainer)
        return self.timerContainer

    def setupTasksTab(self):
        settings = QSettings()
        """ Create vertical tasks container """
        self.tasksWidget = QWidget(self.tabWidget)
        self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget)
        self.tasksWidget.setLayout(self.tasksWidgetLayout)
        """ Create horizontal input container """
        self.inputContainer = QWidget()
        self.inputContainer.setFixedHeight(50)
        self.inputContainerLayout = QHBoxLayout(self.inputContainer)
        self.inputContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputContainer.setLayout(self.inputContainerLayout)
        """ Create text edit """
        self.taskTextEdit = QTextEdit(
            placeholderText="Describe your task briefly.",
            undoRedoEnabled=True)
        """ Create vertical buttons container """
        self.inputButtonContainer = QWidget()
        self.inputButtonContainerLayout = QVBoxLayout(
            self.inputButtonContainer)
        self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputButtonContainer.setLayout(self.inputButtonContainerLayout)
        """ Create buttons """
        self.acceptTaskButton = QToolButton(icon=makeIcon("check"))
        self.deleteTaskButton = QToolButton(icon=makeIcon("trash"))
        """ Create tasks tablewidget """
        self.tasksTableWidget = QTableWidget(0, 1)
        self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"])
        self.tasksTableWidget.horizontalHeader().setStretchLastSection(True)
        self.tasksTableWidget.verticalHeader().setVisible(False)
        self.tasksTableWidget.setWordWrap(True)
        self.tasksTableWidget.setTextElideMode(Qt.TextElideMode.ElideNone)
        self.tasksTableWidget.setEditTriggers(
            QAbstractItemView.EditTriggers.NoEditTriggers)
        self.tasksTableWidget.setSelectionMode(
            QAbstractItemView.SelectionMode.SingleSelection)
        self.insertTasks(*settings.value(tasksKey, []))
        """ Add widgets to container widgets """
        self.inputButtonContainerLayout.addWidget(self.acceptTaskButton)
        self.inputButtonContainerLayout.addWidget(self.deleteTaskButton)
        self.inputContainerLayout.addWidget(self.taskTextEdit)
        self.inputContainerLayout.addWidget(self.inputButtonContainer)
        self.tasksWidgetLayout.addWidget(self.inputContainer)
        self.tasksWidgetLayout.addWidget(self.tasksTableWidget)
        return self.tasksWidget

    def setupStatisticsTab(self):
        """ Create statistics container """
        self.statisticsContainer = QWidget()
        self.statisticsContainerLayout = QVBoxLayout(self.statisticsContainer)
        self.statisticsContainer.setLayout(self.statisticsContainerLayout)
        """ Create work time groupbox """
        self.statisticsWorkTimeGroupBox = QGroupBox("Work Time")
        self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsWorkTimeGroupBox.setLayout(
            self.statisticsWorkTimeGroupBoxLayout)
        self.statisticsWorkTimeDisplay = QLCDNumber(8)
        self.statisticsWorkTimeDisplay.display("00:00:00")
        self.statisticsWorkTimeGroupBoxLayout.addWidget(
            self.statisticsWorkTimeDisplay)
        """ Create rest time groupbox """
        self.statisticsRestTimeGroupBox = QGroupBox("Rest Time")
        self.statisticsRestTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsRestTimeGroupBox.setLayout(
            self.statisticsRestTimeGroupBoxLayout)
        self.statisticsRestTimeDisplay = QLCDNumber(8)
        self.statisticsRestTimeDisplay.display("00:00:00")
        self.statisticsRestTimeGroupBoxLayout.addWidget(
            self.statisticsRestTimeDisplay)
        """ Create total time groupbox """
        self.statisticsTotalTimeGroupBox = QGroupBox("Total Time")
        self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsTotalTimeGroupBox.setLayout(
            self.statisticsTotalTimeGroupBoxLayout)
        self.statisticsTotalTimeDisplay = QLCDNumber(8)
        self.statisticsTotalTimeDisplay.display("00:00:00")
        self.statisticsTotalTimeGroupBoxLayout.addWidget(
            self.statisticsTotalTimeDisplay)
        """ Add widgets to container """
        self.statisticsContainerLayout.addWidget(
            self.statisticsTotalTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsWorkTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsRestTimeGroupBox)
        return self.statisticsContainer

    def setupTrayicon(self):
        self.trayIcon = QSystemTrayIcon(makeIcon("tomato"))
        self.trayIcon.setContextMenu(QMenu())
        self.quitAction = self.trayIcon.contextMenu().addAction(
            makeIcon("exit"), "Quit", self.exit)
        self.quitAction.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onActivate)
        self.trayIcon.show()
        self.trayIcon.setToolTip("Pomodoro")
        self.toast = ToastNotifier()

    def leaveEvent(self, event):
        super(MainWindow, self).leaveEvent(event)
        self.tasksTableWidget.clearSelection()

    def closeEvent(self, event):
        super(MainWindow, self).closeEvent(event)
        settings = QSettings()
        settings.setValue(workHoursKey, self.workHoursSpinBox.value())
        settings.setValue(
            workMinutesKey,
            self.workMinutesSpinBox.value(),
        )
        settings.setValue(
            workSecondsKey,
            self.workSecondsSpinBox.value(),
        )
        settings.setValue(restHoursKey, self.restHoursSpinBox.value())
        settings.setValue(
            restMinutesKey,
            self.restMinutesSpinBox.value(),
        )
        settings.setValue(
            restSecondsKey,
            self.restSecondsSpinBox.value(),
        )

        tasks = []
        for i in range(self.tasksTableWidget.rowCount()):
            item = self.tasksTableWidget.item(i, 0)
            if not item.font().strikeOut():
                tasks.append(item.text())
        settings.setValue(tasksKey, tasks)

    def startTimer(self):
        try:
            if not self.timer.isActive():
                self.createTimer()
        except:
            self.createTimer()

    def createTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.timeout.connect(self.maybeChangeMode)
        self.timer.setInterval(1000)
        self.timer.setSingleShot(False)
        self.timer.start()

    def pauseTimer(self):
        try:
            self.timer.stop()
            self.timer.disconnect()
        except:
            pass

    def resetTimer(self):
        try:
            self.pauseTimer()
            self.time = QTime(0, 0, 0, 0)
            self.displayTime()
        except:
            pass

    def maybeStartTimer(self):
        if self.currentRepetitions != self.maxRepetitions:
            self.startTimer()
            started = True
        else:
            self.currentRepetitions = 0
            started = False
        return started

    def updateWorkEndTime(self):
        self.workEndTime = QTime(
            self.workHoursSpinBox.value(),
            self.workMinutesSpinBox.value(),
            self.workSecondsSpinBox.value(),
        )

    def updateRestEndTime(self):
        self.restEndTime = QTime(
            self.restHoursSpinBox.value(),
            self.restMinutesSpinBox.value(),
            self.restSecondsSpinBox.value(),
        )

    def updateCurrentMode(self, mode: str):
        self.currentMode = Mode.work if mode == "work" else Mode.rest

    def updateTime(self):
        self.time = self.time.addSecs(1)
        self.totalTime = self.totalTime.addSecs(1)
        if self.modeComboBox.currentText() == "work":
            self.workTime = self.workTime.addSecs(1)
        else:
            self.restTime = self.restTime.addSecs(1)
        self.displayTime()

    def updateMaxRepetitions(self, value):
        if value == 0:
            self.currentRepetitions = 0
            self.maxRepetitions = -1
        else:
            self.maxRepetitions = 2 * value

    def maybeChangeMode(self):
        if self.currentMode is Mode.work and self.time >= self.workEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(1)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.workFinished if started else Status.repetitionsReached)
            if not started:
                self.resetButton.click()
        elif self.currentMode is Mode.rest and self.time >= self.restEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(0)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.restFinished if started else Status.repetitionsReached)
            if not started:
                self.resetButton.click()

    def incrementCurrentRepetitions(self):
        if self.maxRepetitions > 0:
            self.currentRepetitions += 1

    def insertTask(self):
        task = self.taskTextEdit.toPlainText()
        self.insertTasks(task)

    def insertTasks(self, *tasks):
        for task in tasks:
            if task:
                rowCount = self.tasksTableWidget.rowCount()
                self.tasksTableWidget.setRowCount(rowCount + 1)
                self.tasksTableWidget.setItem(rowCount, 0,
                                              QTableWidgetItem(task))
                self.tasksTableWidget.resizeRowsToContents()
                self.taskTextEdit.clear()

    def deleteTask(self):
        selectedIndexes = self.tasksTableWidget.selectedIndexes()
        if selectedIndexes:
            self.tasksTableWidget.removeRow(selectedIndexes[0].row())

    def markTaskAsFinished(self, row, col):
        item = self.tasksTableWidget.item(row, col)
        font = self.tasksTableWidget.item(row, col).font()
        font.setStrikeOut(False if item.font().strikeOut() else True)
        item.setFont(font)

    def displayTime(self):
        self.timeDisplay.display(self.time.toString(self.timeFormat))
        self.statisticsRestTimeDisplay.display(
            self.restTime.toString(self.timeFormat))
        self.statisticsWorkTimeDisplay.display(
            self.workTime.toString(self.timeFormat))
        self.statisticsTotalTimeDisplay.display(
            self.totalTime.toString(self.timeFormat))

    def showWindowMessage(self, status):
        if status is Status.workFinished:
            title, text = "Break", choice(work_finished_phrases)
        elif status is Status.restFinished:
            title, text = "Work", choice(rest_finished_phrases)
        else:
            title, text = "Finished", choice(work_finished_phrases)
        self.trayIcon.showMessage(title, text, makeIcon("tomato"))
        self.toast.show_toast(title,
                              text,
                              icon_path="pomodoro/data/icons/tomato.ico",
                              duration=10,
                              threaded=True)

    def makeButton(self, text, iconName=None, disabled=True):
        button = QPushButton(text, sizePolicy=self.size_policy)
        if iconName:
            button.setIcon(makeIcon(iconName))
        button.setDisabled(disabled)
        return button

    def exit(self):
        self.close()
        app = QApplication.instance()
        if app:
            app.quit()

    def onActivate(self, reason):
        if reason == QSystemTrayIcon.ActivationReason.Trigger:
            self.show()
Esempio n. 6
0
class HttpRequestData(QObject):

    # Add some tolerance for scheduling the QTimer to check for timeouts, because the QTimer may trigger the event a
    # little earlier. For example, with a 5000ms interval, the timer event can be triggered after 4752ms, so a request
    # may never timeout if we don't add some tolerance.
    # 4752ms (actual) and 5000ms (expected) has about 6% difference, so here I use 15% to be safer.
    TIMEOUT_CHECK_TOLERANCE = 0.15

    def __init__(self,
                 request_id: str,
                 http_method: str,
                 request: "QNetworkRequest",
                 manager_timeout_callback: Callable[["HttpRequestData"], None],
                 data: Optional[Union[bytes, bytearray]] = None,
                 callback: Optional[Callable[["QNetworkReply"], None]] = None,
                 error_callback: Optional[
                     Callable[["QNetworkReply", "QNetworkReply.NetworkError"],
                              None]] = None,
                 download_progress_callback: Optional[Callable[[int, int],
                                                               None]] = None,
                 upload_progress_callback: Optional[Callable[[int, int],
                                                             None]] = None,
                 timeout: Optional[float] = None,
                 reply: Optional["QNetworkReply"] = None,
                 parent: Optional["QObject"] = None) -> None:
        super().__init__(parent=parent)

        # Sanity checks
        if timeout is not None and timeout <= 0:
            raise ValueError(
                "Timeout must be a positive value, but got [%s] instead." %
                timeout)

        self._request_id = request_id
        self.http_method = http_method
        self.request = request
        self.data = data
        self.callback = callback
        self.error_callback = error_callback
        self.download_progress_callback = download_progress_callback
        self.upload_progress_callback = upload_progress_callback
        self._timeout = timeout
        self.reply = reply

        # For benchmarking. For calculating the time a request spent pending.
        self._create_time = time.time()

        # The timestamp when this request was initially issued to the QNetworkManager. This field to used to track and
        # manage timeouts (if set) for the requests.
        self._start_time = None  # type: Optional[float]
        self.is_aborted_due_to_timeout = False

        self._last_response_time = float(0)
        self._timeout_timer = QTimer(parent=self)
        if self._timeout is not None:
            self._timeout_timer.setSingleShot(True)
            timeout_check_interval = int(self._timeout * 1000 *
                                         (1 + self.TIMEOUT_CHECK_TOLERANCE))
            self._timeout_timer.setInterval(timeout_check_interval)
            self._timeout_timer.timeout.connect(self._onTimeoutTimerTriggered)

        self._manager_timeout_callback = manager_timeout_callback

    @property
    def request_id(self) -> str:
        return self._request_id

    @property
    def timeout(self) -> Optional[float]:
        return self._timeout

    @property
    def start_time(self) -> Optional[float]:
        return self._start_time

    # For benchmarking. Time in seconds that this request stayed in the pending queue.
    @property
    def pending_time(self) -> Optional[float]:
        if self._start_time is None:
            return None
        return self._start_time - self._create_time

    # Sets the start time of this request. This is called when this request is issued to the QNetworkManager.
    def setStartTime(self, start_time: float) -> None:
        self._start_time = start_time

        # Prepare timeout handling
        if self._timeout is not None:
            self._last_response_time = start_time
            self._timeout_timer.start()

    # Do some cleanup, such as stopping the timeout timer.
    def setDone(self) -> None:
        if self._timeout is not None:
            self._timeout_timer.stop()
            self._timeout_timer.timeout.disconnect(
                self._onTimeoutTimerTriggered)

    # Since Qt 5.12, pyqtSignal().connect() will return a Connection instance that represents a connection. This
    # Connection instance can later be used to disconnect for cleanup purpose. We are using Qt 5.10 and this feature
    # is not available yet, and I'm not sure if disconnecting a lambda can potentially cause issues. For this reason,
    # I'm using the following facade callback functions to handle the lambda function cases.

    def onDownloadProgressCallback(self, bytes_received: int,
                                   bytes_total: int) -> None:
        # Update info for timeout handling
        if self._timeout is not None:
            now = time.time()
            time_last = now - self._last_response_time
            self._last_response_time = time.time()
            # We've got a response, restart the timeout timer
            self._timeout_timer.start()

        if self.download_progress_callback is not None:
            self.download_progress_callback(bytes_received, bytes_total)

    def onUploadProgressCallback(self, bytes_sent: int,
                                 bytes_total: int) -> None:
        # Update info for timeout handling
        if self._timeout is not None:
            now = time.time()
            time_last = now - self._last_response_time
            self._last_response_time = time.time()
            # We've got a response, restart the timeout timer
            self._timeout_timer.start()

        if self.upload_progress_callback is not None:
            self.upload_progress_callback(bytes_sent, bytes_total)

    def _onTimeoutTimerTriggered(self) -> None:
        # Make typing happy
        if self._timeout is None:
            return
        if self.reply is None:
            return

        now = time.time()
        time_last = now - self._last_response_time
        if self.reply.isRunning() and time_last >= self._timeout:
            self._manager_timeout_callback(self)
        else:
            self._timeout_timer.start()

    def __str__(self) -> str:
        data = "no-data"
        if self.data:
            data = str(self.data[:10])
            if len(self.data) > 10:
                data += "..."

        return "request[{id}][{method}][{url}][timeout={timeout}][{data}]".format(
            id=self._request_id[:8],
            method=self.http_method,
            url=self.request.url(),
            timeout=self._timeout,
            data=data)
class Window(QMainWindow):

    # The following attributes are dynamically loaded from the .ui file
    startButton: QPushButton
    stopButton: QPushButton
    leftEyeThreshold: QSlider
    rightEyeThreshold: QSlider

    def __init__(self, video_source: FrameSource, capture: Capture):
        super(Window, self).__init__()
        loadUi(settings.GUI_FILE_PATH, self)
        with open(settings.STYLE_FILE_PATH, "r") as css:
            self.setStyleSheet(css.read())

        self.startButton.clicked.connect(self.start)
        self.stopButton.clicked.connect(self.stop)
        self.timer = None
        self.video_source = video_source
        self.capture = capture

    def start(self):
        self.video_source.start()
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(settings.REFRESH_PERIOD)

    def stop(self):
        self.timer.stop()
        self.video_source.stop()

    def update_frame(self):
        frame = self.video_source.next_frame()
        face, l_eye, r_eye = self.capture.process(
            frame, self.leftEyeThreshold.value(),
            self.rightEyeThreshold.value())

        if face is not None:
            self.display_image(self.opencv_to_qt(frame))

        if l_eye is not None:
            self.display_image(self.opencv_to_qt(l_eye), window="leftEyeBox")

        if r_eye is not None:
            self.display_image(self.opencv_to_qt(r_eye), window="rightEyeBox")

    @staticmethod
    def opencv_to_qt(img) -> QImage:
        """
        Convert OpenCV image to PyQT image
        by changing format to RGB/RGBA from BGR
        """
        qformat = QImage.Format.Format_Indexed8
        if len(img.shape) == 3:
            if img.shape[2] == 4:  # RGBA
                qformat = QImage.Format.Format_RGBA8888
            else:  # RGB
                qformat = QImage.Format.Format_RGB888

        img = numpy.require(img, numpy.uint8, "C")
        out_image = QImage(img, img.shape[1], img.shape[0], img.strides[0],
                           qformat)  # BGR to RGB
        out_image = out_image.rgbSwapped()

        return out_image

    def display_image(self, img: QImage, window="baseImage"):
        """
        Display the image on a window - which is a label specified in the GUI .ui file
        """

        display_label: QLabel = getattr(self, window, None)
        if display_label is None:
            raise ValueError(f"No such display window in GUI: {window}")

        display_label.setPixmap(QPixmap.fromImage(img))
        display_label.setScaledContents(True)
Esempio n. 8
0
class MPSM2PrintJobOutputModel(PrintJobOutputModel):
    """Print Job Output Model."""
    def __init__(self, output_controller: PrinterOutputController) -> None:
        """Constructor.

    Args:
      output_controller: Printer's output controller.
    """
        super().__init__(output_controller=output_controller, key='', name='')
        self._state = 'not_started'
        self._progress = 0  # type: int
        self._elapsed_print_time_millis = 0  # type: int
        self._elapsed_percentage_points = None  # type: Optional[int]
        # Estimated printing time left, in seconds.
        self._remaining_print_time_secs = _MAX_REMAINING_TIME_SECS
        self._stopwatch = QTimer(self)
        self._stopwatch.timeout.connect(self._tick)
        self._reset()

    @pyqtProperty(int)
    def progress(self) -> int:
        """UI label for printing progress.

    Superclass computes progress based on elapsed time.
    MPSM2 printers do not provide elapsed time, but progress in percentage.

    Returns:
      Print job progress from 0 to 100.
    """
        return self._progress

    @pyqtProperty(str)
    def estimated_time_left(self) -> str:
        """UI label for estimated time left.

    Returns:
       Human-readable estimated printing time left.
    """
        if self._elapsed_percentage_points is None:
            return ''
        if self._elapsed_percentage_points < _MIN_PERCENT_POINTS:
            return ''
        return TimeUtils.get_human_readable_countdown(
            seconds=self._remaining_print_time_secs)

    def update_progress(self, progress: int) -> None:
        """Updates job progress and calculates estimated printing time left.

    Args:
      progress: Job progress from 0 to 100.
    """
        if progress < 0 or progress > 100:
            raise ValueError(f'Invalid printing progress: {progress}.')
        if progress == 0:
            self._reset()
        elif self._progress != progress:
            if self._elapsed_percentage_points is None:
                # Skip first seen percent point.
                self._elapsed_percentage_points = 0
            elif self._elapsed_percentage_points == 0:
                self._elapsed_percentage_points += 1
                if not self._stopwatch.isActive():
                    # New percent point seen. Start measuring.
                    self._stopwatch.start(_POLL_INTERVAL_MILLIS)
            else:
                self._remaining_print_time_secs = self._calculate_remaining_print_time(
                )
                self._elapsed_percentage_points += 1
        self._progress = progress

    def _reset(self) -> None:
        """Resets variables to calculate estimated print time left."""
        self._elapsed_print_time_millis = 0
        self._elapsed_percentage_points = None
        self._remaining_print_time_secs = _MAX_REMAINING_TIME_SECS
        if self._stopwatch.isActive():
            self._stopwatch.stop()

    def _calculate_remaining_print_time(self) -> int:
        """Calculates remaining print time.

    Calculation is based on the printing time and progress so far.

    Returns
      Remaining print time in seconds.
    """
        return int((100 - self._progress) * self._elapsed_print_time_millis /
                   self._elapsed_percentage_points / 1000)

    def _tick(self) -> None:
        """Updates stopwatch."""
        self._elapsed_print_time_millis += _POLL_INTERVAL_MILLIS
Esempio n. 9
0
class PrintJobUploadProgressMessage(Message):
    """Message displayed when a print upload is in progress."""

    MIN_CALCULATION_TIME_MILLIS = 5000
    POLL_TIME_MILLIS = 10
    MAX_REMAINING_MILLIS = 24 * 60 * 60 * 1000  # arbitrary max
    CALCULATING_TEXT = I18N_CATALOG.i18nc('@info:status',
                                          'Calculating time left...')

    def __init__(self, on_cancelled: Callable) -> None:
        """Constructor.

    Args:
      on_cancelled: Called when user cancels printer upload.
    """
        super().__init__(title=I18N_CATALOG.i18nc(
            '@info:status', 'Uploading model to printer'),
                         text=self.CALCULATING_TEXT,
                         progress=-1,
                         lifetime=0,
                         dismissable=False,
                         use_inactivity_timer=False)
        self._on_cancelled = on_cancelled
        self._elapsed_upload_time_millis = 0
        self._remaining_time_millis = self.MAX_REMAINING_MILLIS
        self.addAction('cancel', I18N_CATALOG.i18nc('@action:button',
                                                    'Cancel'), 'cancel',
                       I18N_CATALOG.i18nc('@action', 'Cancels job upload.'))
        self.actionTriggered.connect(self._on_action_triggered)
        self._stopwatch = QTimer(self)
        self._stopwatch.timeout.connect(self._tick)
        self._reset_calculation_time()

    def show(self) -> None:
        """See base class."""
        self.setProgress(0)
        super().show()
        self._stopwatch.start(self.POLL_TIME_MILLIS)
        self._reset_calculation_time()

    def hide(self, send_signal=True) -> None:
        """See base class."""
        super().hide()
        self._stopwatch.stop()
        self._reset_calculation_time()

    def update(self, bytes_sent: int, bytes_total: int) -> None:
        """Updates the progress bar.

    Args:
      bytes_sent: Number of bytes sent.
      bytes_total: Target bytes.
    """
        percentage = (bytes_sent / bytes_total) if bytes_total else 0
        self.setProgress(percentage * 100)
        if self._elapsed_upload_time_millis > self.MIN_CALCULATION_TIME_MILLIS:
            speed = bytes_sent / self._elapsed_upload_time_millis
            remaining_millis = (bytes_total -
                                bytes_sent) / speed if speed else 0
            # Only go down.
            if remaining_millis < self._remaining_time_millis:
                self._remaining_time_millis = remaining_millis
                self.setText(
                    TimeUtils.get_human_readable_countdown(
                        seconds=int(remaining_millis / 1000)))

    def _reset_calculation_time(self) -> None:
        """Resets the estimated calculation time."""
        self._elapsed_upload_time_millis = 0
        self._remaining_time_millis = self.MAX_REMAINING_MILLIS
        self.setText(self.CALCULATING_TEXT)

    def _on_action_triggered(self, message: str, action: str) -> None:
        """Called when an action from user was triggered.

    Args:
      message: Message (ignored).
      action: Action triggered.
    """
        if action == 'cancel':
            self._on_cancelled()

    def _tick(self) -> None:
        """Updates stopwatch."""
        self._elapsed_upload_time_millis += self.POLL_TIME_MILLIS