def __init__(self): """Create our windgets. """ super().__init__() layout = QVBoxLayout() # For our "uptime" timer. self.start_time = time.time() # Label for our progress bar. bar_label = QLabel("Draw Time:") layout.addWidget(bar_label) # Progress bar is not used for "progress", it's just a bar graph to show # the "draw time", the duration of the "UpdateRequest" event. bar = QProgressBar() bar.setRange(0, 100) bar.setValue(50) bar.setFormat("%vms") layout.addWidget(bar) self.bar = bar # We let the user set the "slow event" threshold. self.thresh_ms = self.THRESH_DEFAULT self.thresh_combo = QComboBox() self.thresh_combo.addItems(self.THRESH_OPTIONS) self.thresh_combo.activated[str].connect(self._change_thresh) self.thresh_combo.setCurrentText(str(self.thresh_ms)) combo_layout = QHBoxLayout() combo_layout.addWidget(QLabel("Show Events Slower Than:")) combo_layout.addWidget(self.thresh_combo) combo_layout.addWidget(QLabel("milliseconds")) combo_layout.addItem( QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) ) layout.addLayout(combo_layout) # We log slow events to this window. self.log = TextLog() layout.addWidget(self.log) # Uptime label. To indicate if the widget is getting updated. label = QLabel('') layout.addWidget(label) self.timer_label = label self.setLayout(layout) # Update us with a timer. self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.timer.setInterval(self.UPDATE_MS) self.timer.start()
class MemoryView(QWidget): set_value = Signal(int, float, float) """ Initializes and updates the view of memory(progress) bar. """ def __init__(self, parent): super(MemoryView, self).__init__(parent) self.critical = CRITICAL_PERCENTAGE self.memory_bar = QProgressBar(self) self.memory_bar.setAlignment(Qt.AlignCenter) self.set_value.connect(self._set_value) def set_bar_color(self, current_value: int, new_value: int): """ Updates the memory(progress) bar style if needed :param current_value: Used system memory in percentage from previous update :param new_value: Latest used system memory in percentage """ if from_normal_to_critical(self.critical, current_value, new_value): self.memory_bar.setStyleSheet(CRITICAL_STYLE) elif from_critical_to_normal(self.critical, current_value, new_value): self.memory_bar.setStyleSheet(NORMAL_STYLE) else: pass def invoke_set_value(self, new_value: int, mem_used: float, mem_avail: float): self.set_value.emit(new_value, mem_used, mem_avail) @Slot(int, float, float) def _set_value(self, new_value, mem_used, mem_avail): """ Receives memory usage information passed by memory presenter and updates the displayed content as well as the style if needed :param new_value: Latest used system memory in percentage :param mem_used: Used system memory in Gigabytes(GB) :param mem_avail: Available system memory in GB """ # newValue is the latest mem_used_percent current_value = self.memory_bar.value() if current_value == new_value: return self.set_bar_color(current_value, new_value) self.memory_bar.setValue(new_value) display_str = f"{mem_used:3.1f}/{mem_avail:3.1f} GB ({new_value:d}%)" self.memory_bar.setFormat(display_str)
class GcodeBackplot(QBackPlot): line_selected = Signal(int) gcode_error = Signal(str) def __init__(self, parent=None, standalone=False): super(GcodeBackplot, self).__init__(parent) # This prevents doing unneeded initialization # when QtDesginer loads the plugin. if parent is None and not standalone: return self.show_overlay = False # no DRO or DRO overlay self.program_alpha = True self.grid_size = 1 self._reload_filename = None # Add loading progress bar and abort button self.progressBar = QProgressBar(visible=False) self.progressBar.setFormat("Loading backplot: %p%") self.abortButton = QPushButton('Abort', visible=False) hBox = QHBoxLayout() hBox.addWidget(self.progressBar) hBox.addWidget(self.abortButton) vBox = QVBoxLayout(self) vBox.addStretch() vBox.addLayout(hBox) self.abortButton.clicked.connect(self.abort) STATUS.actual_position.onValueChanged(self.update) STATUS.joint_actual_position.onValueChanged(self.update) STATUS.homed.onValueChanged(self.update) STATUS.limit.onValueChanged(self.update) STATUS.tool_in_spindle.onValueChanged(self.update) STATUS.motion_mode.onValueChanged(self.update) STATUS.current_vel.onValueChanged(self.update) STATUS.g5x_offset.onValueChanged(self.reloadBackplot) STATUS.g92_offset.onValueChanged(self.reloadBackplot) # Connect status signals STATUS.file.notify(self.loadBackplot) # STATUS.reload_backplot.notify(self.reloadBackplot) STATUS.program_units.notify(lambda v: self.setMetricUnits(v == 2)) def loadBackplot(self, fname): LOG.debug('load the display: {}'.format(fname.encode('utf-8'))) self._reload_filename = fname self.load(fname) @Slot() def reloadBackplot(self): QTimer.singleShot(100, lambda: self._reloadBackplot()) def _reloadBackplot(self): LOG.debug('reload the display: {}'.format(self._reload_filename)) dist = self.get_zoom_distance() try: self.load(self._reload_filename) self.set_zoom_distance(dist) except: LOG.warning("Problem reloading backplot file: {}".format(self._reload_filename), exc_info=True) # ========================================================================== # Override QBackPlot methods # ========================================================================== def report_loading_started(self): self.progressBar.show() self.abortButton.show() self.start = time.time() def report_progress_percentage(self, percentage): QApplication.processEvents() self.progressBar.setValue(percentage) def report_loading_finished(self): print((time.time() - self.start)) self.progressBar.hide() self.abortButton.hide() # overriding functions def report_gcode_error(self, result, seq, filename): error = gcode.strerror(result) file = os.path.basename(filename) line = seq - 1 msg = "G-code error in '{}' near line {}: {}".format(file, line, error) LOG.error(msg) STATUS.backplot_gcode_error.emit(msg) # Override gremlin's / glcannon.py function so we can emit a GObject signal def update_highlight_variable(self, line): self.highlight_line = line if line is None: line = -1 STATUS.backplot_line_selected.emit(line) # ============================================================================== # QtDesigner property setters/getters # ============================================================================== @Slot(str) def setView(self, view): view = view.lower() if self.is_lathe: if view not in ['p', 'y', 'y2']: return False elif view not in ['p', 'x', 'y', 'z', 'z2']: return False self.current_view = view if self.initialised: self.set_current_view() def getView(self): return self.current_view defaultView = Property(str, getView, setView) @Slot() def setViewP(self): self.setView('p') @Slot() def setViewX(self): self.setView('x') @Slot() def setViewY(self): self.setView('y') @Slot() def setViewZ(self): self.setView('z') @Slot() def setViewZ2(self): self.setView('z2') @Slot() def clearLivePlot(self): self.clear_live_plotter() @Slot() def zoomIn(self): self.zoomin() @Slot() def zoomOut(self): self.zoomout() @Slot(bool) def alphaBlend(self, alpha): self.program_alpha = alpha self.update() @Slot(bool) def showGrid(self, grid): self.grid_size = int(grid) # ugly hack for now self.update() # @Slot(str) Fixme check for the correct data type def setdro(self, state): self.enable_dro = state self.updateGL() def getdro(self): return self.enable_dro _dro = Property(bool, getdro, setdro) # DTG # @Slot(str) Fixme check for the correct data type def setdtg(self, state): self.show_dtg = state self.updateGL() def getdtg(self): return self.show_dtg _dtg = Property(bool, getdtg, setdtg) # METRIC # @Slot(str) Fixme check for the correct data type def setMetricUnits(self, metric): self.metric_units = metric self.updateGL() def getMetricUnits(self): return self.metric_units metricUnits = Property(bool, getMetricUnits, setMetricUnits) # @Slot(str) Fixme check for the correct data type def setProgramAlpha(self, alpha): self.program_alpha = alpha self.updateGL() def getProgramAlpha(self): return self.program_alpha renderProgramAlpha = Property(bool, getProgramAlpha, setProgramAlpha) # @Slot(str) Fixme check for the correct data type def setBackgroundColor(self, color): self.colors['back'] = color.getRgbF()[:3] self.updateGL() def getBackgroundColor(self): r, g, b = self.colors['back'] color = QColor() color.setRgbF(r, g, b, 1.0) return color backgroundColor = Property(QColor, getBackgroundColor, setBackgroundColor)
class ProgressView(QWidget): """ :type batch_manager: CalculationManager """ def __init__(self, parent, batch_manager): QWidget.__init__(self, parent) self.calculation_manager = batch_manager self.whole_progress = QProgressBar(self) self.whole_progress.setMinimum(0) self.whole_progress.setMaximum(1) self.whole_progress.setFormat("%v of %m") self.whole_progress.setTextVisible(True) self.part_progress = QProgressBar(self) self.part_progress.setMinimum(0) self.part_progress.setMaximum(1) self.part_progress.setFormat("%v of %m") self.whole_label = QLabel("All batch progress:", self) self.part_label = QLabel("Single batch progress:", self) self.logs = ExceptionList(self) self.logs.setToolTip("Logs") self.task_que = QListWidget() self.process_num_timer = QTimer() self.process_num_timer.setInterval(1000) self.process_num_timer.setSingleShot(True) self.process_num_timer.timeout.connect(self.change_number_of_workers) self.number_of_process = QSpinBox(self) self.number_of_process.setRange(1, multiprocessing.cpu_count()) self.number_of_process.setValue(1) self.number_of_process.setToolTip( "Number of process used in batch calculation") self.number_of_process.valueChanged.connect( self.process_num_timer_start) layout = QGridLayout() layout.addWidget(self.whole_label, 0, 0, Qt.AlignRight) layout.addWidget(self.whole_progress, 0, 1, 1, 2) layout.addWidget(self.part_label, 1, 0, Qt.AlignRight) layout.addWidget(self.part_progress, 1, 1, 1, 2) lab = QLabel("Number of process:") lab.setToolTip("Number of process used in batch calculation") layout.addWidget(lab, 2, 0) layout.addWidget(self.number_of_process, 2, 1) layout.addWidget(self.logs, 3, 0, 1, 3) layout.addWidget(self.task_que, 0, 4, 0, 1) layout.setColumnMinimumWidth(2, 10) layout.setColumnStretch(2, 1) self.setLayout(layout) self.preview_timer = QTimer() self.preview_timer.setInterval(1000) self.preview_timer.timeout.connect(self.update_info) def new_task(self): self.whole_progress.setMaximum( self.calculation_manager.calculation_size) if not self.preview_timer.isActive(): self.update_info() self.preview_timer.start() def update_info(self): res = self.calculation_manager.get_results() for el in res.errors: if el[0]: QListWidgetItem(el[0], self.logs) ExceptionListItem(el[1], self.logs) if (state_store.report_errors and parsed_version.is_devrelease and not isinstance(el[1][0], SegmentationLimitException) and isinstance(el[1][1], tuple)): with sentry_sdk.push_scope() as scope: scope.set_tag("auto_report", "true") sentry_sdk.capture_event(el[1][1][0]) self.whole_progress.setValue(res.global_counter) working_search = True for i, (progress, total) in enumerate(res.jobs_status): if working_search and progress != total: self.part_progress.setMaximum(total) self.part_progress.setValue(progress) working_search = False if i < self.task_que.count(): item = self.task_que.item(i) item.setText("Task {} ({}/{})".format(i, progress, total)) else: self.task_que.addItem("Task {} ({}/{})".format( i, progress, total)) if not self.calculation_manager.has_work: print( "[ProgressView.update_info]", self.calculation_manager.has_work, self.calculation_manager.batch_manager.has_work, self.calculation_manager.writer.writing_finished(), ) self.part_progress.setValue(self.part_progress.maximum()) self.preview_timer.stop() logging.info("Progress stop") def process_num_timer_start(self): self.process_num_timer.start() def update_progress(self, total_progress, part_progress): self.whole_progress.setValue(total_progress) self.part_progress.setValue(part_progress) def set_total_size(self, size): self.whole_progress.setMaximum(size) def set_part_size(self, size): self.part_progress.setMaximum(size) def change_number_of_workers(self): self.calculation_manager.set_number_of_workers( self.number_of_process.value())
class ProgressView(QWidget): """ :type batch_manager: CalculationManager """ def __init__(self, parent, batch_manager): super().__init__(parent) self.task_count = 0 self.calculation_manager = batch_manager self.whole_progress = QProgressBar(self) self.whole_progress.setMinimum(0) self.whole_progress.setMaximum(1) self.whole_progress.setFormat("%v of %m") self.whole_progress.setTextVisible(True) self.part_progress = QProgressBar(self) self.part_progress.setMinimum(0) self.part_progress.setMaximum(1) self.part_progress.setFormat("%v of %m") self.whole_label = QLabel("All batch progress:", self) self.part_label = QLabel("Single batch progress:", self) self.cancel_remove_btn = QPushButton("Remove task") self.cancel_remove_btn.setDisabled(True) self.logs = ExceptionList(self) self.logs.setToolTip("Logs") self.task_view = QListView() self.task_que = QStandardItemModel(self) self.task_view.setModel(self.task_que) self.process_num_timer = QTimer() self.process_num_timer.setInterval(1000) self.process_num_timer.setSingleShot(True) self.process_num_timer.timeout.connect(self.change_number_of_workers) self.number_of_process = QSpinBox(self) self.number_of_process.setRange(1, multiprocessing.cpu_count()) self.number_of_process.setValue(1) self.number_of_process.setToolTip( "Number of process used in batch calculation") self.number_of_process.valueChanged.connect( self.process_num_timer_start) self.progress_item_dict = {} layout = QGridLayout() layout.addWidget(self.whole_label, 0, 0, Qt.AlignRight) layout.addWidget(self.whole_progress, 0, 1, 1, 2) layout.addWidget(self.part_label, 1, 0, Qt.AlignRight) layout.addWidget(self.part_progress, 1, 1, 1, 2) lab = QLabel("Number of process:") lab.setToolTip("Number of process used in batch calculation") layout.addWidget(lab, 2, 0) layout.addWidget(self.number_of_process, 2, 1) layout.addWidget(self.logs, 3, 0, 2, 3) layout.addWidget(self.task_view, 0, 4, 4, 1) layout.addWidget(self.cancel_remove_btn, 4, 4, 1, 1) layout.setColumnMinimumWidth(2, 10) layout.setColumnStretch(2, 1) self.setLayout(layout) self.preview_timer = QTimer() self.preview_timer.setInterval(1000) self.preview_timer.timeout.connect(self.update_info) self.task_view.selectionModel().currentChanged.connect( self.task_selection_change) self.cancel_remove_btn.clicked.connect(self.task_cancel_remove) def task_selection_change(self, new, old): task: CalculationProcessItem = self.task_que.item( new.row(), new.column()) if task is None: self.cancel_remove_btn.setDisabled(True) return self.cancel_remove_btn.setEnabled(True) if task.is_finished(): self.cancel_remove_btn.setText(f"Remove task {task.num}") else: self.cancel_remove_btn.setText(f"Cancel task {task.num}") def task_cancel_remove(self): index = self.task_view.selectionModel().currentIndex() task: CalculationProcessItem = self.task_que.item( index.row(), index.column()) if task.is_finished(): self.calculation_manager.remove_calculation(task.calculation) self.task_que.takeRow(index.row()) else: self.calculation_manager.cancel_calculation(task.calculation) print(task) def new_task(self): self.whole_progress.setMaximum( self.calculation_manager.calculation_size) if not self.preview_timer.isActive(): self.update_info() self.preview_timer.start() def update_info(self): res = self.calculation_manager.get_results() for el in res.errors: if el[0]: QListWidgetItem(el[0], self.logs) ExceptionListItem(el[1], self.logs) if (state_store.report_errors and parsed_version.is_devrelease and not isinstance(el[1][0], SegmentationLimitException) and isinstance(el[1][1], tuple)): with sentry_sdk.push_scope() as scope: scope.set_tag("auto_report", "true") sentry_sdk.capture_event(el[1][1][0]) self.whole_progress.setValue(res.global_counter) working_search = True for uuid, progress in res.jobs_status.items(): calculation = self.calculation_manager.calculation_dict[uuid] total = len(calculation.file_list) if uuid in self.progress_item_dict: item = self.progress_item_dict[uuid] item.update_count(progress) else: item = CalculationProcessItem(calculation, self.task_count, progress) self.task_count += 1 self.task_que.appendRow(item) self.progress_item_dict[uuid] = item if working_search and progress != total: self.part_progress.setMaximum(total) self.part_progress.setValue(progress) working_search = False if not self.calculation_manager.has_work: self.part_progress.setValue(self.part_progress.maximum()) self.preview_timer.stop() logging.info("Progress stop") def process_num_timer_start(self): self.process_num_timer.start() def update_progress(self, total_progress, part_progress): self.whole_progress.setValue(total_progress) self.part_progress.setValue(part_progress) def set_total_size(self, size): self.whole_progress.setMaximum(size) def set_part_size(self, size): self.part_progress.setMaximum(size) def change_number_of_workers(self): self.calculation_manager.set_number_of_workers( self.number_of_process.value())