Exemplo n.º 1
0
 def __init__(self, analyzer_utility):
     super(AnalyzerSelector, self).__init__()
     self.__analyzer_utility = analyzer_utility
     self.__ok = True
     self.__table_analyzer = TableViewEx()
     self.__button_ok = QPushButton('OK')
     self.__button_cancel = QPushButton('Cancel')
     self.init_ui()
Exemplo n.º 2
0
    def __init__(self, memo_data: StockMemoData):
        super(StockMemoDeck, self).__init__()
        self.__memo_data = memo_data

        if self.__memo_data is not None:
            self.__memo_data.add_observer(self)

            self.__sas = self.__memo_data.get_sas()
            self.__memo_record: StockMemoRecord = self.__memo_data.get_memo_record()
            self.__memo_editor: StockMemoEditor = self.__memo_data.get_data('editor')
            self.__data_utility = self.__sas.get_data_hub_entry().get_data_utility() if self.__sas is not None else None
        else:
            # For layout debug
            self.__sas = None
            self.__memo_record = None
            self.__memo_editor = None
            self.__data_utility = None

        self.__memo_extras = []
        self.__list_securities = []
        self.__show_securities = []

        # ---------------- Page -----------------

        self.__page = 1
        self.__item_per_page = 20

        self.__button_first = QPushButton('|<')
        self.__button_prev = QPushButton('<')
        self.__spin_page = QSpinBox()
        self.__label_total_page = QLabel('/ 1')
        self.__button_jump = QPushButton('GO')
        self.__button_next = QPushButton('>')
        self.__button_last = QPushButton('>|')

        self.__button_reload = QPushButton('Reload')
        self.__check_show_black_list = QCheckBox('Black List')

        # --------------- Widgets ---------------

        self.__memo_table = TableViewEx()
        self.__stock_selector = \
            SecuritiesSelector(self.__data_utility) if self.__data_utility is not None else QComboBox()
        self.__line_path = QLineEdit(self.__memo_data.get_root_path() if self.__memo_data is not None else root_path)
        self.__info_panel = QLabel(NOTE)
        self.__button_new = QPushButton('New')
        self.__button_filter = QPushButton('Filter')
        self.__button_browse = QPushButton('Browse')
        # self.__button_black_list = QPushButton('Black List')

        self.__layout_extra = QHBoxLayout()

        self.init_ui()
        self.config_ui()

        self.show_securities(self.__memo_record.get_all_security() if self.__memo_record is not None else [])
Exemplo n.º 3
0
    def __init__(self, data_hub_entry: DataHubEntry,
                 update_table: UpdateTableEx):
        super(DataUpdateUi, self).__init__()

        # Access entry
        self.__data_hub = data_hub_entry
        self.__data_center = self.__data_hub.get_data_center()
        self.__update_table = update_table

        # Table content
        self.__display_uri = []
        self.__display_identities = None
        self.__display_table_lines = []

        # Page related
        self.__page = 0
        self.__item_per_page = 20

        # For processing updating
        self.__processing_update_tasks = []
        # Fot task counting
        self.__processing_update_tasks_count = []

        self.task_finish_signal.connect(self.__on_task_done)
        self.refresh_finish_signal.connect(self.update_table_display)

        # Timer for update status
        self.__timer = QTimer()
        self.__timer.setInterval(1000)
        self.__timer.timeout.connect(self.on_timer)
        self.__timer.start()

        # UI related
        self.__info_panel = QLabel(DEFAULT_INFO)

        self.__table_main = TableViewEx()
        self.__button_head_page = QPushButton('<<')
        self.__button_prev_page = QPushButton('<')
        self.__button_next_page = QPushButton('>')
        self.__button_tail_page = QPushButton('>>')
        self.__button_upper_level = QPushButton('↑')

        self.__button_refresh = QPushButton('Refresh')
        self.__button_batch_auto_update = QPushButton('Auto Update Select')
        self.__button_batch_force_update = QPushButton('Force Update Select')

        self.init_ui()

        # Post update and cache stock list after posting RefreshTask
        data_utility = self.__data_hub.get_data_utility()
        StockAnalysisSystem().get_task_queue().add_observer(self)
        StockAnalysisSystem().get_task_queue().append_task(
            UpdateStockListTask(data_utility))
Exemplo n.º 4
0
    def __init__(self, data_hub_entry: DataHubEntry,
                 strategy_entry: StrategyEntry):
        super(AnalyzerUi, self).__init__()
        self.__data_hub_entry = data_hub_entry
        self.__strategy_entry = strategy_entry

        self.__analyzer_info = self.__strategy_entry.analyzer_info()

        # Thread and task related
        self.__selector_list = []
        self.__analyzer_list = []
        self.__result_output = StockAnalysisSystem().get_project_path()
        self.__timing_clock = Clock()
        self.__progress_rate = ProgressRate()
        self.task_finish_signal.connect(self.__on_task_done)

        # Timer for update status
        self.__timer = QTimer()
        self.__timer.setInterval(1000)
        self.__timer.timeout.connect(self.on_timer)
        self.__timer.start()

        # UI related
        group, layout = create_v_group_box('Selector')
        self.__group_selector = group
        self.__layout_selector = layout

        group, layout = create_v_group_box('Analyzer')
        self.__group_analyzer = group
        self.__layout_analyzer = layout

        group, layout = create_v_group_box('Option')
        self.__group_option = group
        self.__layout_option = layout

        group, layout = create_h_group_box('Result')
        self.__group_result = group
        self.__layout_result = layout

        self.__table_selector = TableViewEx()
        self.__table_analyzer = TableViewEx()

        # self.__radio_group_selector = QButtonGroup(self)
        # self.__radio_all = QRadioButton('All')
        # self.__radio_tags = QRadioButton('Tags')
        # self.__radio_manual = QRadioButton('Manual')
        # self.__table_preview = QTableWidget()

        self.__check_force_calc = QCheckBox('Force Calc')
        self.__check_auto_cache = QCheckBox('Cache Result')

        self.__check_load_json = QCheckBox('Load Json')
        self.__check_dump_json = QCheckBox('Dump Json')
        self.__check_load_dump_all = QCheckBox('Load/Dump All')

        self.__datetime_time_since = QDateTimeEdit(years_ago(5))
        self.__datetime_time_until = QDateTimeEdit(now())

        self.__edit_path = QLineEdit('analysis_report.xlsx')
        self.__button_browse = QPushButton('Browse')

        self.__button_selector = QPushButton('Selector')
        self.__button_analyzer = QPushButton('Analyzer')
        self.__button_result = QPushButton('Result')
        self.__button_run_strategy = QPushButton('Run Strategy')

        self.__check_attach_basic_index = QCheckBox('Attach Basic Index')

        self.init_ui()
        self.update_selector()
        self.update_analyzer()
Exemplo n.º 5
0
class AnalyzerUi(QWidget):
    task_finish_signal = pyqtSignal()

    TABLE_HEADER_SELECTOR = ['', 'Selector', 'Comments', 'UUID', 'Status']
    TABLE_HEADER_ANALYZER = ['', 'Strategy', 'Comments', 'UUID', 'Status']

    def __init__(self, data_hub_entry: DataHubEntry,
                 strategy_entry: StrategyEntry):
        super(AnalyzerUi, self).__init__()
        self.__data_hub_entry = data_hub_entry
        self.__strategy_entry = strategy_entry

        self.__analyzer_info = self.__strategy_entry.analyzer_info()

        # Thread and task related
        self.__selector_list = []
        self.__analyzer_list = []
        self.__result_output = StockAnalysisSystem().get_project_path()
        self.__timing_clock = Clock()
        self.__progress_rate = ProgressRate()
        self.task_finish_signal.connect(self.__on_task_done)

        # Timer for update status
        self.__timer = QTimer()
        self.__timer.setInterval(1000)
        self.__timer.timeout.connect(self.on_timer)
        self.__timer.start()

        # UI related
        group, layout = create_v_group_box('Selector')
        self.__group_selector = group
        self.__layout_selector = layout

        group, layout = create_v_group_box('Analyzer')
        self.__group_analyzer = group
        self.__layout_analyzer = layout

        group, layout = create_v_group_box('Option')
        self.__group_option = group
        self.__layout_option = layout

        group, layout = create_h_group_box('Result')
        self.__group_result = group
        self.__layout_result = layout

        self.__table_selector = TableViewEx()
        self.__table_analyzer = TableViewEx()

        # self.__radio_group_selector = QButtonGroup(self)
        # self.__radio_all = QRadioButton('All')
        # self.__radio_tags = QRadioButton('Tags')
        # self.__radio_manual = QRadioButton('Manual')
        # self.__table_preview = QTableWidget()

        self.__check_force_calc = QCheckBox('Force Calc')
        self.__check_auto_cache = QCheckBox('Cache Result')

        self.__check_load_json = QCheckBox('Load Json')
        self.__check_dump_json = QCheckBox('Dump Json')
        self.__check_load_dump_all = QCheckBox('Load/Dump All')

        self.__datetime_time_since = QDateTimeEdit(years_ago(5))
        self.__datetime_time_until = QDateTimeEdit(now())

        self.__edit_path = QLineEdit('analysis_report.xlsx')
        self.__button_browse = QPushButton('Browse')

        self.__button_selector = QPushButton('Selector')
        self.__button_analyzer = QPushButton('Analyzer')
        self.__button_result = QPushButton('Result')
        self.__button_run_strategy = QPushButton('Run Strategy')

        self.__check_attach_basic_index = QCheckBox('Attach Basic Index')

        self.init_ui()
        self.update_selector()
        self.update_analyzer()

    # ---------------------------------------------------- UI Init -----------------------------------------------------

    def init_ui(self):
        self.__layout_control()
        self.__config_control()

    def __layout_control(self):
        main_layout = QVBoxLayout()
        self.setLayout(main_layout)
        self.setMinimumSize(600, 400)

        self.__layout_selector.addWidget(self.__table_selector)
        main_layout.addWidget(self.__group_selector)

        self.__layout_analyzer.addWidget(self.__table_analyzer)
        main_layout.addWidget(self.__group_analyzer)

        self.__layout_result.addWidget(self.__edit_path)
        self.__layout_result.addWidget(self.__button_browse)
        main_layout.addWidget(self.__group_result)

        grid_layout = QGridLayout()
        grid_layout.addWidget(self.__check_force_calc, 0, 0)
        grid_layout.addWidget(self.__check_auto_cache, 1, 0)
        grid_layout.addWidget(self.__check_load_json, 0, 1)
        grid_layout.addWidget(self.__check_dump_json, 1, 1)

        grid_layout.addWidget(QLabel(' '), 0, 2)
        grid_layout.addWidget(QLabel(' '), 0, 2)

        grid_layout.addWidget(QLabel('Since'), 0, 3)
        grid_layout.addWidget(QLabel('Until'), 1, 3)
        grid_layout.addWidget(self.__datetime_time_since, 0, 4)
        grid_layout.addWidget(self.__datetime_time_until, 1, 4)

        grid_layout.addWidget(self.__check_attach_basic_index, 2, 0, 3, 1)
        grid_layout.addWidget(self.__check_load_dump_all, 2, 1, 3, 1)

        self.__layout_option.addLayout(grid_layout)

        main_layout.addWidget(self.__group_option)

        bottom_control_area = QHBoxLayout()
        main_layout.addLayout(bottom_control_area)

        bottom_control_area.addWidget(QLabel('Strategy Flow: '), 99)
        bottom_control_area.addWidget(self.__button_selector)
        bottom_control_area.addWidget(QLabel('==>'))
        bottom_control_area.addWidget(self.__button_analyzer)
        bottom_control_area.addWidget(QLabel('==>'))
        bottom_control_area.addWidget(self.__button_result)
        bottom_control_area.addWidget(QLabel(' | '))
        bottom_control_area.addWidget(self.__button_run_strategy)

    def __config_control(self):
        self.__table_selector.SetCheckableColumn(0)
        self.__table_selector.SetColumn(AnalyzerUi.TABLE_HEADER_SELECTOR)
        self.__table_selector.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)

        self.__table_analyzer.SetCheckableColumn(0)
        self.__table_analyzer.SetColumn(AnalyzerUi.TABLE_HEADER_ANALYZER)
        self.__table_analyzer.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)

        self.__check_auto_cache.setChecked(True)
        self.__datetime_time_since.setCalendarPopup(True)
        self.__datetime_time_until.setCalendarPopup(True)

        self.__check_force_calc.setToolTip('勾选此项后,程序将不会从缓存中读取分析结果,并强制进行实时计算。')
        self.__check_auto_cache.setToolTip('勾选此项后,程序会自动缓存分析结果到SasCache数据库')
        self.__check_load_json.setToolTip('仅供Debug:从JSON文件中载入分析结果')
        self.__check_dump_json.setToolTip('仅供Debug:将分析结果写入JSON文件中')
        self.__check_load_dump_all.setToolTip(
            '仅供Debug:载入/保存所有结果而不是按Analyzer分别载入/保存')

        self.__layout_selector.setSpacing(0)
        self.__layout_analyzer.setSpacing(0)
        self.__layout_option.setSpacing(0)
        self.__layout_result.setSpacing(0)
        self.__layout_selector.setContentsMargins(0, 0, 0, 0)
        self.__layout_analyzer.setContentsMargins(0, 0, 0, 0)
        # self.__layout_result.setContentsMargins(0, 0, 0, 0)

        self.__button_result.clicked.connect(self.on_button_browse)
        self.__button_browse.clicked.connect(self.on_button_browse)
        self.__button_selector.clicked.connect(self.on_button_selector)
        self.__button_analyzer.clicked.connect(self.on_button_analyzer)
        self.__button_run_strategy.clicked.connect(self.on_button_run_strategy)

    def on_button_browse(self):
        file_path, ok = QFileDialog.getSaveFileName(
            self, 'Select Result Excel Path', '',
            'XLSX Files (*.xlsx);;All Files (*)')
        if ok:
            self.__edit_path.setText(file_path)

    def on_button_selector(self):
        self.__group_selector.setVisible(True)
        self.__group_analyzer.setVisible(not self.__group_analyzer.isVisible())

    def on_button_analyzer(self):
        self.__group_analyzer.setVisible(True)
        self.__group_selector.setVisible(not self.__group_selector.isVisible())

    def on_button_run_strategy(self):
        selector_list = []
        analyzer_list = []

        output_path = self.__edit_path.text()
        if len(output_path.strip()) == 0:
            QMessageBox.information(
                self, QtCore.QCoreApplication.translate('', '配置缺失'),
                QtCore.QCoreApplication.translate('', '请指定结果输出文件'),
                QMessageBox.Close, QMessageBox.Close)

        for i in range(self.__table_analyzer.RowCount()):
            if self.__table_analyzer.GetItemCheckState(i,
                                                       0) == QtCore.Qt.Checked:
                uuid = self.__table_analyzer.GetItemText(i, 3)
                analyzer_list.append(uuid)

        if len(analyzer_list) == 0:
            QMessageBox.information(None, '提示', '请至少选择一个分析方法')
            return

        self.__selector_list = selector_list
        self.__analyzer_list = analyzer_list
        self.__result_output = output_path

        self.execute_update_task()

    def on_timer(self):
        for i in range(self.__table_analyzer.RowCount()):
            uuid = self.__table_analyzer.GetItemText(i, 3)
            if self.__progress_rate.has_progress(uuid):
                rate = self.__progress_rate.get_progress_rate(uuid)
                self.__table_analyzer.SetItemText(i, 4,
                                                  '%.2f%%' % (rate * 100))
            else:
                self.__table_analyzer.SetItemText(i, 4, '')

    def closeEvent(self, event):
        if self.__task_thread is not None:
            QMessageBox.information(
                self, QtCore.QCoreApplication.translate('', '无法关闭窗口'),
                QtCore.QCoreApplication.translate('', '策略运行过程中无法关闭此窗口'),
                QMessageBox.Close, QMessageBox.Close)
            event.ignore()
        else:
            event.accept()

    # --------------------------------------------------------------------------------------

    def update_selector(self):
        self.__table_selector.Clear()
        self.__table_selector.SetRowCount(0)
        self.__table_selector.SetColumn(AnalyzerUi.TABLE_HEADER_SELECTOR)

        self.__table_selector.AppendRow(
            ['', '所有股票', '当前只支持所有股票,不选默认也是所有股票', '-'])

        # Add check box
        # check_item = QTableWidgetItem()
        # check_item.setCheckState(QtCore.Qt.Unchecked)
        # self.__table_selector.setItem(0, 0, check_item)

    def update_analyzer(self):
        self.__table_analyzer.Clear()
        self.__table_analyzer.SetRowCount(0)
        self.__table_analyzer.SetColumn(AnalyzerUi.TABLE_HEADER_ANALYZER)

        for method_uuid, method_name, method_detail, _ in self.__analyzer_info:
            line = [
                '',  # Place holder for check box
                method_name,
                method_detail,
                method_uuid,
                '',  # Place holder for status
            ]
            self.__table_analyzer.AppendRow(line)
            # index = self.__table_analyzer.RowCount() - 1

            # Add check box
            # check_item = QTableWidgetItem()
            # check_item.setCheckState(QtCore.Qt.Unchecked)
            # self.__table_analyzer.setItem(index, 0, check_item)

    # --------------------------------------------------------------------------

    # def load_analyzer_info(self) -> [(str, str, str)]:
    #     info = []
    #     probs = self.__strategy_entry.strategy_prob()
    #     for prob in probs:
    #         methods = prob.get('methods', [])
    #         for method in methods:
    #             method_uuid = method[0]
    #             method_name = method[1]
    #             method_detail = method[2]
    #             method_entry = method[3]
    #             if method_entry is not None and '测试' not in method_name:
    #                 # Notice the item order
    #                 info.append([method_uuid, method_name, method_detail])
    #     return info

    # --------------------------------- Thread ---------------------------------

    def execute_update_task(self):
        options = AnalysisTask.OPTION_CALC

        if not self.__check_force_calc.isChecked():
            options |= AnalysisTask.OPTION_FROM_CACHE

        if self.__check_auto_cache.isChecked():
            options |= AnalysisTask.OPTION_UPDATE_CACHE

        if self.__check_load_json.isChecked():
            options |= AnalysisTask.OPTION_LOAD_JSON
        if self.__check_dump_json.isChecked():
            options |= AnalysisTask.OPTION_DUMP_JSON
        if self.__check_load_dump_all.isChecked():
            options |= AnalysisTask.OPTION_LOAD_DUMP_ALL

        if self.__check_attach_basic_index.isChecked():
            options |= AnalysisTask.OPTION_ATTACH_BASIC_INDEX

        time_serial = (to_py_datetime(self.__datetime_time_since.dateTime()),
                       to_py_datetime(self.__datetime_time_until.dateTime()))

        self.__timing_clock.reset()
        task = AnalysisTask(self, self.__strategy_entry, self.__data_hub_entry,
                            self.__selector_list, self.__analyzer_list,
                            time_serial, options, self.__result_output,
                            self.__progress_rate)
        StockAnalysisSystem().get_task_queue().append_task(task)

        # if self.__task_thread is None:
        #     self.__task_thread = threading.Thread(target=self.ui_task)
        #     StockAnalysisSystem().lock_sys_quit()
        #     self.__timing_clock.reset()
        #     self.__task_thread.start()
        # else:
        #     print('Task already running...')
        #     QMessageBox.information(self,
        #                             QtCore.QCoreApplication.translate('', '无法执行'),
        #                             QtCore.QCoreApplication.translate('', '已经有策略在运行中,无法同时运行多个策略'),
        #                             QMessageBox.Close, QMessageBox.Close)

    # def ui_task(self):
    #     print('Strategy task start.')
    #
    #     self.__lock.acquire()
    #     selector_list = self.__selector_list
    #     analyzer_list = self.__analyzer_list
    #     output_path = self.__result_output
    #     self.__lock.release()
    #
    #     data_utility = self.__data_hub_entry.get_data_utility()
    #     stock_list = data_utility.get_stock_identities()
    #
    #     self.__progress_rate.reset()
    #
    #     # ------------- Run analyzer -------------
    #     clock = Clock()
    #
    #     # result = self.__strategy_entry.run_strategy(stock_list, analyzer_list, progress=self.__progress_rate)
    #
    #     total_result = []
    #     uncached_analyzer = []
    #
    #     for analyzer in analyzer_list:
    #         result = self.__strategy_entry.result_from_cache('Result.Analyzer', analyzer=analyzer)
    #         if result is None or len(result) == 0:
    #             uncached_analyzer.append(analyzer)
    #             result = self.__strategy_entry.run_strategy(stock_list, [analyzer], progress=self.__progress_rate)
    #         else:
    #             self.__progress_rate.finish_progress(analyzer)
    #         if result is not None and len(result) > 0:
    #             total_result.extend(result)
    #
    #     # DEBUG: Load result from json file
    #     # result = None
    #     # with open('analysis_result.json', 'rt') as f:
    #     #     result = analysis_results_from_json(f)
    #     # if result is None:
    #     #     return
    #
    #     print('Analysis time spending: ' + str(clock.elapsed_s()) + ' s')
    #
    #     # # DEBUG: Dump result to json file
    #     # with open('analysis_result.json', 'wt') as f:
    #     #     analysis_results_to_json(result, f)
    #
    #     # self.__strategy_entry.cache_analysis_result('Result.Analyzer', result)
    #     result2 = self.__strategy_entry.result_from_cache('Result.Analyzer')
    #     print(result2)
    #
    #     result = analysis_result_dataframe_to_list(result2)
    #     print(result)
    #
    #     # ------------ Parse to Table ------------
    #
    #     result_table = analysis_result_list_to_analyzer_security_table(result)
    #
    #     # ----------- Generate report ------------
    #     clock.reset()
    #     stock_list = self.__data_hub_entry.get_data_utility().get_stock_list()
    #     stock_dict = {_id: _name for _id, _name in stock_list}
    #     name_dict = self.__strategy_entry.strategy_name_dict()
    #     generate_analysis_report(result_table, output_path, name_dict, stock_dict)
    #     print('Generate report time spending: ' + str(clock.elapsed_s()) + ' s')
    #
    #     # ----------------- End ------------------
    #     self.task_finish_signal.emit()
    #     print('Update task finished.')

    # ---------------------------------------------------------------------------------

    def notify_task_done(self):
        self.task_finish_signal.emit()

    def __on_task_done(self):
        StockAnalysisSystem().release_sys_quit()
        QMessageBox.information(
            self, QtCore.QCoreApplication.translate('main', '远行完成'),
            QtCore.QCoreApplication.translate(
                'main', '策略运行完成,耗时' + str(self.__timing_clock.elapsed_s()) +
                '秒\n' + '报告生成路径:' + self.__result_output), QMessageBox.Ok,
            QMessageBox.Ok)
Exemplo n.º 6
0
class AnalyzerSelector(QDialog):
    TABLE_HEADER_ANALYZER = ['', 'Strategy', 'Comments', 'UUID']

    def __init__(self, analyzer_utility):
        super(AnalyzerSelector, self).__init__()
        self.__analyzer_utility = analyzer_utility
        self.__ok = True
        self.__table_analyzer = TableViewEx()
        self.__button_ok = QPushButton('OK')
        self.__button_cancel = QPushButton('Cancel')
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()
        self.setLayout(layout)

        layout.addWidget(self.__table_analyzer)
        layout.addLayout(
            horizon_layout(
                [QLabel(''), self.__button_ok, self.__button_cancel],
                [8, 1, 1]))

        self.__table_analyzer.SetCheckableColumn(0)
        self.__table_analyzer.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)

        self.__button_ok.clicked.connect(self.__on_button_ok)
        self.__button_cancel.clicked.connect(self.__on_button_cancel)

        self.setMinimumSize(800, 600)
        self.setWindowTitle('Select Analyzer')

        self.load_analyzer()

    def __on_button_ok(self):
        self.__ok = True
        self.close()

    def __on_button_cancel(self):
        self.close()

    def is_ok(self) -> bool:
        return self.__ok

    def load_analyzer(self):
        self.__table_analyzer.Clear()
        self.__table_analyzer.SetRowCount(0)
        self.__table_analyzer.SetColumn(AnalyzerSelector.TABLE_HEADER_ANALYZER)

        analyzer_info = self.__analyzer_utility.analyzer_info()
        for analyzer_uuid, analyzer_name, analyzer_detail, _ in analyzer_info:
            self.__table_analyzer.AppendRow(
                ['', analyzer_name, analyzer_detail, analyzer_uuid])

    def get_select_strategy(self):
        analyzer_list = []
        for i in range(self.__table_analyzer.RowCount()):
            if self.__table_analyzer.GetItemCheckState(i,
                                                       0) == QtCore.Qt.Checked:
                uuid = self.__table_analyzer.GetItemText(i, 3)
                analyzer_list.append(uuid)
        return analyzer_list
Exemplo n.º 7
0
class StockMemoDeck(QWidget):
    STATIC_HEADER = ['Code', 'Name']

    def __init__(self, memo_data: StockMemoData):
        super(StockMemoDeck, self).__init__()
        self.__memo_data = memo_data

        if self.__memo_data is not None:
            self.__memo_data.add_observer(self)

            self.__sas = self.__memo_data.get_sas()
            self.__memo_record: StockMemoRecord = self.__memo_data.get_memo_record(
            )
            self.__memo_editor: StockMemoEditor = self.__memo_data.get_data(
                'editor')
            self.__data_utility = self.__sas.get_data_hub_entry(
            ).get_data_utility() if self.__sas is not None else None
        else:
            # For layout debug
            self.__sas = None
            self.__memo_record = None
            self.__memo_editor = None
            self.__data_utility = None

        self.__memo_extras = []
        self.__list_securities = []
        self.__show_securities = []

        # ---------------- Page -----------------

        self.__page = 1
        self.__item_per_page = 20

        self.__button_first = QPushButton('|<')
        self.__button_prev = QPushButton('<')
        self.__spin_page = QSpinBox()
        self.__label_total_page = QLabel('/ 1')
        self.__button_jump = QPushButton('GO')
        self.__button_next = QPushButton('>')
        self.__button_last = QPushButton('>|')

        self.__button_reload = QPushButton('Reload')
        self.__check_show_black_list = QCheckBox('Black List')

        # --------------- Widgets ---------------

        self.__memo_table = TableViewEx()
        self.__stock_selector = \
            SecuritiesSelector(self.__data_utility) if self.__data_utility is not None else QComboBox()
        self.__line_path = QLineEdit(self.__memo_data.get_root_path() if self.
                                     __memo_data is not None else root_path)
        self.__info_panel = QLabel(NOTE)
        self.__button_new = QPushButton('New')
        self.__button_filter = QPushButton('Filter')
        self.__button_browse = QPushButton('Browse')
        # self.__button_black_list = QPushButton('Black List')

        self.__layout_extra = QHBoxLayout()

        self.init_ui()
        self.config_ui()

        self.show_securities(self.__memo_record.get_all_security() if self.
                             __memo_record is not None else [])

    def init_ui(self):
        main_layout = QVBoxLayout()
        self.setLayout(main_layout)

        # Page control
        page_control_line = QHBoxLayout()
        page_control_line.addWidget(self.__button_reload, 1)
        page_control_line.addWidget(self.__check_show_black_list, 1)

        page_control_line.addWidget(QLabel(''), 99)
        page_control_line.addWidget(self.__button_first, 1)
        page_control_line.addWidget(self.__button_prev, 1)
        page_control_line.addWidget(self.__spin_page, 1)
        page_control_line.addWidget(self.__label_total_page, 1)
        page_control_line.addWidget(self.__button_jump, 1)
        page_control_line.addWidget(self.__button_next, 1)
        page_control_line.addWidget(self.__button_last, 1)

        group_box, group_layout = create_v_group_box('Stock Memo')
        group_layout.addWidget(self.__memo_table)
        group_layout.addLayout(page_control_line)
        main_layout.addWidget(group_box, 10)

        group_box, group_layout = create_h_group_box('Edit')
        right_area = QVBoxLayout()
        group_layout.addWidget(self.__info_panel, 4)
        group_layout.addLayout(right_area, 6)

        line = horizon_layout([
            QLabel('股票选择:'), self.__stock_selector, self.__button_filter,
            self.__button_new
        ], [1, 10, 1, 1])
        right_area.addLayout(line)

        line = horizon_layout(
            [QLabel('保存路径:'), self.__line_path, self.__button_browse],
            [1, 10, 1])
        right_area.addLayout(line)

        # line = horizon_layout([QLabel('其它功能:'), self.__button_black_list, QLabel('')],
        #                       [1, 1, 10])

        self.__layout_extra.addWidget(QLabel('其它功能:'))
        self.__layout_extra.addStretch()
        right_area.addLayout(self.__layout_extra)

        main_layout.addWidget(group_box, 1)

    def config_ui(self):
        self.setMinimumSize(800, 600)
        self.__info_panel.setWordWrap(True)

        # -------------- Page Control --------------

        self.__button_first.clicked.connect(
            partial(self.__on_page_control, '|<'))
        self.__button_prev.clicked.connect(partial(self.__on_page_control,
                                                   '<'))
        self.__button_jump.clicked.connect(partial(self.__on_page_control,
                                                   'g'))
        self.__button_next.clicked.connect(partial(self.__on_page_control,
                                                   '>'))
        self.__button_last.clicked.connect(
            partial(self.__on_page_control, '>|'))

        self.__button_reload.clicked.connect(self.__on_button_reload)

        self.__check_show_black_list.setChecked(False)
        self.__check_show_black_list.clicked.connect(
            self.__on_check_show_black_list)

        self.__memo_table.SetColumn(self.__memo_table_columns())
        self.__memo_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.__memo_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.__memo_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.__memo_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.__memo_table.doubleClicked.connect(
            self.__on_memo_item_double_clicked)

        self.__button_new.clicked.connect(self.__on_button_new_clicked)
        self.__button_browse.clicked.connect(self.__on_button_browse)
        self.__button_filter.clicked.connect(self.__on_button_filter_clicked)

        self.__button_filter.setDefault(True)
        line_editor = self.__stock_selector.lineEdit()
        if line_editor is not None:
            line_editor.returnPressed.connect(self.__on_button_filter_clicked)

    def add_memo_extra(self, extra: MemoExtra):
        extra.set_memo_ui(self)
        self.__memo_extras.append(extra)

        global_entry_text = extra.global_entry_text()
        if str_available(global_entry_text):
            button = QPushButton(global_entry_text)
            button.clicked.connect(
                partial(self.__on_button_global_entry, extra))
            self.__layout_extra.insertWidget(1, button)

    def update_list(self):
        self.__update_memo_securities_list()

    def show_securities(self, securities: [str]):
        self.__update_securities(securities)
        self.__update_memo_securities_list()

    # ------------------- Interface of StockMemoData.Observer --------------------

    # def on_memo_updated(self):
    #     self.update_list()

    def on_data_updated(self, name: str, data: any):
        nop(data)
        if name in ['memo_record', 'tags']:
            self.update_list()

    # ----------------------------------------------------------------------------

    def __on_page_control(self, button_mark: str):
        new_page = self.__page
        if button_mark == '|<':
            new_page = 0
        elif button_mark == '<':
            new_page -= 1
        elif button_mark == 'g':
            new_page = self.__spin_page.value()
        elif button_mark == '>':
            new_page += 1
        elif button_mark == '>|':
            new_page = self.__max_page()

        new_page = max(1, new_page)
        new_page = min(self.__max_page(), new_page)

        if self.__page != new_page:
            self.__page = new_page
            self.__spin_page.setValue(self.__page)
            self.update_list()

    def __on_button_browse(self):
        folder = str(
            QFileDialog.getExistingDirectory(
                self,
                "Select Private Folder",
                directory=self.__line_path.text()))
        if folder == '':
            return
        self.__line_path.setText(folder)

        # Save to system config
        self.__sas.get_config().set('memo_path', folder)
        self.__sas.get_config().save_config()

        # Update new path to memo extras
        self.__memo_data.set_root_path(folder)

        # TODO: Auto handle path update
        stock_tags: Tags = self.__memo_data.get_data('tags')
        if stock_tags is not None:
            stock_tags.load(os.path.join(folder, 'tags.json'))
        self.__memo_data.get_memo_record().load(
            os.path.join(folder, 'stock_memo.csv'))

    def __on_button_new_clicked(self):
        security = self.__stock_selector.get_input_securities()
        self.__memo_editor.select_security(security)
        self.__memo_editor.create_new_memo(now())
        self.__memo_editor.exec()

    def __on_button_filter_clicked(self):
        input_security = self.__stock_selector.get_input_securities()
        list_securities = self.__data_utility.guess_securities(input_security)
        self.show_securities(list_securities)

    def __on_button_reload(self):
        self.show_securities(self.__memo_record.get_all_security() if self.
                             __memo_record is not None else [])

    def __on_check_show_black_list(self):
        self.__update_securities()
        self.__update_memo_securities_list()

    def __on_memo_item_double_clicked(self, index: QModelIndex):
        item_data = index.data(Qt.UserRole)
        if item_data is not None and isinstance(item_data, tuple):
            memo_extra, security = item_data
            memo_extra.security_entry(security)
            # print('Double Click on memo item: %s - %s' % (memo_extra.title_text(), security))

    def __on_button_global_entry(self, extra: MemoExtra):
        extra.global_entry()

    def __update_memo_securities_list(self, securities: [str] or None = None):
        if securities is None:
            securities = self.__show_securities

        columns = self.__memo_table_columns()

        self.__memo_table.Clear()
        self.__memo_table.SetColumn(columns)

        index = []
        offset = (self.__page - 1) * self.__item_per_page

        for i in range(offset, offset + self.__item_per_page):
            if i < 0 or i >= len(securities):
                continue
            security = securities[i]
            index.append(str(i + 1))

            self.__memo_table.AppendRow([''] * len(columns))
            row_count = self.__memo_table.RowCount()
            row = row_count - 1

            col = 0
            self.__memo_table.SetItemText(row, col, security)
            self.__memo_table.SetItemData(row, col, security)

            col = 1
            self.__memo_table.SetItemText(
                row, col, self.__data_utility.stock_identity_to_name(security))

            for memo_extra in self.__memo_extras:
                if not str_available(memo_extra.title_text()):
                    continue

                col += 1
                text = memo_extra.security_entry_text(security)

                self.__memo_table.SetItemText(row, col, text)
                self.__memo_table.SetItemData(row, col, (memo_extra, security))

                # _item = self.__memo_table.GetItem(row, col)
                # _item.clicked.connect(partial(self.__on_memo_item_clicked, _item, security, memo_extra))

        model = self.__memo_table.model()
        model.setVerticalHeaderLabels(index)

    def __update_securities(self, list_securities: [str] or None = None):
        if list_securities is None:
            # Just refresh the show securities
            pass
        else:
            self.__list_securities = list_securities \
                if isinstance(list_securities, (list, tuple)) else [list_securities]
        self.__update_show_securities()
        self.__update_page_control()

    def __update_show_securities(self):
        self.__show_securities = self.__list_securities

        show_black_list = self.__check_show_black_list.isChecked()
        if not show_black_list:
            black_list: BlackList = self.__memo_data.get_data('black_list')
            if black_list is not None:
                black_list_securities = black_list.all_black_list()
                self.__show_securities = list(
                    set(self.__show_securities).difference(
                        set(black_list_securities)))

    def __memo_table_columns(self) -> [str]:
        return StockMemoDeck.STATIC_HEADER + [
            memo_extra.title_text() for memo_extra in self.__memo_extras
            if str_available(memo_extra.title_text())
        ]

    def __max_page(self) -> int:
        return (len(self.__show_securities) + self.__item_per_page -
                1) // self.__item_per_page

    def __update_page_control(self):
        self.__page = 1
        max_page = self.__max_page()
        self.__spin_page.setValue(1)
        self.__spin_page.setMinimum(1)
        self.__spin_page.setMaximum(max_page)
        self.__label_total_page.setText('/ %s' % max_page)
Exemplo n.º 8
0
class DataUpdateUi(QWidget, TaskQueue.Observer):
    task_finish_signal = pyqtSignal([UpdateTask])
    refresh_finish_signal = pyqtSignal()

    INDEX_CHECK = 0
    INDEX_ITEM = 1
    INDEX_STATUS = 8
    TABLE_HEADER = [
        '', 'Item', 'Local Data Since', 'Local Data Until', 'Latest Update',
        'Update Estimation', 'Sub Update', 'Update', 'Status'
    ]

    def get_uri_sub_update(self, uri: str) -> list or None:
        agent = self.__data_hub.get_data_center().get_data_agent(uri)
        if agent is not None:
            return agent.update_list()
        else:
            print('Error: Agent of URI %s is None.' % uri)

    def __init__(self, data_hub_entry: DataHubEntry,
                 update_table: UpdateTableEx):
        super(DataUpdateUi, self).__init__()

        # Access entry
        self.__data_hub = data_hub_entry
        self.__data_center = self.__data_hub.get_data_center()
        self.__update_table = update_table

        # Table content
        self.__display_uri = []
        self.__display_identities = None
        self.__display_table_lines = []

        # Page related
        self.__page = 0
        self.__item_per_page = 20

        # For processing updating
        self.__processing_update_tasks = []
        # Fot task counting
        self.__processing_update_tasks_count = []

        self.task_finish_signal.connect(self.__on_task_done)
        self.refresh_finish_signal.connect(self.update_table_display)

        # Timer for update status
        self.__timer = QTimer()
        self.__timer.setInterval(1000)
        self.__timer.timeout.connect(self.on_timer)
        self.__timer.start()

        # UI related
        self.__info_panel = QLabel(DEFAULT_INFO)

        self.__table_main = TableViewEx()
        self.__button_head_page = QPushButton('<<')
        self.__button_prev_page = QPushButton('<')
        self.__button_next_page = QPushButton('>')
        self.__button_tail_page = QPushButton('>>')
        self.__button_upper_level = QPushButton('↑')

        self.__button_refresh = QPushButton('Refresh')
        self.__button_batch_auto_update = QPushButton('Auto Update Select')
        self.__button_batch_force_update = QPushButton('Force Update Select')

        self.init_ui()

        # Post update and cache stock list after posting RefreshTask
        data_utility = self.__data_hub.get_data_utility()
        StockAnalysisSystem().get_task_queue().add_observer(self)
        StockAnalysisSystem().get_task_queue().append_task(
            UpdateStockListTask(data_utility))

    # ---------------------------------------------------- UI Init -----------------------------------------------------

    def init_ui(self):
        self.__layout_control()
        self.__config_control()
        self.__to_top_level()

    def __layout_control(self):
        main_layout = QVBoxLayout()
        self.setLayout(main_layout)
        self.setMinimumSize(600, 400)
        main_layout.addWidget(self.__table_main)

        bottom_control_area = QHBoxLayout()
        main_layout.addLayout(bottom_control_area)

        bottom_right_area = QVBoxLayout()
        bottom_control_area.addWidget(self.__info_panel, 99)
        bottom_control_area.addLayout(bottom_right_area, 0)

        line = horizon_layout([
            self.__button_head_page, self.__button_prev_page,
            self.__button_next_page, self.__button_tail_page,
            self.__button_upper_level, self.__button_refresh
        ])
        bottom_right_area.addLayout(line)

        line = horizon_layout([
            self.__button_batch_auto_update, self.__button_batch_force_update
        ])
        bottom_right_area.addLayout(line)

    def __config_control(self):
        self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER)
        self.__table_main.SetCheckableColumn(DataUpdateUi.INDEX_CHECK)
        self.__table_main.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)

        self.__button_head_page.clicked.connect(
            partial(self.on_page_control, '<<'))
        self.__button_prev_page.clicked.connect(
            partial(self.on_page_control, '<'))
        self.__button_next_page.clicked.connect(
            partial(self.on_page_control, '>'))
        self.__button_tail_page.clicked.connect(
            partial(self.on_page_control, '>>'))
        self.__button_upper_level.clicked.connect(
            partial(self.on_page_control, '^'))
        self.__button_refresh.clicked.connect(
            partial(self.on_page_control, 'r'))

        self.__button_batch_auto_update.clicked.connect(
            partial(self.on_batch_update, False))
        self.__button_batch_force_update.clicked.connect(
            partial(self.on_batch_update, True))

    def on_detail_button(self, uri: str):
        print('Detail of ' + uri)
        self.__page = 0
        self.__to_detail_level(uri)

    def on_auto_update_button(self, uri: str, identity: str):
        print('Auto update ' + uri + ':' + str(identity))
        self.__build_post_update_task(uri, identity, False)

    def on_force_update_button(self, uri: str, identity: str):
        print('Force update ' + uri + ' : ' + str(identity))
        self.__build_post_update_task(uri, identity, True)

    def on_batch_update(self, force: bool):
        for i in range(self.__table_main.RowCount()):
            if self.__table_main.GetItemCheckState(
                    i, DataUpdateUi.INDEX_CHECK) == Qt.Checked:
                item_id = self.__table_main.GetItemText(
                    i, DataUpdateUi.INDEX_ITEM)
                # A little ugly...To distinguish it's uri or securities ideneity
                if self.__display_identities is None:
                    self.__build_post_update_task(item_id, None, force)
                else:
                    self.__build_post_update_task(self.__display_uri[0],
                                                  item_id, force)

    def on_page_control(self, control: str):
        # data_utility = self.__data_hub.get_data_utility()
        # stock_list = data_utility.get_stock_list()
        # max_page = len(stock_list) // self.__item_per_page

        if self.__display_identities is None:
            max_item_count = len(self.__display_uri)
        else:
            max_item_count = len(self.__display_identities)
        max_page = max_item_count // self.__item_per_page

        new_page = self.__page
        if control == '<<':
            new_page = 0
        elif control == '<':
            new_page = max(self.__page - 1, 0)
        elif control == '>':
            new_page = min(self.__page + 1, max_page)
        elif control == '>>':
            new_page = max_page
        elif control == '^':
            self.__to_top_level()

        if control in ['<<', '<', '>', '>>', 'r']:
            if control == 'r' or new_page != self.__page:
                self.update_table()
                self.__page = new_page

    def on_timer(self):
        for i in range(self.__table_main.RowCount()):
            item_id = self.__table_main.GetItemText(i, DataUpdateUi.INDEX_ITEM)
            # A little ugly...To distinguish it's uri or securities identity
            if self.__display_identities is None:
                uri = item_id
                prog_id = uri
            else:
                uri = self.__display_uri[0]
                prog_id = [uri, item_id]
            for task in self.__processing_update_tasks:
                if not task.in_work_package(uri):
                    continue
                text = []
                if task.status() in [
                        TaskQueue.Task.STATUS_IDLE,
                        TaskQueue.Task.STATUS_PENDING
                ]:
                    text.append('等待中...')
                else:
                    if task.progress.has_progress(prog_id):
                        rate = task.progress.get_progress_rate(prog_id)
                        text.append('%ss' % task.clock.elapsed_s())
                        text.append('%.2f%%' % (rate * 100))
                    if task.status() == TaskQueue.Task.STATUS_CANCELED:
                        text.append('[Canceled]')
                    elif task.status() == TaskQueue.Task.STATUS_FINISHED:
                        text.append('[Finished]')
                    elif task.status() == TaskQueue.Task.STATUS_EXCEPTION:
                        text.append('[Error]')
                self.__table_main.SetItemText(i, DataUpdateUi.INDEX_STATUS,
                                              ' | '.join(text))
                break

    # def closeEvent(self, event):
    #     if self.__task_thread is not None:
    #         QMessageBox.information(self,
    #                                 QtCore.QCoreApplication.translate('', '无法关闭窗口'),
    #                                 QtCore.QCoreApplication.translate('', '更新过程中无法关闭此窗口'),
    #                                 QMessageBox.Close, QMessageBox.Close)
    #         event.ignore()
    #     else:
    #         event.accept()

    # ---------------------------------------- Table Update ----------------------------------------

    def update_table(self):
        self.__table_main.Clear()
        self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER)
        self.__table_main.AppendRow(['', '刷新中...', '', '', '', '', '', '', ''])
        task = RefreshTask(self)
        StockAnalysisSystem().get_task_queue().append_task(task)

    def update_table_display(self):
        self.__table_main.Clear()
        self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER)

        for line in self.__display_table_lines:
            self.__table_main.AppendRow(line)
            index = self.__table_main.RowCount() - 1

            # Add detail button
            # Only if currently in top level
            if self.__display_identities is None or len(
                    self.__display_identities) == 0:
                uri = line[1]
                agent = self.__data_center.get_data_agent(uri)
                if agent is not None and len(agent.update_list()) > 0:
                    button = QPushButton('Enter')
                    button.clicked.connect(
                        partial(self.on_detail_button, line[1]))
                    self.__table_main.SetCellWidget(index, 6, button)

            # Add update button
            button_auto = QPushButton('Auto')
            button_force = QPushButton('Force')
            if self.__display_identities is None:
                button_auto.clicked.connect(
                    partial(self.on_auto_update_button, line[1], None))
                button_force.clicked.connect(
                    partial(self.on_force_update_button, line[1], None))
            else:
                button_auto.clicked.connect(
                    partial(self.on_auto_update_button, self.__display_uri[0],
                            line[1]))
                button_force.clicked.connect(
                    partial(self.on_force_update_button, self.__display_uri[0],
                            line[1]))
            self.__table_main.SetCellWidget(index, 7,
                                            [button_auto, button_force])

    def update_table_content(self):
        contents = []
        count = self.__item_per_page
        offset = self.__page * self.__item_per_page

        for uri in self.__display_uri:
            update_details = self.__display_identities if \
                self.__display_identities is not None else [None]
            for index in range(offset, offset + count):
                if index >= len(update_details):
                    break
                line = self.generate_line_content(uri, update_details[index])
                if line is not None:
                    contents.append(line)
        self.__display_table_lines = contents

    def generate_line_content(self, uri: str, identity: str
                              or None) -> [list] or None:
        line = []

        agent = self.__data_center.get_data_agent(uri)
        update_table = self.__update_table

        if agent is None:
            return None

        update_tags = uri.split('.') + ([identity]
                                        if identity is not None else [])
        since, until = update_table.get_since_until(update_tags)

        if since is None or until is None:
            # TODO: Workaround - because each stock storage in each table.
            # So we cannot fetch its time range with this method.
            since, until = agent.data_range(uri, identity)
        if until is not None:
            update_since = min(tomorrow_of(until), now())
            update_until = now()
        else:
            update_since, update_until = self.__data_center.calc_update_range(
                uri, identity)

        update_tags = uri.split('.')
        latest_update = self.__update_table.get_last_update_time(update_tags)

        line.append('')  # Place holder for check box
        line.append(identity if str_available(identity) else uri)
        line.append(date2text(since) if since is not None else ' - ')
        line.append(date2text(until) if until is not None else ' - ')
        line.append(
            date2text(latest_update) if latest_update is not None else ' - ')

        if update_since is not None and update_until is not None:
            line.append(
                date2text(update_since) + ' - ' + date2text(update_until))
        else:
            line.append(' - ')
        line.append('-')  # Place holder for detail button
        line.append('')  # Place holder for update button
        line.append('')  # Place holder for status

        return line

    # --------------------------------------------------------------------------

    def __to_top_level(self):
        # Temporary exclude Factor related data
        support_uri = self.__data_center.get_all_uri()
        self.__display_uri = [
            uri for uri in support_uri if 'Factor' not in uri
        ]
        self.__display_identities = None
        self.__page = 0
        self.update_table()

    def __to_detail_level(self, uri: str):
        self.__display_uri = [uri]
        self.__display_identities = self.get_uri_sub_update(uri)
        self.__page = 0
        self.update_table()

    def __build_post_update_task(self, uri: str, identities: list or None,
                                 force: bool) -> bool:
        agent = self.__data_center.get_data_agent(uri)
        task = UpdateTask(self, self.__data_hub, self.__data_center, force)
        task.set_work_package(agent, identities)
        self.__processing_update_tasks.append(task)
        self.__processing_update_tasks_count.append(task)
        ret = StockAnalysisSystem().get_task_queue().append_task(task)
        # After updating market info, also update stock list cache
        if ret and (uri == 'Market.SecuritiesInfo'
                    or uri == 'Market.IndexInfo'):
            data_utility = self.__data_hub.get_data_utility()
            StockAnalysisSystem().get_task_queue().append_task(
                UpdateStockListTask(data_utility))
        return ret

    # ---------------------------------------------------------------------------------

    def on_task_updated(self, task, change: str):
        if change in ['canceled', 'finished']:
            if task in self.__processing_update_tasks_count:
                self.task_finish_signal[UpdateTask].emit(task)

    def __on_task_done(self, task: UpdateTask):
        if task in self.__processing_update_tasks_count:
            self.__processing_update_tasks_count.remove(task)
            print('Finish task: %s, remaining count: %s' %
                  (task.name(), len(self.__processing_update_tasks_count)))
            if len(self.__processing_update_tasks_count) == 0:
                QMessageBox.information(
                    self, QtCore.QCoreApplication.translate('main', '更新完成'),
                    QtCore.QCoreApplication.translate('main', '数据更新完成'),
                    QMessageBox.Ok, QMessageBox.Ok)
                self.__processing_update_tasks.clear()
                self.update_table()
        else:
            print('Impossible: Cannot find finished task in task list.')