Exemple #1
0
class SyncWidget(QWidget):
    def __init__(self, gui, do_user_config, selected_book_ids,
                 is_sync_selected):
        QWidget.__init__(self, gui)

        api.build_request('/limits')

        self.logger = Logger(
            path.join(gui.current_db.library_path, 'bookfusion_sync.log'))
        self.logger.info(
            'Open sync dialog: selected_book_ids={}; is_sync_selected={}'.
            format(selected_book_ids, is_sync_selected))

        if len(selected_book_ids) == 0:
            is_sync_selected = False

        self.worker_thread = None

        self.do_user_config = do_user_config
        self.db = gui.current_db.new_api

        self.selected_book_ids = selected_book_ids

        self.l = QVBoxLayout()
        self.l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.l)

        self.radio_layout = QVBoxLayout()
        self.l.addLayout(self.radio_layout)

        self.sync_all_radio = QRadioButton('Sync all books')
        self.sync_all_radio.setChecked(not is_sync_selected)
        self.radio_layout.addWidget(self.sync_all_radio)

        sync_selected_radio_label = 'Sync selected books'
        if len(selected_book_ids) > 0:
            sync_selected_radio_label = 'Sync {} selected {}'.format(
                len(selected_book_ids),
                'book' if len(selected_book_ids) == 1 else 'books')
        self.sync_selected_radio = QRadioButton(sync_selected_radio_label)
        self.sync_selected_radio.toggled.connect(self.toggle_sync_selected)
        self.sync_selected_radio.setChecked(is_sync_selected)
        self.sync_selected_radio.setEnabled(len(selected_book_ids) > 0)
        self.radio_layout.addWidget(self.sync_selected_radio)

        self.reupload_possible = len(selected_book_ids) > 0 and len(
            selected_book_ids) <= 100
        if self.reupload_possible:
            for book_id in selected_book_ids:
                identifiers = self.db.get_proxy_metadata(book_id).identifiers
                if not identifiers.get('bookfusion'):
                    self.reupload_possible = False

        self.reupload_checkbox = QCheckBox('Re-upload book files', self)
        self.reupload_checkbox.setVisible(is_sync_selected
                                          and self.reupload_possible)
        self.radio_layout.addWidget(self.reupload_checkbox)

        self.btn_layout = QHBoxLayout()
        self.l.addLayout(self.btn_layout)

        self.config_btn = QPushButton('Configure')
        self.config_btn.clicked.connect(self.config)
        self.btn_layout.addWidget(self.config_btn)

        self.btn_layout.addStretch()

        self.start_btn = QPushButton('Start')
        self.start_btn.clicked.connect(self.start)
        self.btn_layout.addWidget(self.start_btn)

        self.cancel_btn = QPushButton('Cancel')
        self.cancel_btn.clicked.connect(self.cancel)
        self.cancel_btn.hide()
        self.btn_layout.addWidget(self.cancel_btn)

        self.info = QHBoxLayout()
        self.info.setContentsMargins(0, 0, 0, 0)
        self.l.addLayout(self.info)
        self.msg = QLabel()
        self.info.addWidget(self.msg)
        self.info.addStretch()
        self.log_btn = QLabel('<a href="#">Log</a>')
        self.log_btn.linkActivated.connect(self.toggle_log)
        self.log_btn.hide()
        self.info.addWidget(self.log_btn)

        self.log = QTableWidget(0, 2)
        self.log.setHorizontalHeaderLabels(['Book', 'Message'])
        self.log.horizontalHeader().setStretchLastSection(True)
        self.log.hide()
        self.l.addWidget(self.log)

        self.apply_config()

    def __del__(self):
        if self.worker_thread:
            self.worker_thread.quit()
            self.worker_thread.terminate()

    def config(self):
        self.do_user_config(parent=self)
        self.apply_config()

    def apply_config(self):
        configured = bool(prefs['api_key'])
        self.start_btn.setEnabled(configured)

    def toggle_sync_selected(self, is_sync_selected):
        if hasattr(self, 'reupload_checkbox'):
            self.reupload_checkbox.setVisible(is_sync_selected
                                              and self.reupload_possible)

    def start(self):
        if self.sync_selected_radio.isChecked(
        ) and self.reupload_checkbox.isChecked():
            reply = QMessageBox.question(
                self, 'BookFusion Sync',
                'Re-uploading book files can potentially result in previous highlights or bookmarks no longer working.\n\nPreviously uploaded files will be overwritten. Are you sure you want to re-upload?',
                QMessageBox.No | QMessageBox.Yes, QMessageBox.Yes)
            if reply != QMessageBox.Yes:
                return

        self.worker = None
        self.valid_book_ids = None
        self.book_log_map = {}
        self.book_progress_map = {}

        if self.sync_selected_radio.isChecked():
            book_ids = list(self.selected_book_ids)
        else:
            book_ids = list(self.db.all_book_ids())

        self.logger.info('Start sync: sync_selected={}; book_ids={}'.format(
            self.sync_selected_radio.isChecked(), book_ids))

        self.in_progress = True
        self.total = len(book_ids)
        self.update_progress(None)
        self.start_btn.hide()
        self.cancel_btn.show()
        self.config_btn.setEnabled(False)
        self.sync_all_radio.setEnabled(False)
        self.sync_selected_radio.setEnabled(False)

        self.worker_thread = QThread(self)

        self.worker = CheckWorker(self.db, self.logger, book_ids)
        self.worker.finished.connect(self.finish_check)
        self.worker.finished.connect(self.worker_thread.quit)
        self.worker.progress.connect(self.update_progress)
        self.worker.limitsAvailable.connect(self.apply_limits)
        self.worker.resultsAvailable.connect(self.apply_results)
        self.worker.aborted.connect(self.abort)
        self.worker.moveToThread(self.worker_thread)

        self.worker_thread.started.connect(self.worker.start)
        self.worker_thread.start()

    def apply_limits(self, limits):
        self.logger.info('Limits: {}'.format(limits))
        self.limits = limits

    def apply_results(self, books_count, valid_ids):
        self.logger.info('Check results: books_count={}; valid_ids={}'.format(
            books_count, valid_ids))
        self.valid_book_ids = valid_ids
        self.books_count = books_count

    def finish_check(self):
        if self.valid_book_ids:
            is_filesize_exceeded = len(self.valid_book_ids) < self.books_count
            is_total_books_exceeded = self.limits[
                'total_books'] and self.books_count > self.limits['total_books']

            if is_filesize_exceeded or is_total_books_exceeded:
                if self.limits['message']:
                    msg_box = QMessageBox(self)
                    msg_box.setWindowTitle('BookFusion Sync')
                    msg_box.addButton(QMessageBox.No)
                    msg_box.addButton(QMessageBox.Yes)
                    msg_box.setText(self.limits['message'])
                    msg_box.setDefaultButton(QMessageBox.Yes)
                    reply = msg_box.exec_()
                    if reply == QMessageBox.Yes:
                        self.start_sync()
                    else:
                        self.in_progress = False
                        self.msg.setText('Canceled.')
                        self.finish_sync()
                else:
                    self.start_sync()
            else:
                self.start_sync()
        else:
            if self.in_progress:
                self.in_progress = False
                self.msg.setText('No supported books selected.')
            self.finish_sync()

    def start_sync(self):
        self.log_btn.show()
        self.log.setRowCount(0)
        self.log.show()

        self.worker_thread = QThread(self)

        book_ids = self.valid_book_ids
        if self.limits['total_books']:
            book_ids = book_ids[:self.limits['total_books']]

        self.total = len(book_ids)

        self.worker = UploadManager(
            self.db, self.logger, book_ids,
            self.sync_selected_radio.isChecked()
            and self.reupload_checkbox.isChecked())
        self.worker.finished.connect(self.finish_sync)
        self.worker.finished.connect(self.worker_thread.quit)
        self.worker.progress.connect(self.update_progress)
        self.worker.uploadProgress.connect(self.update_upload_progress)
        self.worker.started.connect(self.log_start)
        self.worker.skipped.connect(self.log_skip)
        self.worker.failed.connect(self.log_fail)
        self.worker.uploaded.connect(self.log_upload)
        self.worker.updated.connect(self.log_update)
        self.worker.aborted.connect(self.abort)
        self.worker.moveToThread(self.worker_thread)

        self.worker_thread.started.connect(self.worker.start)
        self.worker_thread.start()

    def finish_sync(self):
        if self.in_progress:
            self.msg.setText('Done.')
        self.cancel_btn.hide()
        self.cancel_btn.setEnabled(True)
        self.start_btn.show()
        self.config_btn.setEnabled(True)
        self.sync_all_radio.setEnabled(True)
        self.sync_selected_radio.setEnabled(len(self.selected_book_ids) > 0)

    def abort(self, error):
        self.in_progress = False
        self.msg.setText(error)

    def cancel(self):
        self.in_progress = False
        self.msg.setText('Canceled.')
        self.cancel_btn.setEnabled(False)
        self.worker.cancel()

    def update_progress(self, progress):
        if self.in_progress:
            if isinstance(self.worker, UploadManager):
                msg = 'Synchronizing...'
            else:
                msg = 'Preparing...'
            if progress:
                msg += ' {} of {}'.format(progress + 1, self.total)
            self.msg.setText(msg)

    def update_upload_progress(self, book_id, sent, total):
        if not book_id in self.book_progress_map:
            return

        progress = self.book_progress_map[book_id]

        if sent < total:
            progress.setValue(sent)
            progress.setMaximum(total)
        else:
            progress.setMaximum(0)

    def log_start(self, book_id):
        self.update_log(book_id, None)

    def log_fail(self, book_id, msg):
        self.update_log(book_id, msg)

    def log_skip(self, book_id):
        self.update_log(book_id, 'skipped')

    def log_upload(self, book_id):
        self.update_log(book_id, 'uploaded')

    def log_update(self, book_id):
        self.update_log(book_id, 'updated')

    def toggle_log(self, _):
        self.log.setVisible(not self.log.isVisible())

    def update_log(self, book_id, msg):
        if book_id in self.book_log_map:
            index = self.book_log_map[book_id]
        else:
            index = self.log.rowCount()
            self.book_log_map[book_id] = index

            self.log.insertRow(index)

            title = self.db.get_proxy_metadata(book_id).title
            title_item = QTableWidgetItem(title)
            title_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                | Qt.ItemNeverHasChildren)
            self.log.setItem(index, 0, title_item)

            progress = QProgressBar()
            progress.setMaximum(0)
            self.log.setCellWidget(index, 1, progress)
            self.book_progress_map[book_id] = progress

        if not msg is None:
            del (self.book_progress_map[book_id])
            self.log.setCellWidget(index, 1, None)

            msg_item = QTableWidgetItem(msg)
            msg_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                              | Qt.ItemNeverHasChildren)
            self.log.setItem(index, 1, msg_item)

    def maybe_cancel(self):
        if self.worker_thread and self.worker_thread.isRunning():
            reply = QMessageBox.question(
                self, 'BookFusion Sync',
                'Are you sure you want to cancel the currently running process?',
                QMessageBox.No | QMessageBox.Yes, QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.cancel()
            else:
                return False
        return True
Exemple #2
0
class Game(QWidget):
    def __init__(self):
        super().__init__()
        self._flag_1 = False
        self.media = QtCore.QUrl.fromLocalFile("MP3/music.mp3")
        content = QtMultimedia.QMediaContent(self.media)
        self.player = QtMultimedia.QMediaPlayer()
        self.player.setMedia(content)
        self.player.setVolume(50)
        self.initUI()

    def initUI(self):
        self.file_number = 2
        self._score = 0
        self.setMouseTracking(True)
        self.resize(500, 500)
        self.center()
        self.setWindowTitle('Игра')

        self.main_pic = QLabel(self)
        self.main_pic.setPixmap(
            QPixmap(resource_path("PIC/running_rabbit.jpg")))
        self.main_pic.resize(500, 500)

        self.button_start_game = QPushButton("НАЧАТЬ ИГРУ", self)
        self.button_start_game.resize(140, 50)
        self.button_start_game.move(70, 300)
        self.button_start_game.clicked.connect(self.start_game)

        self.button_edit_map = QPushButton("СОЗДАТЬ КАРТУ", self)
        self.button_edit_map.resize(140, 50)
        self.button_edit_map.move(70, 360)
        self.button_edit_map.clicked.connect(self.edit_map_menu)

        self.button_exit = QPushButton("ЗАКОНЧИТЬ СЕАНС", self)
        self.button_exit.resize(140, 50)
        self.button_exit.move(70, 420)
        self.button_exit.clicked.connect(self.exit)

        self.timer_game = QTimer()
        self.timer_game.timeout.connect(self.updateValues)
        self.timer_game.start(200)
        self.setFocusPolicy(Qt.StrongFocus)

        self.lable_score = QLabel(self)
        self.lable_score.resize(200, 35)
        self.lable_score.setFont(
            QFont("RetroComputer[RUS by Daymarius]", 26, QFont.Bold))
        self.lable_score.setVisible(False)

        self.button_menu = QPushButton("НАЗАД", self)
        self.button_menu.resize(120, 40)
        self.button_menu.clicked.connect(self.show_menu)
        self.button_menu.setVisible(False)

        self.lable_name = QLabel("ВВЕДИТЕ ВАШЕ ИМЯ:", self)
        self.lable_name.sizeHint()
        self.lable_name.setFont(
            QFont("RetroComputer[RUS by Daymarius]", 10, QFont.Bold))
        self.lable_name.move(230, 300)

        self.input_name = QLineEdit("Без имени", self)
        self.input_name.resize(200, 20)
        self.input_name.move(230, 325)

        self.table_score = QTableWidget(self)
        self.table_score.resize(200, 120)
        self.table_score.move(230, 350)

    def bd_score(self):
        con = sqlite3.connect(resource_path("DB/score.db"))
        # Создание курсора
        cur = con.cursor()
        # Выполнение запроса и получение всех результатов
        result = cur.execute(
            "SELECT * FROM main ORDER BY score DESC;").fetchmany(5)
        cur.execute("DROP TABLE main")
        cur.execute("CREATE TABLE main (name STRING, score INTEGER)")
        for item in result:
            cur.execute("INSERT INTO main VALUES(?, ?)", (item[0], item[1]))
            con.commit()
        # Вывод результатов на экран
        if result != []:
            self.table_score.setColumnCount(len(result[0]))
            self.table_score.setRowCount(0)
            for i, row in enumerate(result):
                self.table_score.setRowCount(self.table_score.rowCount() + 1)
                for j, elem in enumerate(row):
                    item = QTableWidgetItem(str(elem))
                    self.table_score.setItem(i, j, item)
                    item.setFlags(QtCore.Qt.ItemIsEnabled)
            self.table_score.setHorizontalHeaderItem(
                0, QTableWidgetItem("Имя игрока"))
            self.table_score.setHorizontalHeaderItem(1,
                                                     QTableWidgetItem("Счет"))
            self.table_score.setColumnWidth(0, 127)
            self.table_score.setColumnWidth(1, 20)
        con.close()

    def append_bd_score_and_name(self):
        con = sqlite3.connect("DB/score.db")
        # Создание курсора
        cur = con.cursor()
        cur.execute("INSERT INTO main VALUES(?, ?)",
                    (self.input_name.text(), self.get_score()))
        con.commit()
        self.bd_score()
        con.close()

    def get_score(self):
        return self._score

    def set_score(self, score):
        self._score = score

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Right:
            self.hero.go_right()
        elif event.key() == Qt.Key_Left:
            self.hero.go_left()
        elif event.key() == Qt.Key_Up:
            self.hero.go_up()
        elif event.key() == Qt.Key_Down:
            self.hero.go_down()
        elif event.key() == Qt.Key_Space:
            self.hero.go_dig()

    def keyReleaseEvent(self, QKeyEvent):
        if self._flag_1 and not QKeyEvent.isAutoRepeat():
            self.hero.stop()

    def edit_map_menu(self):
        game.setVisible(False)
        edit_map.create_map()
        edit_map.show()

    def exit(self):
        sys.exit(app.exec())

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def reload_game(self):
        score = self.get_score()
        lifes = self.hero.get_lifes()
        self.start_game()
        self.set_score(score)
        self.hero.set_lifes(lifes)

    def start_game(self):
        self.player.play()
        self.set_score(0)
        self.map = Map(resource_path("MAP/" + str(self.file_number) + ".map"))
        for enemy in self.enemies:
            enemy.create_labirint()
        self.button_menu.setVisible(True)
        self.button_menu.setFocusPolicy(False)
        self.lable_score.setVisible(True)
        self.lable_score.move(0, 0)
        self.button_menu.move(self.map.get_col() * 40 - 120, 0)
        self.lable_score.setText("00000")
        sp_0_1 = []
        for j in range(self.map.get_row()):
            for i in range(self.map.get_col()):
                if type(self.map.get_elem_xy(i, j)) == Empty and (
                        self.map.get_row() - 1 == j
                        or type(self.map.get_elem_xy(
                            i, j + 1)) in [Stairs, Brick]):
                    sp_0_1.append((i, j))

        zerro = Zerro()
        one = One()
        for i in range(int(round(len(sp_0_1) * 0.2))):
            t = randrange(0, len(sp_0_1))
            x, y = sp_0_1[t]
            self.map.set_elem_xy(x, y, choice([zerro, one]))
            del sp_0_1[t]
        self.hide_menu()

    def show_menu(self):
        self.append_bd_score_and_name()
        game.player.pause()
        self.hero.timer.stop()
        for enemy in self.enemies:
            enemy.timer.stop()
        self.timer_game.stop()
        self.main_pic.show()
        self.table_score.show()
        self.input_name.show()
        self.lable_name.show()
        self.button_menu.setVisible(False)
        self.lable_score.setVisible(False)
        self.button_edit_map.setVisible(True)
        self.button_exit.setVisible(True)
        self.button_start_game.setVisible(True)
        self.resize(500, 500)
        self.center()
        self._flag_1 = False

    def hide_menu(self):
        game.player.play()
        self.hero.timer.start(200)
        for enemy in self.enemies:
            enemy.timer.start(200)
        game.timer_game.start(200)
        self.main_pic.hide()
        self.table_score.hide()
        self.input_name.hide()
        self.lable_name.hide()
        self.button_menu.setVisible(True)
        self.lable_score.setVisible(True)
        self.button_edit_map.setVisible(False)
        self.button_exit.setVisible(False)
        self.button_start_game.setVisible(False)
        self.resize(self.map.get_col() * 40, self.map.get_row() * 40 + 40)
        self.center()
        self._flag_1 = True

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        if self._flag_1:
            for i in range(self.map.get_col()):
                for j in range(self.map.get_row()):
                    qp.drawPixmap(
                        i * 40, j * 40 + 40,
                        self.map.get_elem_xy(
                            i, j).get_pic())  # рисуем картинками из elem_map
            qp.drawPixmap(self.hero.get_x() * 40,
                          self.hero.get_y() * 40 + 40, self.hero.get_pic())
            for enemy in self.enemies:
                qp.drawPixmap(enemy.get_x() * 40,
                              enemy.get_y() * 40 + 40, enemy.get_pic())
            for i in range(game.hero.get_lifes()):
                qp.drawPixmap(280 + i * 40, 0,
                              self.hero._pic[self.hero._STOP][0])

            txt = "00000" + str(self._score)
            self.lable_score.setText(txt[len(txt) - 5:len(txt)])
        qp.end()

    def updateValues(self):
        self.update()

    def you_lose(self):
        self.player.pause()
        self.hero.timer.stop()
        for enemy in self.enemies:
            enemy.timer.stop()
        self.timer_game.stop()
        if self.hero.get_lifes() > 1:
            game.player.pause()
            buttonReply = QMessageBox.question(
                self, 'ВЫ ПРОИГРАЛИ', "Продолжить игру?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
            if buttonReply == QMessageBox.Yes:
                self.hero.set_lifes(self.hero.get_lifes() - 1)
                self.reload_game()
                self.timer_game.start(200)
            else:
                self.set_score(0)
                self.show_menu()
        else:
            game.player.pause()
            buttonReply = QMessageBox.information(self, 'ИГРА ОКОНЧЕНА',
                                                  "Вы проиграли.")
            self.append_bd_score_and_name()
            self.show_menu()
Exemple #3
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle(WINDOW_TITLE)

        from pathlib import Path
        file_name = str(Path(__file__).resolve().parent / 'favicon.ico')
        icon = QIcon(file_name)

        self.setWindowIcon(icon)

        self.tray = QSystemTrayIcon(icon)
        self.tray.setToolTip(self.windowTitle())
        self.tray.activated.connect(self._on_tray_activated)
        self.tray.show()

        self.logged_dict = dict()

        self.pb_refresh = QPushButton('REFRESH')
        self.pb_refresh.clicked.connect(self.refresh)

        self.cb_show_log = QCheckBox()
        self.cb_show_log.setChecked(True)

        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setWordWrapMode(QTextOption.NoWrap)
        log_font = self.log.font()
        log_font.setFamily('Courier New')
        self.log.setFont(log_font)

        self.cb_show_log.clicked.connect(self.log.setVisible)
        self.log.setVisible(self.cb_show_log.isChecked())

        header_labels = ['DATE', 'TOTAL LOGGED TIME']
        self.table_logged = QTableWidget()
        self.table_logged.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_logged.setSelectionBehavior(QTableWidget.SelectRows)
        self.table_logged.setSelectionMode(QTableWidget.SingleSelection)
        self.table_logged.setColumnCount(len(header_labels))
        self.table_logged.setHorizontalHeaderLabels(header_labels)
        self.table_logged.horizontalHeader().setStretchLastSection(True)
        self.table_logged.itemClicked.connect(
            self._on_table_logged_item_clicked)

        header_labels = ['TIME', 'LOGGED', 'JIRA']
        self.table_logged_info = QTableWidget()
        self.table_logged_info.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_logged_info.setSelectionBehavior(QTableWidget.SelectRows)
        self.table_logged_info.setSelectionMode(QTableWidget.SingleSelection)
        self.table_logged_info.setColumnCount(len(header_labels))
        self.table_logged_info.setHorizontalHeaderLabels(header_labels)
        self.table_logged_info.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self.table_logged_info.horizontalHeader().setStretchLastSection(True)
        self.table_logged_info.itemDoubleClicked.connect(
            self._on_table_logged_info_item_double_clicked)

        main_layout = QVBoxLayout()

        central_widget = QWidget()
        central_widget.setLayout(main_layout)

        self.setCentralWidget(central_widget)

        self.pb_refresh.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred))

        h_layout = QHBoxLayout()
        h_layout.addWidget(self.pb_refresh)
        h_layout.addWidget(self.cb_show_log)

        layout_table_widget = QVBoxLayout()
        layout_table_widget.setContentsMargins(0, 0, 0, 0)
        layout_table_widget.addWidget(self.table_logged)
        layout_table_widget.addWidget(self.table_logged_info)

        table_widget = QWidget()
        table_widget.setLayout(layout_table_widget)

        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(table_widget)
        splitter.addWidget(self.log)

        main_layout.addLayout(h_layout)
        main_layout.addWidget(splitter)

    def _fill_tables(self, xml_data: bytes):
        import io
        buffer_io = io.StringIO()

        from contextlib import redirect_stdout

        try:
            with redirect_stdout(buffer_io):
                print(len(xml_data), repr(xml_data[:50]))

                # Структура документа -- xml
                self.logged_dict = parse_logged_dict(xml_data)
                print(self.logged_dict)

                if not self.logged_dict:
                    return

                import json
                print(
                    json.dumps(self.logged_dict, indent=4, ensure_ascii=False))
                print()

                logged_list = get_logged_list_by_now_utc_date(self.logged_dict)

                logged_total_seconds = get_logged_total_seconds(logged_list)
                logged_total_seconds_str = seconds_to_str(logged_total_seconds)
                print('entry_logged_list:', logged_list)
                print('today seconds:', logged_total_seconds)
                print('today time:', logged_total_seconds_str)
                print()

                # Для красоты выводим результат в табличном виде
                lines = []

                # Удаление строк таблицы
                while self.table_logged.rowCount():
                    self.table_logged.removeRow(0)

                for i, (date_str, logged_list) in enumerate(
                        get_sorted_logged(self.logged_dict)):
                    total_seconds = get_logged_total_seconds(logged_list)
                    total_seconds_str = seconds_to_str(total_seconds)
                    row = date_str, total_seconds_str, total_seconds
                    lines.append(row)

                    self.table_logged.setRowCount(
                        self.table_logged.rowCount() + 1)

                    self.table_logged.setItem(i, 0, QTableWidgetItem(date_str))

                    item = QTableWidgetItem(total_seconds_str)
                    item.setToolTip('Total seconds: {}'.format(total_seconds))
                    self.table_logged.setItem(i, 1, item)

                self.table_logged.setCurrentCell(0, 0)
                self.table_logged.setFocus()
                self._on_table_logged_item_clicked(
                    self.table_logged.currentItem())

                # Список строк станет списком столбцов, у каждого столбца подсчитается максимальная длина
                max_len_columns = [
                    max(map(len, map(str, col))) for col in zip(*lines)
                ]

                # Создание строки форматирования: [30, 14, 5] -> "{:<30} | {:<14} | {:<5}"
                my_table_format = ' | '.join('{:<%s}' % max_len
                                             for max_len in max_len_columns)

                for line in lines:
                    print(my_table_format.format(*line))

        finally:
            text = buffer_io.getvalue()
            self.log.setPlainText(text)

            print(text)

    def refresh(self):
        progress_dialog = QProgressDialog(self)

        thread = RunFuncThread(func=get_rss_jira_log)
        thread.run_finished.connect(self._fill_tables)
        thread.run_finished.connect(progress_dialog.close)
        thread.start()

        progress_dialog.setWindowTitle('Please wait...')
        progress_dialog.setLabelText(progress_dialog.windowTitle())
        progress_dialog.setRange(0, 0)
        progress_dialog.exec()

        from datetime import datetime
        self.setWindowTitle(WINDOW_TITLE + ". Last refresh date: " +
                            datetime.now().strftime('%d/%m/%Y %H:%M:%S'))

    def _on_table_logged_item_clicked(self, item: QTableWidgetItem):
        # Удаление строк таблицы
        while self.table_logged_info.rowCount():
            self.table_logged_info.removeRow(0)

        row = item.row()
        date_str = self.table_logged.item(row, 0).text()
        logged_list = self.logged_dict[date_str]
        logged_list = reversed(logged_list)

        for i, logged in enumerate(logged_list):
            self.table_logged_info.setRowCount(
                self.table_logged_info.rowCount() + 1)

            self.table_logged_info.setItem(i, 0,
                                           QTableWidgetItem(logged['time']))
            self.table_logged_info.setItem(
                i, 1, QTableWidgetItem(logged['logged_human_time']))

            item = QTableWidgetItem(logged['jira_id'])
            item.setToolTip(logged['jira_title'])
            self.table_logged_info.setItem(i, 2, item)

    def _on_table_logged_info_item_double_clicked(self,
                                                  item: QTableWidgetItem):
        row = item.row()
        jira_id = self.table_logged_info.item(row, 2).text()

        url = 'https://jira.compassplus.ru/browse/' + jira_id

        import webbrowser
        webbrowser.open(url)

    def _on_tray_activated(self, reason):
        self.setVisible(not self.isVisible())

        if self.isVisible():
            self.showNormal()
            self.activateWindow()

    def changeEvent(self, event: QEvent):
        if event.type() == QEvent.WindowStateChange:
            # Если окно свернули
            if self.isMinimized():
                # Прячем окно с панели задач
                QTimer.singleShot(0, self.hide)
class SnifferFilter(QDialog):

    ## The constructor.
    #  Initialize lists to be filled with filtered payloads and
    #  create the dialog.
    def __init__(self, parent):
        super(SnifferFilter, self).__init__()
        self.parent = parent
        self.setWindowTitle('SnifferFilter')
        self.filteredPayloadList = []
        self.filteredIdList = []
        self.layoutingComplete = False

        self.calledBy = 'NONE'  # We store here which tab the filter belongs to, if there is no parent.(Like when the filter is global!)

        self.objectTabDict = {}
        self.filteredObjectDict = {}

        self.resize(670, 700)

    ## Filters the global payloadList by ID by iterating through it and
    #  appending to a new list by filter-criteria
    #  @param filterList a list of IDs that are to be transferred to the new list
    def filterPayloadsByID(self, filterList):
        for payload in Globals.payloadList:
            if hasattr(payload, 'payloadHead'):
                if Globals.tspDict[
                        payload.payloadHead.informationID][0] in filterList:
                    self.filteredPayloadList.append(payload)
                else:
                    #print('informationID is in filteredIdList, skipping packet')
                    pass

    ## Filters the global payloadList by Message by iterating through it and
    #  appending to a new list by filter-criteria
    #  @param filterDict a dictionary of Key: ObjectType and Value: ObjectsToKeep as a template
    #  of which items are to be kept in the filteredList
    def filterPayloadsByMessage(self, filterDict):
        localFilteredList = []
        for payload in self.filteredPayloadList:
            print('payloadID:' + str(payload.payloadHead.informationID))
            # If the ID has nothing to do with the object, we can safely add it.
            if payload.payloadHead.informationID is 23:
                x = 0
                pass
            if isRelatedToObject(payload):
                for objType, messageID in filterDict.items():
                    print(Globals.objectTypeDict[getObjectType(payload)])
                    if Globals.objectTypeDict[getObjectType(
                            payload
                    )] == objType:  # If the objectType matches the one in the dictionary
                        if objType == 0:
                            x = 0
                            pass
                        if getDataType(payload) == 2:
                            if payload.data2 not in messageID:  # and the message does not match the dictionary
                                print(
                                    'Passing data with msgid: ' +
                                    str(payload.data2)
                                )  # don't append, but print that we skipped this one
                            else:
                                localFilteredList.append(
                                    payload
                                )  # the message does match the dictionary -> we want to keep it, so we add it to the list

                        elif getDataType(payload) == 1:
                            if payload.data1 not in messageID:
                                print('Passing data with msgid: ' +
                                      str(payload.data1))
                            else:
                                localFilteredList.append(payload)
                        else:
                            localFilteredList.append(payload)
                    else:
                        # If the ID has nothing to do with the object, we can safely add it.
                        # Also, is the object is not even in the filterDict, we can add it too (this should not happen, but
                        # it's there for safety purposes
                        if getDataType(payload) == 0 or Globals.objectTypeDict[
                                getObjectType(payload)] not in filterDict:
                            localFilteredList.append(payload)
            else:
                localFilteredList.append(payload)

        # In every other case, append it to the list, since we only want to filter out specific objects
        self.filteredPayloadList = list(localFilteredList)

    ## Create the visible UI
    #  like the different tables, the searchbar etc.
    def setSnifferFilterUi(self):

        self.filterTabs = QTabWidget()
        self.H1layout = QHBoxLayout()
        self.Vlayout = QVBoxLayout()

        self.searchInputField = QLineEdit()
        self.searchInputField.setPlaceholderText(
            'Enter search term, then click search')
        self.searchButt = QPushButton('Search Table')
        self.saveFilterButt = QPushButton('Save Filter')
        self.filterTable = QTableWidget()

        self.saveFilterButt.clicked.connect(self.saveFilterList)
        self.searchButt.clicked.connect(
            lambda: self.searchInTable(self.searchInputField.text(), 0))

        # Create Table
        self.filterTableIndex = 0
        self.filterTable = QTableWidget()
        self.filterTableItem = QTableWidgetItem()
        self.filterTable.setRowCount(0)
        self.filterTable.setColumnCount(2)

        self.filterTable.setHorizontalHeaderLabels(
            'informationID;Enable'.split(';'))
        self.filterTable.resizeColumnsToContents()
        self.filterTableHeader = self.filterTable.horizontalHeader()
        self.filterTableHeader.setSectionResizeMode(0, QHeaderView.Stretch)
        self.filterTableHeader.setSectionResizeMode(
            1, QHeaderView.ResizeToContents)

        font = self.getFont()

        self.checkBoxAllIds = self.createCheckBox()
        self.filterTable.itemChanged.connect(self.filterAllIDs)
        self.checkBoxAllMessages = self.createCheckBox()

        # -- Add first Row for all -- #
        self.filterTable.insertRow(self.filterTableIndex)
        idFilterItem = QTableWidgetItem('FILTER ALL IDs')
        idFilterItem.setFont(font)
        messageFilterItem = QTableWidgetItem('FILTER ALL Messages')
        messageFilterItem.setFont(font)
        self.filterTable.setItem(self.filterTableIndex, 0, idFilterItem)
        self.filterTable.setItem(self.filterTableIndex, 1, self.checkBoxAllIds)
        self.filterTableIndex = self.filterTableIndex + 1

        # -- Add informationID filter rows -- #
        for keys, values in Globals.tspDict.items():
            if values[0].startswith('ID'):
                checkBoxFilter = self.createCheckBox()
                self.filterTable.insertRow(self.filterTableIndex)
                self.filterTable.setItem(self.filterTableIndex, 0,
                                         QTableWidgetItem(values[0]))
                self.filterTable.setItem(self.filterTableIndex, 1,
                                         checkBoxFilter)
                self.filterTableIndex = self.filterTableIndex + 1

        self.filterTabs.addTab(self.filterTable, 'Information ID')

        self.H1layout.addWidget(self.searchInputField)
        self.H1layout.addWidget(self.searchButt)
        self.Vlayout.addLayout(self.H1layout)
        self.Vlayout.addWidget(self.filterTabs)
        self.Vlayout.addWidget(self.saveFilterButt)
        #------------------------------------
        self.setLayout(self.Vlayout)
        self.layoutingComplete = True

    ## Updates the visible filter UI to the new objectList
    #  This function is called, when either a new measurement was executed or an old measurement was loaded.
    #  Since the objects shown in the Filter need to be updated.
    def updateObjectFilter(self):
        # -- Add message filter rows -- #
        font = self.getFont()
        self.filterTabs.clear()
        self.filterTabs.addTab(self.filterTable, 'Information ID')
        # For each object in objectList, create a new Table and add it to the tabs.
        for keys, values in Globals.objectDict.items():
            objectFilterTable = QTableWidget()
            objectFilterTable.setRowCount(0)
            objectFilterTable.setColumnCount(2)
            strSplit = keys + ';Enable'
            objectFilterTable.setHorizontalHeaderLabels(strSplit.split(';'))
            objectFilterTable.resizeColumnsToContents()
            filterTableHeader = objectFilterTable.horizontalHeader()
            filterTableHeader.setSectionResizeMode(0, QHeaderView.Stretch)
            filterTableHeader.setSectionResizeMode(
                1, QHeaderView.ResizeToContents)
            checkBoxFilter = self.createCheckBox()

            objectFilterTable.itemChanged.connect(
                lambda *a, table=objectFilterTable: self.filterAllObjectIDs(
                    *a, table=table))

            objectTableIndex = 0
            objectFilterTable.insertRow(objectTableIndex)
            objCat = QTableWidgetItem('FILTER ALL')
            objCat.setFont(font)
            objectFilterTable.setItem(objectTableIndex, 0, objCat)
            objectFilterTable.setItem(objectTableIndex, 1, checkBoxFilter)
            objectTableIndex = objectTableIndex + 1
            for keys2, values2 in values.items():
                objectFilterTable.insertRow(objectTableIndex)
                checkBoxFilter = self.createCheckBox()
                objectFilterTable.setItem(
                    objectTableIndex, 0,
                    QTableWidgetItem('ID: ' + str(keys2) + ' Name: ' +
                                     str(values2)))
                objectFilterTable.setItem(objectTableIndex, 1, checkBoxFilter)
                objectTableIndex = objectTableIndex + 1

            # Add the newly create table to the tabs.
            self.filterTabs.addTab(objectFilterTable, keys)
            self.objectTabDict[keys] = objectFilterTable

    ## Searches the table for a string and scrolls to the found item.
    #  @param textToSearch the string that needs to be found in the table
    #  @param column the column where the search needs to take place
    def searchInTable(self, textToSearch, column):
        # Create a model of the table, so we can match a text
        tableModel = self.filterTable.model()
        start = tableModel.index(0, column)
        matches = tableModel.match(start, Qt.DisplayRole, textToSearch, 1,
                                   Qt.MatchContains)
        # If there are multiple matches, we take the first one, select it and scroll to it
        if matches:
            index = matches[0]
            self.filterTable.selectionModel().select(
                index, QItemSelectionModel.Select)
            self.filterTable.scrollToItem(
                self.filterTable.itemFromIndex(index))

    ## CB: SaveFilterButton // Call the filterFunctions -> Filter the unfiltered list by ID and Object and call the update
    #  function of the executing tab in order to update their UI.
    def saveFilterList(self):
        self.filteredPayloadList.clear()

        #--Save by ID--#
        rowCnt = self.filterTable.rowCount()
        self.filteredIdList.clear()
        for rows in range(0, rowCnt):
            if self.filterTable.item(rows, 1).checkState() == Qt.Checked:
                #print(self.filterTable.item(rows,0).text())
                self.filteredIdList.append(
                    self.filterTable.item(rows, 0).text())
        self.filterPayloadsByID(self.filteredIdList)
        print(len(self.filteredPayloadList))
        print(len(Globals.payloadList))

        #--Save By Objects--#
        self.filteredObjectDict.clear()
        for objType, objectTable in self.objectTabDict.items():
            rowCnt = objectTable.rowCount()
            objectsToFilter = []
            for rows in range(0, rowCnt):
                if objectTable.item(rows, 1).checkState() == Qt.Checked:
                    #print(objectTable.item(rows,0).text())
                    try:
                        objectsToFilter.append(
                            int(
                                re.search('ID: (.*) Name:.*',
                                          objectTable.item(
                                              rows, 0).text()).group(1)))
                        self.filteredObjectDict[objType] = objectsToFilter
                        #print('Found Regex: '+re.search('ID: (.*) Name:.*',objectTable.item(rows,0).text()).group(1))
                    except:
                        print('Error when parsing TableRegex...this is okay')
        self.filterPayloadsByMessage(self.filteredObjectDict)

        # We filtered the list, now we hide the windows and call the update-function
        # If the maintainer of the tab did not follow the implementation guide, there is no update-function to call.
        # We still save the filtered list, so we print a message to show where to find it.
        self.hide()
        try:
            self.parent.filterUpdated(self.filteredIdList,
                                      self.filteredPayloadList)
        except AttributeError:
            print(
                'No corresponding callable function filterUpdated was found, you can access the most recent filteredList via self.snifferFilter.filteredIdList'
            )
        try:
            Globals.dockDict[self.calledBy].filterUpdated(
                self.filteredIdList, self.filteredPayloadList)
        except:
            print('not global!')

    ## Check whether the first checkbox was checked and then update the entire ID table to either checked or unchecked state
    #  @param checkBox a checkBox we perform the query on
    def filterAllIDs(self, checkBox):
        if self.layoutingComplete == True:
            if checkBox.column() == 1 and checkBox.row(
            ) == 0:  # We clicked the toggle ID checkbox
                if checkBox.checkState() == Qt.Checked:
                    rowCnt = self.filterTable.rowCount()
                    for rows in range(0, rowCnt):
                        try:
                            self.filterTable.item(rows,
                                                  1).setCheckState(Qt.Checked)
                        except AttributeError:
                            print(
                                'no items after' + str(rows) +
                                'found...Maybe this column has less items than'
                                + str(rowCnt) + '?')
                elif checkBox.checkState() == Qt.Unchecked:
                    rowCnt = self.filterTable.rowCount()
                    for rows in range(0, rowCnt):
                        try:
                            self.filterTable.item(rows, 1).setCheckState(
                                Qt.Unchecked)
                        except AttributeError:
                            print(
                                'no items after' + str(rows) +
                                'found...Maybe this column has less items than'
                                + str(rowCnt) + '?')
                else:
                    print(
                        'neither checked nor unchecked...should never be here..'
                    )

    ## Check whether the first checkbox was checked and then update the entire ObjectIDtable to either checked or unchecked state
    #  @param checkBox a checkBox we perform the query on
    #  @param table the table that is to be updated
    def filterAllObjectIDs(self, checkBox, table):
        if (self.objectTabDict):
            if checkBox.column() == 1 and checkBox.row(
            ) == 0:  # We clicked the toggle ID checkbox
                if checkBox.checkState() == Qt.Checked:
                    rowCnt = table.rowCount()
                    for rows in range(0, rowCnt):
                        try:
                            table.item(rows, 1).setCheckState(Qt.Checked)
                        except AttributeError:
                            print(
                                'no items after' + str(rows) +
                                'found...Maybe this column has less items than'
                                + str(rowCnt) + '?')
                elif checkBox.checkState() == Qt.Unchecked:
                    rowCnt = table.rowCount()
                    for rows in range(0, rowCnt):
                        try:
                            table.item(rows, 1).setCheckState(Qt.Unchecked)
                        except AttributeError:
                            print(
                                'no items after' + str(rows) +
                                'found...Maybe this column has less items than'
                                + str(rowCnt) + '?')
                else:
                    print(
                        'neither checked nor unchecked...should never be here..'
                    )

    # --- HELPER FUNCTIONS --- #
    ## Create a defined checkbox within a tableWidgetItem to facilitate filling the table
    #  @return the created checkbox
    def createCheckBox(self):
        myCheck = QTableWidgetItem()
        myCheck.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
        myCheck.setCheckState(Qt.Checked)
        return myCheck

    ## Create a defined font (bold,underlined) to facilitate filling the table
    #  @return the created font
    def getFont(self):
        font = QFont()
        font.setBold(True)
        font.setUnderline(True)
        return font
class DictionaryDialog(QDialog):
    def setupUi(self):
        self.setWindowTitle('Dictionary')

        layout = QGridLayout(self)
        self.setLayout(layout)

        self.edit = QLineEdit(self)
        self.edit.textChanged.connect(self.onTextChanged)
        self.edit.returnPressed.connect(self.onReturnPressed)

        searchButton = QPushButton('&Search', self)
        searchButton.clicked.connect(self.onSearchButtonClicked)

        addButton = QPushButton('Add', self)
        addButton.clicked.connect(self.onAddButtonClicked)

        header = ('Short', 'Long', "Translate")
        self.table = QTableWidget(self)
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(header)
        self.table.setColumnWidth(0, 50)
        self.table.setColumnWidth(1, 200)

        self.edit.setCompleter(
            QCompleter(self.updateTable(self.dictionary.words)))

        layout.addWidget(self.edit, 0, 0)
        layout.addWidget(searchButton, 0, 1)
        layout.addWidget(addButton, 0, 2)
        layout.addWidget(self.table, 1, 0, 1, 3)

    def onSearchButtonClicked(self):
        pass

    def onAddButtonClicked(self):
        pass

    def onTextChanged(self, arg):
        self.updateTable(self.dictionary.compare(arg))

    def onReturnPressed(self):
        if (self.table.rowCount() == 0):
            if (QMessageBox.question(
                    self, "Add",
                    "Not Found\nAdd new one?") == QMessageBox.Yes):
                self.createWordDialog(Word('%s,,' % self.edit.text()))

    def createWordDialog(self, word=Word('')):
        dialog = QDialog(self)
        layout = QGridLayout(self)

        dialog.setLayout(layout)
        shortEdit = QLineEdit(word.short)
        longEdit = QLineEdit(word.long)
        explainEdit = QLineEdit(word.explain)
        okButton = QPushButton('OK')
        okButton.clicked.connect(dialog.accept)
        cancelButton = QPushButton('Cancel')
        cancelButton.clicked.connect(dialog.reject)

        layout.addWidget(QLabel('Short'), 0, 0)
        layout.addWidget(shortEdit, 0, 1)
        layout.addWidget(QLabel('Long'), 1, 0)
        layout.addWidget(longEdit, 1, 1)
        layout.addWidget(QLabel('Translate'), 2, 0)
        layout.addWidget(explainEdit, 2, 1)
        layout.addWidget(okButton, 3, 0)
        layout.addWidget(cancelButton, 3, 1)

        dialog.exec()
        if (dialog.result() == QDialog.Accepted):
            word = Word(
                '%s,%s,%s' %
                (shortEdit.text(), longEdit.text(), explainEdit.text()))
            self.dictionary.append(word)
            self.dictionary.save()
            self.updateTable(self.dictionary.words)

    def updateTable(self, words):
        results = []
        self.table.setRowCount(len(words))
        i = 0
        for word in words:
            self.table.setItem(i, 0, QTableWidgetItem(word.short))
            self.table.setItem(i, 1, QTableWidgetItem(word.long))
            self.table.setItem(i, 2, QTableWidgetItem(word.explain))
            i += 1
            results.append(word.short)
        return results

    def __init__(self, parent=None):
        super(QDialog, self).__init__()
        self.dictionary = Dictionary()
        self.dictionary.load()
        self.setupUi()