class AttributeCreatorWidget(CustomScrollableListItem): def __init__(self, document_base_creator_widget) -> None: super(AttributeCreatorWidget, self).__init__(document_base_creator_widget) self.document_base_creator_widget = document_base_creator_widget self.setFixedHeight(40) self.setStyleSheet("background-color: white") self.layout = QHBoxLayout(self) self.layout.setContentsMargins(20, 0, 20, 0) self.layout.setSpacing(10) self.name = QLineEdit() self.name.setFont(CODE_FONT_BOLD) self.name.setStyleSheet("border: none") self.layout.addWidget(self.name) self.delete_button = QPushButton() self.delete_button.setIcon(QIcon("aset_ui/resources/trash.svg")) self.delete_button.setFlat(True) self.delete_button.clicked.connect(self._delete_button_clicked) self.layout.addWidget(self.delete_button) def update_item(self, item, params=None): self.name.setText(item) def _delete_button_clicked(self): self.document_base_creator_widget.delete_attribute(self.name.text()) def enable_input(self): self.delete_button.setEnabled(True) def disable_input(self): self.delete_button.setEnabled(False)
def __init__(self, ID=0): super(NodeWidget, self).__init__() laytout = QHBoxLayout() self.input_id = QLineEdit(str(ID)) self.input_id.setFixedWidth(30) self.input_text = QLineEdit("") self.input_text.setFixedHeight(20) self.input_text.setFixedWidth(400) self.input_type = QComboBox() self.input_type.addItem('开始/结束') self.input_type.addItem('流程') self.input_type.addItem('判定') self.input_type.addItem('None') self.input_type.setFixedWidth(80) self.input_x = QLineEdit("0") self.input_x.setFixedWidth(30) self.input_y = QLineEdit("0") self.input_y.setFixedWidth(30) self.input_link1 = QLineEdit("") self.input_link1.setFixedWidth(30) self.input_link2 = QLineEdit("") self.input_link2.setFixedWidth(30) laytout.addWidget(self.input_id) laytout.addWidget(self.input_text) laytout.addWidget(self.input_type) laytout.addWidget(self.input_x) laytout.addWidget(self.input_y) laytout.addWidget(self.input_link1) laytout.addWidget(self.input_link2) laytout.addStretch() laytout.setContentsMargins(0, 0, 0, 0) self.setLayout(laytout) self.data = []
def __init__( self, onOpenLogButtonPressed: Callable[[], None], onAgentVarsButtonPressed: Callable[[], None], parent: Optional[QWidget] = None, *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ The "Open Log" and "Agent Variables" buttons view used for opening those windows. """ super(SolverWindowsButtonsView, self).__init__(parent=parent, *args, **kwargs) self.setContentsMargins(0, 0, 0, 0) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # define the buttons openLogButton = QPushButton("Open Log") agentVarsButton = QPushButton("Agent Variables") # connect them to their respective methods openLogButton.pressed.connect(onOpenLogButtonPressed) # type: ignore agentVarsButton.pressed.connect(onAgentVarsButtonPressed) # type: ignore layout.addWidget(openLogButton) layout.addWidget(agentVarsButton) layout.setAlignment(openLogButton, Qt.Alignment.AlignHCenter) layout.setAlignment(agentVarsButton, Qt.Alignment.AlignHCenter) self.setLayout(layout)
def __addInputAndRadio__(self, input, radio): hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.addWidget(input) hbox.addWidget(radio) widget = QWidget(self) widget.setLayout(hbox) self.layout.addWidget(widget, self.row, 0, 1, -1) self.row += 1
def __addInputAndSelect__(self, input, top): hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.addWidget(input) browseButton = BrowseButton(self, input, top) browseButton.adjustSize() hbox.addWidget(browseButton) widget = QWidget(self) widget.setLayout(hbox) self.layout.addWidget(widget, self.row, 0, 1, -1) self.row += 1
class NuggetListWidget(QWidget): def __init__(self, interactive_matching_widget): super(NuggetListWidget, self).__init__(interactive_matching_widget) self.interactive_matching_widget = interactive_matching_widget self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(10) # top widget self.top_widget = QWidget() self.top_layout = QHBoxLayout(self.top_widget) self.top_layout.setContentsMargins(0, 0, 0, 0) self.top_layout.setSpacing(10) self.layout.addWidget(self.top_widget) self.description = QLabel( "Below you see a list of guessed matches for you to confirm or correct." ) self.description.setFont(LABEL_FONT) self.top_layout.addWidget(self.description) self.stop_button = QPushButton("Continue With Next Attribute") self.stop_button.setFont(BUTTON_FONT) self.stop_button.clicked.connect(self._stop_button_clicked) self.stop_button.setMaximumWidth(240) self.top_layout.addWidget(self.stop_button) # nugget list self.nugget_list = CustomScrollableList(self, NuggetListItemWidget) self.layout.addWidget(self.nugget_list) def update_nuggets(self, nuggets): max_start_chars = max([ nugget[CachedContextSentenceSignal]["start_char"] for nugget in nuggets ]) self.nugget_list.update_item_list(nuggets, max_start_chars) def _stop_button_clicked(self): self.interactive_matching_widget.main_window.give_feedback_task( {"message": "stop-interactive-matching"}) def enable_input(self): self.stop_button.setEnabled(True) self.nugget_list.enable_input() def disable_input(self): self.stop_button.setDisabled(True) self.nugget_list.disable_input()
def __init__( self, minimum: XY, maximum: XY, initialValue: XY, parent: Optional[QWidget] = None, label: str = "by", *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ A horizontal dual spin box widget designed for the XY size of a maze. """ valid = True if (initialValue.x < minimum.x) or (initialValue.y > maximum.y): valid = False elif (initialValue.x < minimum.x) or (initialValue.y > maximum.y): valid = False if not valid: raise ValueError( f"Initial value for XYPicker must be between {minimum} and {maximum}." ) super(XYPicker, self).__init__(parent=parent, *args, **kwargs) self.setContentsMargins(0, 0, 0, 0) mazeSizePickerLayout = QHBoxLayout() mazeSizePickerLayout.setContentsMargins(0, 0, 0, 0) self.__xSpinBox = QSpinBox() self.__ySpinBox = QSpinBox() self.__xSpinBox.setMinimum(minimum.x) self.__ySpinBox.setMinimum(minimum.y) self.__xSpinBox.setMaximum(maximum.x) self.__ySpinBox.setMaximum(maximum.y) self.__xSpinBox.setValue(initialValue.x) self.__ySpinBox.setValue(initialValue.y) mazeSizePickerLayout.addWidget(self.__xSpinBox) mazeSizePickerLayout.addWidget(QLabel(label)) mazeSizePickerLayout.addWidget(self.__ySpinBox) self.setLayout(mazeSizePickerLayout)
def __init__( self, onValueChanged: Callable[[int], None], parent: Optional[QWidget] = None, *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ Slow/fast slider for maze solver agents speed """ super(MazeSolverSpeedControlView, self).__init__(parent=parent, *args, **kwargs) self.setContentsMargins(0, 0, 0, 0) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) slider = QSlider(Qt.Orientations.Horizontal) # minimum of 1 op/s (0 would result in a divide by zero op and thus crash) slider.setMinimum(1) # maximum of 50 op/s slider.setMaximum(70) # initial value in the middle slider.setValue(35) # connect the onValueChange event to the method passed to this widget slider.valueChanged.connect(onValueChanged) # type: ignore # slow/fast horizontal labels view slowFastLabelsLayout = QHBoxLayout() slowFastLabelsLayout.setContentsMargins(0, 0, 0, 0) slowLabel = QLabel("Slow") fastLabel = QLabel("Fast") slowFastLabelsLayout.addWidget(slowLabel) slowFastLabelsLayout.addStretch() slowFastLabelsLayout.addWidget(fastLabel) layout.addWidget(slider) layout.addLayout(slowFastLabelsLayout) self.setLayout(layout)
def __init__(self, table_view): """ A simple class that inherits QWidget and acts as a container for items added to QTableView cells """ super().__init__() self.table_view = table_view self.setAutoFillBackground(True) view_button = QPushButton(QIcon("icons/view.png"), None) view_button.clicked.connect(self.displayItemValues) delete_button = QPushButton(QIcon("icons/trash.png"), None) delete_button.clicked.connect(self.deleteTableRows) # Create the layout for the buttons cell_layout = QHBoxLayout() cell_layout.setContentsMargins(0, 0, 0, 0) cell_layout.setSpacing(0) cell_layout.addWidget(view_button) cell_layout.addWidget(delete_button) self.setLayout(cell_layout)
def __init__(self): super(MyWidget, self).__init__() self.setFixedSize(620, 600) self.setWindowTitle("自动画流程图工具 version:1.0.0 ") self.laytout = QVBoxLayout(self) headwidget = QWidget(self) headlayout = QHBoxLayout() label01 = QLabel(" ID ") label02 = QLabel("流程图内容") label03 = QLabel("节点类型") label04 = QLabel("X坐标") label05 = QLabel("Y坐标") label06 = QLabel("link1") label07 = QLabel('link2') headlayout.addWidget(label01, 3) headlayout.addWidget(label02, 40) headlayout.addWidget(label03, 8) headlayout.addWidget(label04, 3) headlayout.addWidget(label05, 3) headlayout.addWidget(label06, 3) headlayout.addWidget(label07, 3) headlayout.addStretch() headlayout.setContentsMargins(0, 0, 0, 0) headwidget.setLayout(headlayout) btnwidget = QWidget() btnlayout = QHBoxLayout() self.add_btn = QPushButton("添加节点") self.start_btn = QPushButton("开始画图") btnlayout.addWidget(self.add_btn) btnlayout.addWidget(self.start_btn) btnwidget.setLayout(btnlayout) btnlayout.setContentsMargins(0, 0, 0, 0) self.laytout.addStretch() self.laytout.addWidget(btnwidget) self.laytout.addWidget(headwidget) #self.laytout.addStretch() self.add_btn.clicked.connect(self.add_node) self.start_btn.clicked.connect(self.start_draw_visiflow) self.nodes = [] self.id = 0
class Ribbon(QWidget): selection_mode = pyqtSignal(bool) def __init__(self, parent): super(Ribbon, self).__init__(parent) self.configure_gui() self.create_widgets() def configure_gui(self): self.undo = [''] self.redo = [] self.layout = QHBoxLayout(self) self.layout.setContentsMargins(0, 0, 5, 0) def create_widgets(self): pass
def exerciseLayout(self, index): hLayout = QHBoxLayout() setSpinBox = QSpinBox() setSpinBox.setRange(1, 100) setSpinBox.setValue(5) setSpinBox.setMaximumWidth(80) startButton = QPushButton(self.classifyExercises.exercises[index].name) startButton.setMaximumWidth(120) assignedKey = QPushButton( self.classifyExercises.exercises[index].assigned_key[0]) assignedKey.setStyleSheet('background-color: grey; color: white;') assignedKey.setMaximumWidth(50) assignedKey.setEnabled(False) progress = QProgressBar() progress.setMaximumWidth(150) progress.setValue(randint(1, 100)) progress.setAlignment(QtCore.Qt.Alignment.AlignCenter) latency = QLabel(str(randint(50, 250)) + 'ms') avgLatency = QLabel(str(randint(50, 250)) + 'ms') hLayout.addWidget(setSpinBox) hLayout.setAlignment(setSpinBox, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(startButton) hLayout.setAlignment(startButton, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(assignedKey) hLayout.setAlignment(assignedKey, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(progress) hLayout.setAlignment(progress, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(latency) hLayout.setAlignment(latency, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(avgLatency) hLayout.setAlignment(avgLatency, QtCore.Qt.Alignment.AlignHCenter) hLayout.setContentsMargins(0, 10, 0, 10) self.exerciseLayouts.append(hLayout) return hLayout
def __init__(self, *args): QFrame.__init__(self, *args) self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Sunken) self.edit = QTextEdit() self.edit.setFrameStyle(QFrame.Shape.NoFrame) self.edit.setAcceptRichText(False) self.edit.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) self.number_bar = self.NumberBar() self.number_bar.set_text_edit(self.edit) hbox = QHBoxLayout(self) hbox.setSpacing(0) hbox.setContentsMargins(10,0,0,0) hbox.addWidget(self.number_bar) hbox.addWidget(self.edit) self.edit.installEventFilter(self) self.edit.viewport().installEventFilter(self)
def displayTag(self, tagName): tagWidget = QWidget() tagWidget.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) tagWidget.enterEvent = lambda e: self.setCursor( QCursor(Qt.CursorShape.PointingHandCursor)) tagWidget.leaveEvent = lambda e: self.setCursor( QCursor(Qt.CursorShape.ArrowCursor)) tagWidget.mouseReleaseEvent = lambda e: self.removeTag( self.flowLayout.indexOf(tagWidget), returnTag=False) self.renderStyleSheet(tagWidget) hBoxTag = QHBoxLayout() tagLabel = QLabel() tagLabel.setText(tagName) tagLabel.setStyleSheet(f''' QLabel {{ background-color: transparent; border: none; }} ''') hBoxTag.addWidget(tagLabel) crossIcon = QPixmap('MangoUI/TagBox/img/crossresized.png') crossIconLabel = QLabel() crossIconLabel.setPixmap(crossIcon) crossIconLabel.setStyleSheet(f''' QLabel {{ background-color: transparent; border: none; }} ''') hBoxTag.addWidget(crossIconLabel) hBoxTag.setContentsMargins(10, 6, 6, 6) tagWidget.setLayout(hBoxTag) self.flowLayout.addWidget(tagWidget)
class AttributeWidget(CustomScrollableListItem): def __init__(self, document_base_viewer): super(AttributeWidget, self).__init__(document_base_viewer) self.document_base_viewer = document_base_viewer self.attribute = None self.setFixedHeight(40) self.setStyleSheet("background-color: white") self.layout = QHBoxLayout(self) self.layout.setContentsMargins(20, 0, 20, 0) self.layout.setSpacing(40) self.attribute_name = QLabel() self.attribute_name.setFont(CODE_FONT_BOLD) self.layout.addWidget(self.attribute_name, alignment=Qt.AlignmentFlag.AlignLeft) self.num_matched = QLabel("matches: -") self.num_matched.setFont(CODE_FONT) self.layout.addWidget(self.num_matched, alignment=Qt.AlignmentFlag.AlignLeft) self.buttons_widget = QWidget() self.buttons_layout = QHBoxLayout(self.buttons_widget) self.buttons_layout.setContentsMargins(0, 0, 0, 0) self.buttons_layout.setSpacing(10) self.layout.addWidget(self.buttons_widget, alignment=Qt.AlignmentFlag.AlignRight) self.forget_matches_button = QPushButton() self.forget_matches_button.setIcon(QIcon("aset_ui/resources/redo.svg")) self.forget_matches_button.setToolTip( "Forget matches for this attribute.") self.forget_matches_button.setFlat(True) self.forget_matches_button.clicked.connect( self._forget_matches_button_clicked) self.buttons_layout.addWidget(self.forget_matches_button) self.remove_button = QPushButton() self.remove_button.setIcon(QIcon("aset_ui/resources/trash.svg")) self.remove_button.setToolTip("Remove this attribute.") self.remove_button.setFlat(True) self.remove_button.clicked.connect(self._remove_button_clicked) self.buttons_layout.addWidget(self.remove_button) def update_item(self, item, params=None): self.attribute = item if len(params.attributes) == 0: max_attribute_name_len = 10 else: max_attribute_name_len = max( len(attribute.name) for attribute in params.attributes) self.attribute_name.setText(self.attribute.name + ( " " * (max_attribute_name_len - len(self.attribute.name)))) mappings_in_some_documents = False no_mappings_in_some_documents = False num_matches = 0 for document in params.documents: if self.attribute.name in document.attribute_mappings.keys(): mappings_in_some_documents = True if document.attribute_mappings[self.attribute.name] != []: num_matches += 1 else: no_mappings_in_some_documents = True if not mappings_in_some_documents and no_mappings_in_some_documents: self.num_matched.setText("not matched yet") elif mappings_in_some_documents and no_mappings_in_some_documents: self.num_matched.setText("only partly matched") else: self.num_matched.setText(f"matches: {num_matches}") def enable_input(self): self.forget_matches_button.setEnabled(True) self.remove_button.setEnabled(True) def disable_input(self): self.forget_matches_button.setDisabled(True) self.remove_button.setDisabled(True) def _forget_matches_button_clicked(self): self.document_base_viewer.main_window.forget_matches_for_attribute_with_given_name_task( self.attribute.name) def _remove_button_clicked(self): self.document_base_viewer.main_window.remove_attribute_with_given_name_task( self.attribute.name)
def __init__(self, parent=None): super(VideoWindow, self).__init__(parent) self.setWindowTitle("StudioProject") self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.gScene = QGraphicsScene(self) self.gView = GraphicView(self.gScene, self) self.gView.viewport().setAttribute( Qt.WidgetAttribute.WA_AcceptTouchEvents, False) # self.gView.setBackgroundBrush(QBrush(Qt.black)) self.videoStartDatetime = None self.videoCurrentDatetime = None self.projectFile = '' self.graphicsFile = '' self.videoFile = '' self.obsTb = ObsToolbox(self) # # ===================== Setting video item ============================== # self.videoItem = QGraphicsVideoItem() # self.videoItem.setAspectRatioMode(Qt.KeepAspectRatio) # self.gScene.addItem(self.videoItem) # self.videoItem.mouseMoveEvent = self.gView.mouseMoveEvent self.mediaPlayer = QMediaPlayer(self) # self.mediaPlayer.setVideoOutput(self.videoItem) self.mediaPlayer.playbackStateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.errorOccurred.connect(self.handleError) # self.mediaPlayer.setMuted(True) # self.mediaPlayer.setNotifyInterval(100) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon( QStyle.StandardPixmap.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.changePlayRateBtn = QPushButton('1x') self.changePlayRateBtn.setFixedWidth(40) # self.incrPlayRateBtn.setEnabled(False) self.changePlayRateBtn.clicked.connect(self.changePlayRate) self.positionSlider = QSlider(Qt.Orientation.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.timerLabel = QLabel() self.timerLabel.setText('--:--:--') self.timerLabel.setFixedWidth(58) self.dateLabel = QLabel() self.dateLabel.setText('Video date: --') self.statusBar.addPermanentWidget(self.dateLabel) # Create open action self.openVideoAction = QAction(QIcon('icons/video-file.png'), 'Open video', self) self.openVideoAction.setShortcut('Ctrl+O') self.openVideoAction.setStatusTip('Open video file') self.openVideoAction.triggered.connect(self.openVideoFile) # Create observation action obsTbAction = QAction(QIcon('icons/checklist.png'), 'Observation toolbox', self) obsTbAction.setStatusTip('Open observation toolbox') obsTbAction.triggered.connect(self.openObsToolbox) self.drawPointAction = QAction(QIcon('icons/drawPoint.png'), 'Draw point', self) self.drawPointAction.setStatusTip('Draw point over the video') self.drawPointAction.setCheckable(True) self.drawPointAction.setEnabled(False) self.drawPointAction.triggered.connect(self.drawingClick) self.drawLineAction = QAction(QIcon('icons/drawLine.png'), 'Draw line', self) self.drawLineAction.setStatusTip('Draw line over the video') self.drawLineAction.setCheckable(True) self.drawLineAction.setEnabled(False) self.drawLineAction.triggered.connect(self.drawingClick) self.drawZoneAction = QAction(QIcon('icons/drawZone.png'), 'Draw zone', self) self.drawZoneAction.setStatusTip('Draw zone over the video') self.drawZoneAction.setCheckable(True) self.drawZoneAction.setEnabled(False) self.drawZoneAction.triggered.connect(self.drawingClick) self.maskGenAction = QAction(QIcon('icons/mask.png'), 'Generate mask file', self) self.maskGenAction.setStatusTip( 'Generate mask file for TrafficIntelligence') self.maskGenAction.setCheckable(True) self.maskGenAction.setEnabled(False) self.maskGenAction.triggered.connect(self.generateMask) actionGroup = QActionGroup(self) actionGroup.addAction(self.drawPointAction) actionGroup.addAction(self.drawLineAction) actionGroup.addAction(self.drawZoneAction) openProjectAction = QAction(QIcon('icons/open-project.png'), 'Open project', self) openProjectAction.setStatusTip('Open project') openProjectAction.triggered.connect(self.openProject) self.saveProjectAction = QAction(QIcon('icons/save-project.png'), 'Save project', self) self.saveProjectAction.setStatusTip('Save project') self.saveProjectAction.setEnabled(False) self.saveProjectAction.triggered.connect(self.saveProject) self.saveGraphAction = QAction(QIcon('icons/save-graphics.png'), 'Save graphics', self) self.saveGraphAction.setStatusTip('Save graphics to database') self.saveGraphAction.setEnabled(False) self.saveGraphAction.triggered.connect(self.saveGraphics) self.loadGraphAction = QAction(QIcon('icons/folders.png'), 'Load graphics', self) self.loadGraphAction.setStatusTip('Load graphics from database') self.loadGraphAction.setEnabled(False) self.loadGraphAction.triggered.connect(self.loadGraphics) # Create exit action exitAction = QAction(QIcon('icons/close.png'), 'Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.exitCall) # self.exitCall # Create menu bar and add action # menuBar = self.menuBar() # menuBar.setNativeMenuBar(False) # fileMenu = menuBar.addMenu('&File') # fileMenu.addAction(openVideoAction) # fileMenu.addAction(obsTbAction) # fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Tools') self.toolbar.setIconSize(QSize(24, 24)) self.toolbar.addAction(openProjectAction) self.toolbar.addAction(self.saveProjectAction) self.toolbar.addAction(self.openVideoAction) # self.toolbar.insertSeparator(self.loadGraphAction) # self.toolbar.addAction(self.loadGraphAction) # self.toolbar.addAction(self.saveGraphAction) # self.toolbar.addAction(self.drawPointAction) # self.toolbar.addAction(self.drawLineAction) # self.toolbar.addAction(self.drawZoneAction) self.toolbar.addAction(self.maskGenAction) # self.toolbar.insertSeparator(self.drawPointAction) self.toolbar.insertSeparator(obsTbAction) self.toolbar.addAction(obsTbAction) self.toolbar.insertSeparator(exitAction) self.toolbar.addAction(exitAction) # Create a widget for window contents wid = QWidget(self) self.setCentralWidget(wid) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) # controlLayout.addWidget(self.decrPlayRateBtn) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.changePlayRateBtn) controlLayout.addWidget(self.timerLabel) controlLayout.addWidget(self.positionSlider) # controlLayout.addWidget(self.durationLabel) layout = QVBoxLayout() layout.addWidget(self.gView) layout.addLayout(controlLayout) # Set widget to contain window contents wid.setLayout(layout)
class NuggetListItemWidget(CustomScrollableListItem): def __init__(self, nugget_list_widget): super(NuggetListItemWidget, self).__init__(nugget_list_widget) self.nugget_list_widget = nugget_list_widget self.nugget = None self.setFixedHeight(40) self.setStyleSheet("background-color: white") self.layout = QHBoxLayout(self) self.layout.setContentsMargins(20, 0, 20, 0) self.layout.setSpacing(10) self.info_label = QLabel() self.info_label.setFont(CODE_FONT_BOLD) self.layout.addWidget(self.info_label) self.left_split_label = QLabel("|") self.left_split_label.setFont(CODE_FONT_BOLD) self.layout.addWidget(self.left_split_label) self.text_edit = QTextEdit() self.text_edit.setReadOnly(True) self.text_edit.setFrameStyle(0) self.text_edit.setFont(CODE_FONT) self.text_edit.setLineWrapMode(QTextEdit.LineWrapMode.FixedPixelWidth) self.text_edit.setLineWrapColumnOrWidth(10000) self.text_edit.setHorizontalScrollBarPolicy( Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.text_edit.setVerticalScrollBarPolicy( Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.text_edit.setFixedHeight(30) self.text_edit.setText("") self.layout.addWidget(self.text_edit) self.right_split_label = QLabel("|") self.right_split_label.setFont(CODE_FONT_BOLD) self.layout.addWidget(self.right_split_label) self.match_button = QPushButton() self.match_button.setIcon(QIcon("aset_ui/resources/correct.svg")) self.match_button.setFlat(True) self.match_button.clicked.connect(self._match_button_clicked) self.layout.addWidget(self.match_button) self.fix_button = QPushButton() self.fix_button.setIcon(QIcon("aset_ui/resources/incorrect.svg")) self.fix_button.setFlat(True) self.fix_button.clicked.connect(self._fix_button_clicked) self.layout.addWidget(self.fix_button) def update_item(self, item, params=None): self.nugget = item sentence = self.nugget[CachedContextSentenceSignal]["text"] start_char = self.nugget[CachedContextSentenceSignal]["start_char"] end_char = self.nugget[CachedContextSentenceSignal]["end_char"] self.text_edit.setText("") formatted_text = ( f"{' ' * (params - start_char)}{sentence[:start_char]}" f"<span style='background-color: #FFFF00'><b>{sentence[start_char:end_char]}</b></span>" f"{sentence[end_char:]}{' ' * 50}") self.text_edit.textCursor().insertHtml(formatted_text) scroll_cursor = QTextCursor(self.text_edit.document()) scroll_cursor.setPosition(params + 50) self.text_edit.setTextCursor(scroll_cursor) self.text_edit.ensureCursorVisible() self.info_label.setText( f"{str(round(self.nugget[CachedDistanceSignal], 2)).ljust(4)}") def _match_button_clicked(self): self.nugget_list_widget.interactive_matching_widget.main_window.give_feedback_task( { "message": "is-match", "nugget": self.nugget }) def _fix_button_clicked(self): self.nugget_list_widget.interactive_matching_widget.get_document_feedback( self.nugget) def enable_input(self): self.match_button.setEnabled(True) self.fix_button.setEnabled(True) def disable_input(self): self.match_button.setDisabled(True) self.fix_button.setDisabled(True)
class CalibrateWizard(QWizard): def __init__(self, parent): super().__init__(parent) self.parent = parent self.setWizardStyle(QWizard.WizardStyle.ModernStyle) # CREATE PAGE 1, LINE EDIT, TITLES buttons_layout = [QWizard.WizardButton.NextButton] self.page1 = QWizardPage() self.page1.setTitle('Select the exercises you wish to do later') self.page1.setSubTitle( 'Below are listed all the available and selected exercises by you.' ) self.listSelection = TwoListSelection() # listSelection.addAvailableItems(["item-{}".format(i) for i in range(5)]) hLayout1 = QHBoxLayout(self.page1) hLayout1.addWidget(self.listSelection) # CREATE PAGE 2, LABEL, TITLES self.page2 = QWizardPage() self.page2.setFinalPage(True) self.setButtonLayout(buttons_layout) self.page2.setTitle('Calibrate every exercise') self.page2.setSubTitle( 'Do every exercise once, record after pressing button.') self.contentLayout = QVBoxLayout(self.page2) self.hLayout2 = QHBoxLayout() # Create progress bar, buttons self.actionsLayout = QHBoxLayout() self.finishButton = QPushButton('Ready') self.finishButton.setStyleSheet(CustomQStyles.buttonStyle) self.finishButton.setFixedSize(120, 35) self.progress = QProgressBar() self.progress.setRange(0, 1) self.actionsLayout.addWidget(self.progress) self.actionsLayout.setAlignment(self.progress, Qt.Alignment.AlignBottom) self.actionsLayout.addWidget(self.finishButton) self.actionsLayout.setAlignment(self.finishButton, Qt.Alignment.AlignBottom) self.contentLayout.addLayout(self.hLayout2) self.contentLayout.addLayout(self.actionsLayout) self.actionsLayout.setContentsMargins(15, 35, 15, 0) itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] print("items:", itemsTextList) self.button(QWizard.WizardButton.NextButton).clicked.connect( self.onWizardNextButton) self.finishButton.clicked.connect(self.onWizardFinishButton) self.addPage(self.page1) self.addPage(self.page2) # Recording data self.buttons = [] self.images = [] self.labels = [] self.exerciseLayouts = [] self.recordReady = [] self.recordThread = RecordThread(self.parent.classifyExercises) # Training recorded data self.trained = False self.trainThread = TrainThread(self.parent.classifyExercises) self.trainThread.taskFinished.connect(self.onTrainFinished) # Send list to next page def onWizardNextButton(self): self.setPage(1, self.page1) self.trained = False itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] # Update list if self.parent.classifyExercises is not None: self.parent.classifyExercises.UpdateExerciseList(itemsTextList) # Set elements on UI self.setMinimumWidth(len(itemsTextList) * 200) self.deleteItemsOfLayout(self.hLayout2) self.images.clear() self.labels.clear() self.buttons.clear() self.recordReady.clear() for x, i in zip(itemsTextList, range(len(itemsTextList))): self.exerciseLayouts.append(QVBoxLayout()) self.buttons.append(QPushButton('Record')) self.recordReady.append(False) image = QLabel() image.setPixmap( QPixmap(os.getcwd() + "/resources/images/" + itemsTextList[i] + ".png")) self.labels.append(QLabel(itemsTextList[i])) self.images.append(image) self.buttons[i].setFixedSize(100, 35) self.buttons[i].clicked.connect( functools.partial(self.onRecordExerciseButtonClicked, x, i)) self.buttons[i].setStyleSheet(CustomQStyles.outlineButtonStyle) self.exerciseLayouts[i].addWidget(self.labels[i]) self.exerciseLayouts[i].addWidget(self.images[i]) self.exerciseLayouts[i].addWidget(self.buttons[i]) self.exerciseLayouts[i].setAlignment(self.labels[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.images[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.buttons[i], Qt.Alignment.AlignCenter) self.hLayout2.addLayout(self.exerciseLayouts[i]) def onRecordExerciseButtonClicked(self, exercise, ind): print("Recording - ", exercise) if self.parent.classifyExercises is not None: self.recordThread.exercise = exercise self.recordThread.taskFinished.connect( functools.partial(self.recordFinished, exercise, ind), Qt.ConnectionType.SingleShotConnection) self.recordThread.start() self.recordReady[ind] = False self.buttons[ind].setStyleSheet(CustomQStyles.recordButtonStyle) self.images[ind].setPixmap( QPixmap(os.getcwd() + "/resources/images/" + exercise + ".png")) def recordFinished(self, exercise, index): imagePath = os.getcwd() + "/resources/images/" + exercise + ".png" if self.recordThread.result == 0: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-fail.png" elif self.recordThread.result == 1: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-success.png" self.recordReady[index] = True else: print("None.") self.images[index].setPixmap(QPixmap(imagePath)) self.buttons[index].setStyleSheet(CustomQStyles.outlineButtonStyle) print(self.recordReady) def onWizardFinishButton(self): if all(x == True for x in self.recordReady): print("All recorded!") if not self.trained: if self.parent.classifyExercises is not None: self.progress.setRange(0, 0) # indefinite progress bar self.parent.classifyExercises.SaveProcessedData() self.parent.classifyExercises.SavePatientData() self.parent.ui.loadPatientList() self.trainThread.start() else: self.close() else: print("Not all recorded!") def onTrainFinished(self): self.progress.setRange(0, 1) self.progress.setValue(1) self.trained = True CustomMessage.showDialog("Message", "Training model finished!", QMessageBox.StandardButtons.Ok) self.finishButton.setText('Finish') def deleteItemsOfLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.setParent(None) else: self.deleteItemsOfLayout(item.layout())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupTrayicon() self.setupVariables() self.setupUi() self.setupConnections() self.show() def setupVariables(self): settings = QSettings() self.workEndTime = QTime( int(settings.value(workHoursKey, 0)), int(settings.value(workMinutesKey, 25)), int(settings.value(workSecondsKey, 0)), ) self.restEndTime = QTime( int(settings.value(restHoursKey, 0)), int(settings.value(restMinutesKey, 5)), int(settings.value(restSecondsKey, 0)), ) self.timeFormat = "hh:mm:ss" self.time = QTime(0, 0, 0, 0) self.workTime = QTime(0, 0, 0, 0) self.restTime = QTime(0, 0, 0, 0) self.totalTime = QTime(0, 0, 0, 0) self.currentMode = Mode.work self.maxRepetitions = -1 self.currentRepetitions = 0 def setupConnections(self): """ Create button connections """ self.startButton.clicked.connect(self.startTimer) self.startButton.clicked.connect( lambda: self.startButton.setDisabled(True)) self.startButton.clicked.connect( lambda: self.pauseButton.setDisabled(False)) self.startButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.pauseButton.clicked.connect(self.pauseTimer) self.pauseButton.clicked.connect( lambda: self.startButton.setDisabled(False)) self.pauseButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.pauseButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.pauseButton.clicked.connect( lambda: self.startButton.setText("continue")) self.resetButton.clicked.connect(self.resetTimer) self.resetButton.clicked.connect( lambda: self.startButton.setDisabled(False)) self.resetButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.resetButton.clicked.connect( lambda: self.resetButton.setDisabled(True)) self.resetButton.clicked.connect( lambda: self.startButton.setText("start")) self.acceptTaskButton.pressed.connect(self.insertTask) self.deleteTaskButton.pressed.connect(self.deleteTask) """ Create spinbox connections """ self.workHoursSpinBox.valueChanged.connect(self.updateWorkEndTime) self.workMinutesSpinBox.valueChanged.connect(self.updateWorkEndTime) self.workSecondsSpinBox.valueChanged.connect(self.updateWorkEndTime) self.restHoursSpinBox.valueChanged.connect(self.updateRestEndTime) self.restMinutesSpinBox.valueChanged.connect(self.updateRestEndTime) self.restSecondsSpinBox.valueChanged.connect(self.updateRestEndTime) self.repetitionsSpinBox.valueChanged.connect(self.updateMaxRepetitions) """ Create combobox connections """ self.modeComboBox.currentTextChanged.connect(self.updateCurrentMode) """ Create tablewidget connections """ self.tasksTableWidget.cellDoubleClicked.connect( self.markTaskAsFinished) def setupUi(self): self.size_policy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) """ Create tabwidget """ self.tabWidget = QTabWidget() """ Create tab widgets """ timerWidget = self.setupTimerTab() tasksWidget = self.setupTasksTab() statisticsWidget = self.setupStatisticsTab() """ add tab widgets to tabwidget""" self.timerTab = self.tabWidget.addTab(timerWidget, makeIcon("timer"), "Timer") self.tasksTab = self.tabWidget.addTab(tasksWidget, makeIcon("tasks"), "Tasks") self.statisticsTab = self.tabWidget.addTab(statisticsWidget, makeIcon("statistics"), "Statistics") """ Set mainwindows central widget """ self.setCentralWidget(self.tabWidget) def setupTimerTab(self): settings = QSettings() self.timerContainer = QWidget(self) self.timerContainerLayout = QVBoxLayout(self.timerContainer) self.timerContainer.setLayout(self.timerContainerLayout) """ Create work groupbox""" self.workGroupBox = QGroupBox("Work") self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox) self.workGroupBox.setLayout(self.workGroupBoxLayout) self.workHoursSpinBox = QSpinBox( minimum=0, maximum=24, value=int(settings.value(workHoursKey, 0)), suffix="h", sizePolicy=self.size_policy, ) self.workMinutesSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(workMinutesKey, 25)), suffix="m", sizePolicy=self.size_policy, ) self.workSecondsSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(workSecondsKey, 0)), suffix="s", sizePolicy=self.size_policy, ) """ Create rest groupbox""" self.restGroupBox = QGroupBox("Rest") self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox) self.restGroupBox.setLayout(self.restGroupBoxLayout) self.restHoursSpinBox = QSpinBox( minimum=0, maximum=24, value=int(settings.value(restHoursKey, 0)), suffix="h", sizePolicy=self.size_policy, ) self.restMinutesSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(restMinutesKey, 5)), suffix="m", sizePolicy=self.size_policy, ) self.restSecondsSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(restSecondsKey, 0)), suffix="s", sizePolicy=self.size_policy, ) self.restGroupBoxLayout.addWidget(self.restHoursSpinBox) self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox) self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox) """ Create other groupbox""" self.otherGroupBox = QGroupBox("Other") self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox) self.otherGroupBox.setLayout(self.otherGroupBoxLayout) self.repetitionsLabel = QLabel("Repetitions") self.repetitionsSpinBox = QSpinBox( minimum=0, maximum=10000, value=0, sizePolicy=self.size_policy, specialValueText="∞", ) self.modeLabel = QLabel("Mode") self.modeComboBox = QComboBox(sizePolicy=self.size_policy) self.modeComboBox.addItems(["work", "rest"]) self.otherGroupBoxLayout.addWidget(self.repetitionsLabel) self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox) self.otherGroupBoxLayout.addWidget(self.modeLabel) self.otherGroupBoxLayout.addWidget(self.modeComboBox) """ Create timer groupbox""" self.lcdDisplayGroupBox = QGroupBox("Time") self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox) self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout) self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy) self.timeDisplay.setFixedHeight(100) self.timeDisplay.display("00:00:00") self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay) """ Create pause, start and reset buttons""" self.buttonContainer = QWidget() self.buttonContainerLayout = QHBoxLayout(self.buttonContainer) self.buttonContainer.setLayout(self.buttonContainerLayout) self.startButton = self.makeButton("start", disabled=False) self.resetButton = self.makeButton("reset") self.pauseButton = self.makeButton("pause") """ Add widgets to container """ self.workGroupBoxLayout.addWidget(self.workHoursSpinBox) self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox) self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox) self.timerContainerLayout.addWidget(self.workGroupBox) self.timerContainerLayout.addWidget(self.restGroupBox) self.timerContainerLayout.addWidget(self.otherGroupBox) self.timerContainerLayout.addWidget(self.lcdDisplayGroupBox) self.buttonContainerLayout.addWidget(self.pauseButton) self.buttonContainerLayout.addWidget(self.startButton) self.buttonContainerLayout.addWidget(self.resetButton) self.timerContainerLayout.addWidget(self.buttonContainer) return self.timerContainer def setupTasksTab(self): settings = QSettings() """ Create vertical tasks container """ self.tasksWidget = QWidget(self.tabWidget) self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget) self.tasksWidget.setLayout(self.tasksWidgetLayout) """ Create horizontal input container """ self.inputContainer = QWidget() self.inputContainer.setFixedHeight(50) self.inputContainerLayout = QHBoxLayout(self.inputContainer) self.inputContainerLayout.setContentsMargins(0, 0, 0, 0) self.inputContainer.setLayout(self.inputContainerLayout) """ Create text edit """ self.taskTextEdit = QTextEdit( placeholderText="Describe your task briefly.", undoRedoEnabled=True) """ Create vertical buttons container """ self.inputButtonContainer = QWidget() self.inputButtonContainerLayout = QVBoxLayout( self.inputButtonContainer) self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0) self.inputButtonContainer.setLayout(self.inputButtonContainerLayout) """ Create buttons """ self.acceptTaskButton = QToolButton(icon=makeIcon("check")) self.deleteTaskButton = QToolButton(icon=makeIcon("trash")) """ Create tasks tablewidget """ self.tasksTableWidget = QTableWidget(0, 1) self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"]) self.tasksTableWidget.horizontalHeader().setStretchLastSection(True) self.tasksTableWidget.verticalHeader().setVisible(False) self.tasksTableWidget.setWordWrap(True) self.tasksTableWidget.setTextElideMode(Qt.TextElideMode.ElideNone) self.tasksTableWidget.setEditTriggers( QAbstractItemView.EditTriggers.NoEditTriggers) self.tasksTableWidget.setSelectionMode( QAbstractItemView.SelectionMode.SingleSelection) self.insertTasks(*settings.value(tasksKey, [])) """ Add widgets to container widgets """ self.inputButtonContainerLayout.addWidget(self.acceptTaskButton) self.inputButtonContainerLayout.addWidget(self.deleteTaskButton) self.inputContainerLayout.addWidget(self.taskTextEdit) self.inputContainerLayout.addWidget(self.inputButtonContainer) self.tasksWidgetLayout.addWidget(self.inputContainer) self.tasksWidgetLayout.addWidget(self.tasksTableWidget) return self.tasksWidget def setupStatisticsTab(self): """ Create statistics container """ self.statisticsContainer = QWidget() self.statisticsContainerLayout = QVBoxLayout(self.statisticsContainer) self.statisticsContainer.setLayout(self.statisticsContainerLayout) """ Create work time groupbox """ self.statisticsWorkTimeGroupBox = QGroupBox("Work Time") self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout() self.statisticsWorkTimeGroupBox.setLayout( self.statisticsWorkTimeGroupBoxLayout) self.statisticsWorkTimeDisplay = QLCDNumber(8) self.statisticsWorkTimeDisplay.display("00:00:00") self.statisticsWorkTimeGroupBoxLayout.addWidget( self.statisticsWorkTimeDisplay) """ Create rest time groupbox """ self.statisticsRestTimeGroupBox = QGroupBox("Rest Time") self.statisticsRestTimeGroupBoxLayout = QHBoxLayout() self.statisticsRestTimeGroupBox.setLayout( self.statisticsRestTimeGroupBoxLayout) self.statisticsRestTimeDisplay = QLCDNumber(8) self.statisticsRestTimeDisplay.display("00:00:00") self.statisticsRestTimeGroupBoxLayout.addWidget( self.statisticsRestTimeDisplay) """ Create total time groupbox """ self.statisticsTotalTimeGroupBox = QGroupBox("Total Time") self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout() self.statisticsTotalTimeGroupBox.setLayout( self.statisticsTotalTimeGroupBoxLayout) self.statisticsTotalTimeDisplay = QLCDNumber(8) self.statisticsTotalTimeDisplay.display("00:00:00") self.statisticsTotalTimeGroupBoxLayout.addWidget( self.statisticsTotalTimeDisplay) """ Add widgets to container """ self.statisticsContainerLayout.addWidget( self.statisticsTotalTimeGroupBox) self.statisticsContainerLayout.addWidget( self.statisticsWorkTimeGroupBox) self.statisticsContainerLayout.addWidget( self.statisticsRestTimeGroupBox) return self.statisticsContainer def setupTrayicon(self): self.trayIcon = QSystemTrayIcon(makeIcon("tomato")) self.trayIcon.setContextMenu(QMenu()) self.quitAction = self.trayIcon.contextMenu().addAction( makeIcon("exit"), "Quit", self.exit) self.quitAction.triggered.connect(self.exit) self.trayIcon.activated.connect(self.onActivate) self.trayIcon.show() self.trayIcon.setToolTip("Pomodoro") self.toast = ToastNotifier() def leaveEvent(self, event): super(MainWindow, self).leaveEvent(event) self.tasksTableWidget.clearSelection() def closeEvent(self, event): super(MainWindow, self).closeEvent(event) settings = QSettings() settings.setValue(workHoursKey, self.workHoursSpinBox.value()) settings.setValue( workMinutesKey, self.workMinutesSpinBox.value(), ) settings.setValue( workSecondsKey, self.workSecondsSpinBox.value(), ) settings.setValue(restHoursKey, self.restHoursSpinBox.value()) settings.setValue( restMinutesKey, self.restMinutesSpinBox.value(), ) settings.setValue( restSecondsKey, self.restSecondsSpinBox.value(), ) tasks = [] for i in range(self.tasksTableWidget.rowCount()): item = self.tasksTableWidget.item(i, 0) if not item.font().strikeOut(): tasks.append(item.text()) settings.setValue(tasksKey, tasks) def startTimer(self): try: if not self.timer.isActive(): self.createTimer() except: self.createTimer() def createTimer(self): self.timer = QTimer() self.timer.timeout.connect(self.updateTime) self.timer.timeout.connect(self.maybeChangeMode) self.timer.setInterval(1000) self.timer.setSingleShot(False) self.timer.start() def pauseTimer(self): try: self.timer.stop() self.timer.disconnect() except: pass def resetTimer(self): try: self.pauseTimer() self.time = QTime(0, 0, 0, 0) self.displayTime() except: pass def maybeStartTimer(self): if self.currentRepetitions != self.maxRepetitions: self.startTimer() started = True else: self.currentRepetitions = 0 started = False return started def updateWorkEndTime(self): self.workEndTime = QTime( self.workHoursSpinBox.value(), self.workMinutesSpinBox.value(), self.workSecondsSpinBox.value(), ) def updateRestEndTime(self): self.restEndTime = QTime( self.restHoursSpinBox.value(), self.restMinutesSpinBox.value(), self.restSecondsSpinBox.value(), ) def updateCurrentMode(self, mode: str): self.currentMode = Mode.work if mode == "work" else Mode.rest def updateTime(self): self.time = self.time.addSecs(1) self.totalTime = self.totalTime.addSecs(1) if self.modeComboBox.currentText() == "work": self.workTime = self.workTime.addSecs(1) else: self.restTime = self.restTime.addSecs(1) self.displayTime() def updateMaxRepetitions(self, value): if value == 0: self.currentRepetitions = 0 self.maxRepetitions = -1 else: self.maxRepetitions = 2 * value def maybeChangeMode(self): if self.currentMode is Mode.work and self.time >= self.workEndTime: self.resetTimer() self.modeComboBox.setCurrentIndex(1) self.incrementCurrentRepetitions() started = self.maybeStartTimer() self.showWindowMessage( Status.workFinished if started else Status.repetitionsReached) if not started: self.resetButton.click() elif self.currentMode is Mode.rest and self.time >= self.restEndTime: self.resetTimer() self.modeComboBox.setCurrentIndex(0) self.incrementCurrentRepetitions() started = self.maybeStartTimer() self.showWindowMessage( Status.restFinished if started else Status.repetitionsReached) if not started: self.resetButton.click() def incrementCurrentRepetitions(self): if self.maxRepetitions > 0: self.currentRepetitions += 1 def insertTask(self): task = self.taskTextEdit.toPlainText() self.insertTasks(task) def insertTasks(self, *tasks): for task in tasks: if task: rowCount = self.tasksTableWidget.rowCount() self.tasksTableWidget.setRowCount(rowCount + 1) self.tasksTableWidget.setItem(rowCount, 0, QTableWidgetItem(task)) self.tasksTableWidget.resizeRowsToContents() self.taskTextEdit.clear() def deleteTask(self): selectedIndexes = self.tasksTableWidget.selectedIndexes() if selectedIndexes: self.tasksTableWidget.removeRow(selectedIndexes[0].row()) def markTaskAsFinished(self, row, col): item = self.tasksTableWidget.item(row, col) font = self.tasksTableWidget.item(row, col).font() font.setStrikeOut(False if item.font().strikeOut() else True) item.setFont(font) def displayTime(self): self.timeDisplay.display(self.time.toString(self.timeFormat)) self.statisticsRestTimeDisplay.display( self.restTime.toString(self.timeFormat)) self.statisticsWorkTimeDisplay.display( self.workTime.toString(self.timeFormat)) self.statisticsTotalTimeDisplay.display( self.totalTime.toString(self.timeFormat)) def showWindowMessage(self, status): if status is Status.workFinished: title, text = "Break", choice(work_finished_phrases) elif status is Status.restFinished: title, text = "Work", choice(rest_finished_phrases) else: title, text = "Finished", choice(work_finished_phrases) self.trayIcon.showMessage(title, text, makeIcon("tomato")) self.toast.show_toast(title, text, icon_path="pomodoro/data/icons/tomato.ico", duration=10, threaded=True) def makeButton(self, text, iconName=None, disabled=True): button = QPushButton(text, sizePolicy=self.size_policy) if iconName: button.setIcon(makeIcon(iconName)) button.setDisabled(disabled) return button def exit(self): self.close() app = QApplication.instance() if app: app.quit() def onActivate(self, reason): if reason == QSystemTrayIcon.ActivationReason.Trigger: self.show()
class DocumentBaseViewerWidget(MainWindowContent): def __init__(self, main_window): super(DocumentBaseViewerWidget, self).__init__(main_window, "Document Base") # controls self.controls = QWidget() self.controls_layout = QHBoxLayout(self.controls) self.controls_layout.setContentsMargins(0, 0, 0, 0) self.controls_layout.setSpacing(10) self.controls_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.layout.addWidget(self.controls) self.create_document_base_button = QPushButton( "Create a new Document Base") self.create_document_base_button.setFont(BUTTON_FONT) self.create_document_base_button.clicked.connect( self.main_window.show_document_base_creator_widget_task) self.controls_layout.addWidget(self.create_document_base_button) self.load_and_run_default_preprocessing_phase_button = QPushButton( "Preprocess the Document Base") self.load_and_run_default_preprocessing_phase_button.setFont( BUTTON_FONT) self.load_and_run_default_preprocessing_phase_button.clicked.connect( self.main_window.load_and_run_default_preprocessing_phase_task) self.controls_layout.addWidget( self.load_and_run_default_preprocessing_phase_button) self.load_and_run_default_matching_phase_button = QPushButton( "Match the Nuggets to the Attributes") self.load_and_run_default_matching_phase_button.setFont(BUTTON_FONT) self.load_and_run_default_matching_phase_button.clicked.connect( self.main_window.load_and_run_default_matching_phase_task) self.controls_layout.addWidget( self.load_and_run_default_matching_phase_button) self.save_table_button = QPushButton("Export the Table to CSV") self.save_table_button.setFont(BUTTON_FONT) self.save_table_button.clicked.connect( self.main_window.save_table_to_csv_task) self.controls_layout.addWidget(self.save_table_button) # documents self.documents = MainWindowContentSection(self, "Documents:") self.layout.addWidget(self.documents) self.num_documents = QLabel("number of documents: -") self.num_documents.setFont(LABEL_FONT) self.documents.layout.addWidget(self.num_documents) self.num_nuggets = QLabel("number of nuggets: -") self.num_nuggets.setFont(LABEL_FONT) self.documents.layout.addWidget(self.num_nuggets) # attributes self.attributes = MainWindowContentSection(self, "Attributes:") self.layout.addWidget(self.attributes) self.add_attribute_button = QPushButton("Add Attribute") self.add_attribute_button.setFont(BUTTON_FONT) self.add_attribute_button.clicked.connect( self.main_window.add_attribute_task) self.attributes_list = CustomScrollableList(self, AttributeWidget, self.add_attribute_button) self.attributes.layout.addWidget(self.attributes_list) def update_document_base(self, document_base): # update documents self.num_documents.setText( f"number of documents: {len(document_base.documents)}") self.num_nuggets.setText( f"number of nuggets: {len(document_base.nuggets)}") # update attributes self.attributes_list.update_item_list(document_base.attributes, document_base) def enable_input(self): self.create_document_base_button.setEnabled(True) if self.main_window.document_base is not None: self.load_and_run_default_preprocessing_phase_button.setEnabled( True) self.load_and_run_default_matching_phase_button.setEnabled(True) self.save_table_button.setEnabled(True) self.add_attribute_button.setEnabled(True) self.attributes_list.enable_input() def disable_input(self): self.create_document_base_button.setDisabled(True) self.load_and_run_default_preprocessing_phase_button.setDisabled(True) self.load_and_run_default_matching_phase_button.setDisabled(True) self.save_table_button.setDisabled(True) self.add_attribute_button.setDisabled(True) self.attributes_list.disable_input()
class DocumentBaseCreatorWidget(MainWindowContent): def __init__(self, main_window) -> None: super(DocumentBaseCreatorWidget, self).__init__(main_window, "Create Document Base") self.documents = MainWindowContentSection(self, "Documents:") self.layout.addWidget(self.documents) self.documents_explanation = QLabel( "Enter the path of the directory that contains the documents as .txt files." ) self.documents_explanation.setFont(LABEL_FONT) self.documents.layout.addWidget(self.documents_explanation) self.path_widget = QFrame() self.path_layout = QHBoxLayout(self.path_widget) self.path_layout.setContentsMargins(20, 0, 20, 0) self.path_layout.setSpacing(10) self.path_widget.setStyleSheet("background-color: white") self.path_widget.setFixedHeight(40) self.documents.layout.addWidget(self.path_widget) self.path = QLineEdit() self.path.setFont(CODE_FONT_BOLD) self.path.setStyleSheet("border: none") self.path_layout.addWidget(self.path) self.edit_path_button = QPushButton() self.edit_path_button.setIcon(QIcon("aset_ui/resources/folder.svg")) self.edit_path_button.setFlat(True) self.edit_path_button.clicked.connect(self._edit_path_button_clicked) self.path_layout.addWidget(self.edit_path_button) self.attributes = MainWindowContentSection(self, "Attributes:") self.layout.addWidget(self.attributes) self.labels_explanation = QLabel("Enter the attribute names.") self.labels_explanation.setFont(LABEL_FONT) self.attributes.layout.addWidget(self.labels_explanation) self.create_attribute_button = QPushButton("New Attribute") self.create_attribute_button.setFont(BUTTON_FONT) self.create_attribute_button.clicked.connect( self._create_attribute_button_clicked) self.attribute_names = [] self.attributes_list = CustomScrollableList( self, AttributeCreatorWidget, self.create_attribute_button) self.attributes.layout.addWidget(self.attributes_list) self.buttons_widget = QWidget() self.buttons_layout = QHBoxLayout(self.buttons_widget) self.buttons_layout.setContentsMargins(0, 0, 0, 0) self.buttons_layout.setSpacing(10) self.buttons_layout.setAlignment(Qt.AlignmentFlag.AlignRight) self.attributes.layout.addWidget(self.buttons_widget) self.cancel_button = QPushButton("Cancel") self.cancel_button.setFont(BUTTON_FONT) self.cancel_button.clicked.connect(self._cancel_button_clicked) self.buttons_layout.addWidget(self.cancel_button) self.create_document_base_button = QPushButton("Create Document Base") self.create_document_base_button.setFont(BUTTON_FONT) self.create_document_base_button.clicked.connect( self._create_document_base_button_clicked) self.buttons_layout.addWidget(self.create_document_base_button) def enable_input(self): self.edit_path_button.setEnabled(True) self.create_attribute_button.setEnabled(True) self.cancel_button.setEnabled(True) self.create_document_base_button.setEnabled(True) self.attributes_list.enable_input() def disable_input(self): self.edit_path_button.setDisabled(True) self.create_attribute_button.setDisabled(True) self.cancel_button.setDisabled(True) self.create_document_base_button.setDisabled(True) self.attributes_list.disable_input() def initialize_for_new_document_base(self): self.path.setText("") self.attribute_names = [] self.attributes_list.update_item_list([]) def delete_attribute(self, attribute_name): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.attribute_names.remove(attribute_name) self.attributes_list.update_item_list(self.attribute_names) self.attributes_list.last_item_widget().name.setFocus() def _edit_path_button_clicked(self): path = str( QFileDialog.getExistingDirectory( self, "Choose a directory of text files.")) if path != "": path = f"{path}/*.txt" self.path.setText(path) def _create_attribute_button_clicked(self): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.attribute_names.append("") self.attributes_list.update_item_list(self.attribute_names) self.attributes_list.last_item_widget().name.setFocus() def _cancel_button_clicked(self): self.main_window.show_start_menu_widget() self.main_window.enable_global_input() def _create_document_base_button_clicked(self): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.main_window.create_document_base_task(self.path.text(), self.attribute_names)
def __init__( self, onPlayButtonPressed: Callable[[], None], onPauseButtonPressed: Callable[[], None], onStepButtonPressed: Callable[[], None], onRestartButtonPressed: Callable[[], None], parent: Optional[QWidget] = None, *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ The play, pause, step and restart buttons for the solver """ super(SolverControlButtonsView, self).__init__(parent=parent, *args, **kwargs) self.setContentsMargins(0, 0, 0, 0) buttonsLayout = QHBoxLayout() buttonsLayout.setContentsMargins(0, 0, 0, 0) ### ### Play, pause, step and restart buttons ### self.__playButton = LabelledIconButton( icon=QStyle.StandardPixmap.SP_MediaPlay, labelText="Play", parent=self, ) self.__playButton.onButtonPressed.connect( onPlayButtonPressed) # type: ignore self.__pauseButton = LabelledIconButton( icon=QStyle.StandardPixmap.SP_MediaPause, labelText="Pause", parent=self, ) self.__pauseButton.onButtonPressed.connect( onPauseButtonPressed) # type: ignore self.__stepButton = LabelledIconButton( icon=QStyle.StandardPixmap.SP_ArrowForward, labelText="Step", parent=self, ) self.__stepButton.onButtonPressed.connect( onStepButtonPressed) # type: ignore self.__restartButton = LabelledIconButton( icon=QStyle.StandardPixmap.SP_BrowserReload, labelText="Restart", parent=self, ) self.__restartButton.onButtonPressed.connect( onRestartButtonPressed) # type: ignore buttonsLayout.addWidget(self.__playButton) buttonsLayout.addWidget(self.__pauseButton) buttonsLayout.addWidget(self.__stepButton) buttonsLayout.addWidget(self.__restartButton) self.setLayout(buttonsLayout)
class ManageData(QMainWindow): populateGallery = pyqtSignal() closedWindow = pyqtSignal(object) def __init__(self): super(ManageData, self).__init__() self.setWindowTitle('Manage Data') self.configure_gui() self.create_widgets() self.create_menu() self.showMaximized() self.mysql = Authenticate() def configure_gui(self): self.center = QWidget(self) self.layout = QHBoxLayout() self.center.setLayout(self.layout) self.setCentralWidget(self.center) self.layout.setContentsMargins(5, 0, 5, 0) self.layout.setSpacing(0) def create_widgets(self): self.windows = set() self.gallery = Gallery(self) self.preview = Preview(self, 'white') self.layout.addWidget(self.gallery) self.layout.addWidget(self.preview) self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.statusbar.setFixedHeight(25) def create_menu(self): pass def keyPressEvent(self, event): key_press = event.key() modifiers = event.modifiers() alt = modifiers == Qt.Modifier.ALT if alt: if key_press == Qt.Key_Left: self.ribbon.go_back() elif key_press == Qt.Key_Right: self.ribbon.go_forward() if key_press == Qt.Key.Key_F4: self.ribbon.tags.setFocus() elif key_press == Qt.Key.Key_F5: self.select_records() elif key_press == Qt.Key.Key_Delete: self.delete_records(self.gallery.selectedIndexes()) elif key_press == Qt.Key.Key_Escape: self.close() def closeEvent(self, event): self.mysql.close() for window in self.windows: window.close() self.closedWindow.emit(self)
class MainWindow(QMainWindow): ################################ # signals (aset ui --> aset api) ################################ create_document_base = pyqtSignal(str, list) add_attribute = pyqtSignal(str, ASETDocumentBase) remove_attribute = pyqtSignal(str, ASETDocumentBase) forget_matches_for_attribute = pyqtSignal(str, ASETDocumentBase) load_document_base_from_bson = pyqtSignal(str) save_document_base_to_bson = pyqtSignal(str, ASETDocumentBase) save_table_to_csv = pyqtSignal(str, ASETDocumentBase) forget_matches = pyqtSignal(ASETDocumentBase) load_preprocessing_phase_from_config = pyqtSignal(str) save_preprocessing_phase_to_config = pyqtSignal(str, PreprocessingPhase) load_matching_phase_from_config = pyqtSignal(str) save_matching_phase_to_config = pyqtSignal(str, BaseMatchingPhase) run_preprocessing_phase = pyqtSignal(ASETDocumentBase, PreprocessingPhase, Statistics) run_matching_phase = pyqtSignal(ASETDocumentBase, BaseMatchingPhase, Statistics) save_statistics_to_json = pyqtSignal(str, Statistics) load_and_run_default_preprocessing_phase = pyqtSignal(ASETDocumentBase, Statistics) load_and_run_default_matching_phase = pyqtSignal(ASETDocumentBase, Statistics) ############################## # slots (aset api --> aset ui) ############################## @pyqtSlot(str, float) def status(self, message, progress): logger.debug("Called slot 'status'.") self.status_widget_message.setText(message) if progress == -1: self.status_widget_progress.setRange(0, 0) else: self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(int(progress * 100)) @pyqtSlot(str) def finished(self, message): logger.debug("Called slot 'finished'.") self.status_widget_message.setText(message) self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(100) self.show_document_base_viewer_widget() self.enable_global_input() @pyqtSlot(str) def error(self, message): logger.debug("Called slot 'error'.") self.status_widget_message.setText(message) self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(0) self.show_document_base_viewer_widget() self.enable_global_input() @pyqtSlot(ASETDocumentBase) def document_base_to_ui(self, document_base): logger.debug("Called slot 'document_base_to_ui'.") self.document_base = document_base self.document_base_viewer_widget.update_document_base(self.document_base) self._was_enabled.append(self.save_document_base_to_bson_action) self._was_enabled.append(self.save_table_to_csv_action) self._was_enabled.append(self.add_attribute_action) self._was_enabled.append(self.remove_attribute_action) self._was_enabled.append(self.forget_matches_for_attribute_action) self._was_enabled.append(self.forget_matches_action) self._was_enabled.append(self.load_and_run_default_preprocessing_phase_action) self._was_enabled.append(self.load_and_run_default_matching_phase_action) if self.preprocessing_phase is not None: self._was_enabled.append(self.run_preprocessing_phase_action) if self.matching_phase is not None: self._was_enabled.append(self.run_matching_phase_action) @pyqtSlot(PreprocessingPhase) def preprocessing_phase_to_ui(self, preprocessing_phase): logger.debug("Called slot 'preprocessing_phase_to_ui'.") self.preprocessing_phase = preprocessing_phase self._was_enabled.append(self.save_preprocessing_phase_to_config_action) if self.document_base is not None: self._was_enabled.append(self.run_preprocessing_phase_action) @pyqtSlot(BaseMatchingPhase) def matching_phase_to_ui(self, matching_phase): logger.debug("Called slot 'matching_phase_to_ui'.") self.matching_phase = matching_phase self._was_enabled.append(self.save_matching_phase_to_config_action) if self.document_base is not None: self._was_enabled.append(self.run_preprocessing_phase_action) @pyqtSlot(Statistics) def statistics_to_ui(self, statistics): logger.debug("Called slot 'statistics_to_ui'.") self.statistics = statistics @pyqtSlot(dict) def feedback_request_to_ui(self, feedback_request): logger.debug("Called slot 'feedback_request_to_ui'.") self.interactive_matching_widget.handle_feedback_request(feedback_request) # noinspection PyUnresolvedReferences def _connect_slots_and_signals(self): self.create_document_base.connect(self.api.create_document_base) self.add_attribute.connect(self.api.add_attribute) self.remove_attribute.connect(self.api.remove_attribute) self.forget_matches_for_attribute.connect(self.api.forget_matches_for_attribute) self.load_document_base_from_bson.connect(self.api.load_document_base_from_bson) self.save_document_base_to_bson.connect(self.api.save_document_base_to_bson) self.save_table_to_csv.connect(self.api.save_table_to_csv) self.forget_matches.connect(self.api.forget_matches) self.load_preprocessing_phase_from_config.connect(self.api.load_preprocessing_phase_from_config) self.save_preprocessing_phase_to_config.connect(self.api.save_preprocessing_phase_to_config) self.load_matching_phase_from_config.connect(self.api.load_matching_phase_from_config) self.save_matching_phase_to_config.connect(self.api.save_matching_phase_to_config) self.run_preprocessing_phase.connect(self.api.run_preprocessing_phase) self.run_matching_phase.connect(self.api.run_matching_phase) self.save_statistics_to_json.connect(self.api.save_statistics_to_json) self.load_and_run_default_preprocessing_phase.connect(self.api.load_and_run_default_preprocessing_phase) self.load_and_run_default_matching_phase.connect(self.api.load_and_run_default_matching_phase) self.api.status.connect(self.status) self.api.finished.connect(self.finished) self.api.error.connect(self.error) self.api.document_base_to_ui.connect(self.document_base_to_ui) self.api.preprocessing_phase_to_ui.connect(self.preprocessing_phase_to_ui) self.api.matching_phase_to_ui.connect(self.matching_phase_to_ui) self.api.statistics_to_ui.connect(self.statistics_to_ui) self.api.feedback_request_to_ui.connect(self.feedback_request_to_ui) ####### # tasks ####### def load_document_base_from_bson_task(self): logger.info("Execute task 'load_document_base_from_bson_task'.") path, ok = QFileDialog.getOpenFileName(self, "Choose a document collection .bson file!") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.load_document_base_from_bson.emit(str(path)) def save_document_base_to_bson_task(self): logger.info("Execute task 'save_document_base_to_bson_task'.") if self.document_base is not None: path, ok = QFileDialog.getSaveFileName(self, "Choose where to save the document collection .bson file!") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.save_document_base_to_bson.emit(str(path), self.document_base) def add_attribute_task(self): logger.info("Execute task 'add_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Create Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.add_attribute.emit(str(name), self.document_base) def remove_attribute_task(self): logger.info("Execute task 'remove_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Remove Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.remove_attribute.emit(str(name), self.document_base) def remove_attribute_with_given_name_task(self, attribute_name): logger.info("Execute task 'remove_attribute_with_given_name_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.remove_attribute.emit(str(attribute_name), self.document_base) def forget_matches_for_attribute_task(self): logger.info("Execute task 'forget_matches_for_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Forget Matches for Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches_for_attribute.emit(str(name), self.document_base) def forget_matches_for_attribute_with_given_name_task(self, attribute_name): logger.info("Execute task 'forget_matches_for_attribute_with_given_name_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches_for_attribute.emit(attribute_name, self.document_base) def forget_matches_task(self): logger.info("Execute task 'forget_matches_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches.emit(self.document_base) def enable_collect_statistics_task(self): logger.info("Execute task 'task_enable_collect_statistics'.") self.collect_statistics = True self.enable_collect_statistics_action.setEnabled(False) self.disable_collect_statistics_action.setEnabled(True) def disable_collect_statistics_task(self): logger.info("Execute task 'disable_collect_statistics_task'.") self.collect_statistics = False self.disable_collect_statistics_action.setEnabled(False) self.enable_collect_statistics_action.setEnabled(True) def save_statistics_to_json_task(self): logger.info("Execute task 'save_statistics_to_json_task'.") if self.statistics is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the statistics .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_statistics_to_json.emit(path, self.statistics) def show_document_base_creator_widget_task(self): logger.info("Execute task 'show_document_base_creator_widget_task'.") self.disable_global_input() self.document_base_creator_widget.enable_input() self.document_base_creator_widget.initialize_for_new_document_base() self.show_document_base_creator_widget() self.document_base_creator_widget.path.setFocus() def create_document_base_task(self, path, attribute_names): logger.info("Execute task 'create_document_base_task'.") self.disable_global_input() # noinspection PyUnresolvedReferences self.create_document_base.emit(path, attribute_names) def save_table_to_csv_task(self): logger.info("Execute task 'save_table_to_csv_task'.") if self.document_base is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the table .csv file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_table_to_csv.emit(path, self.document_base) def load_preprocessing_phase_from_config_task(self): logger.info("Execute task 'load_preprocessing_phase_from_config_task'.") path = str(QFileDialog.getOpenFileName(self, "Choose a configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.load_preprocessing_phase_from_config.emit(path) def save_preprocessing_phase_to_config_task(self): logger.info("Execute task 'save_preprocessing_phase_to_config_task'.") if self.preprocessing_phase is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_preprocessing_phase_to_config.emit(path, self.preprocessing_phase) def load_matching_phase_from_config_task(self): logger.info("Execute task 'load_matching_phase_from_config_task'.") path = str(QFileDialog.getOpenFileName(self, "Choose a configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.load_matching_phase_from_config.emit(path) def save_matching_phase_to_config_task(self): logger.info("Execute task 'save_matching_phase_to_config_task'.") if self.matching_phase is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_matching_phase_to_config.emit(path, self.matching_phase) def run_preprocessing_phase_task(self): logger.info("Execute task 'run_preprocessing_phase_task'.") if self.document_base is not None and self.preprocessing_phase is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() # noinspection PyUnresolvedReferences self.run_preprocessing_phase.emit(self.document_base, self.preprocessing_phase, self.statistics) def run_matching_phase_task(self): logger.info("Execute task 'run_matching_phase_task'.") if self.document_base is not None and self.matching_phase is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() self.interactive_matching_widget.enable_input() self.show_interactive_matching_widget() # noinspection PyUnresolvedReferences self.run_matching_phase.emit(self.document_base, self.matching_phase, self.statistics) def give_feedback_task(self, feedback): logger.info("Execute task 'give_feedback_task'.") self.api.feedback = feedback self.feedback_cond.wakeAll() def load_and_run_default_preprocessing_phase_task(self): logger.info("Execute task 'load_and_run_default_preprocessing_phase_task'.") if self.document_base is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() # noinspection PyUnresolvedReferences self.load_and_run_default_preprocessing_phase.emit(self.document_base, self.statistics) def load_and_run_default_matching_phase_task(self): logger.info("Execute task 'load_and_run_default_matching_phase_task'.") if self.document_base is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() self.interactive_matching_widget.enable_input() self.show_interactive_matching_widget() # noinspection PyUnresolvedReferences self.load_and_run_default_matching_phase.emit(self.document_base, self.statistics) ################## # controller logic ################## def enable_global_input(self): for action in self._was_enabled: action.setEnabled(True) self.document_base_creator_widget.enable_input() self.document_base_viewer_widget.enable_input() self.interactive_matching_widget.enable_input() self._was_enabled = [] def disable_global_input(self): for action in self._all_actions: if action.isEnabled(): self._was_enabled.append(action) action.setEnabled(False) self.document_base_creator_widget.disable_input() self.document_base_viewer_widget.disable_input() self.interactive_matching_widget.disable_input() def show_document_base_viewer_widget(self): if self.document_base_viewer_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.interactive_matching_widget.hide() self.document_base_creator_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.addWidget(self.document_base_viewer_widget) self.document_base_viewer_widget.show() self.central_widget_layout.update() def show_interactive_matching_widget(self): if self.interactive_matching_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.document_base_viewer_widget.hide() self.document_base_creator_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.addWidget(self.interactive_matching_widget) self.interactive_matching_widget.show() self.central_widget_layout.update() def show_document_base_creator_widget(self): if self.document_base_creator_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.document_base_viewer_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.addWidget(self.document_base_creator_widget) self.document_base_creator_widget.show() self.central_widget_layout.update() def show_start_menu_widget(self): if self.start_menu_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) self.document_base_viewer_widget.hide() self.document_base_creator_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.addWidget(self.start_menu_widget) self.start_menu_widget.show() self.central_widget_layout.update() def __init__(self) -> None: super(MainWindow, self).__init__() self.setWindowTitle("ASET") self.document_base = None self.preprocessing_phase = None self.matching_phase = None self.statistics = Statistics(True) self.collect_statistics = True # set up the api_thread and api and connect slots and signals self.feedback_mutex = QMutex() self.feedback_cond = QWaitCondition() self.api = ASETAPI(self.feedback_mutex, self.feedback_cond) self.api_thread = QThread() self.api.moveToThread(self.api_thread) self._connect_slots_and_signals() self.api_thread.start() # set up the status bar self.status_bar = self.statusBar() self.status_bar.setFont(STATUS_BAR_FONT) self.status_widget = QWidget(self.status_bar) self.status_widget_layout = QHBoxLayout(self.status_widget) self.status_widget_layout.setContentsMargins(0, 0, 0, 0) self.status_widget_message = QLabel() self.status_widget_message.setFont(STATUS_BAR_FONT) self.status_widget_message.setMinimumWidth(10) self.status_widget_layout.addWidget(self.status_widget_message) self.status_widget_progress = QProgressBar() self.status_widget_progress.setMinimumWidth(10) self.status_widget_progress.setMaximumWidth(200) self.status_widget_progress.setTextVisible(False) self.status_widget_progress.setMaximumHeight(20) self.status_widget_layout.addWidget(self.status_widget_progress) self.status_bar.addPermanentWidget(self.status_widget) # set up the actions self._all_actions = [] self._was_enabled = [] self.exit_action = QAction("&Exit", self) self.exit_action.setIcon(QIcon("aset_ui/resources/leave.svg")) self.exit_action.setStatusTip("Exit the application.") self.exit_action.triggered.connect(QApplication.instance().quit) self._all_actions.append(self.exit_action) self.show_document_base_creator_widget_action = QAction("&Create new document base", self) self.show_document_base_creator_widget_action.setIcon(QIcon("aset_ui/resources/two_documents.svg")) self.show_document_base_creator_widget_action.setStatusTip( "Create a new document base from a collection of .txt files and a list of attribute names." ) self.show_document_base_creator_widget_action.triggered.connect(self.show_document_base_creator_widget_task) self._all_actions.append(self.show_document_base_creator_widget_action) self.add_attribute_action = QAction("&Add attribute", self) self.add_attribute_action.setIcon(QIcon("aset_ui/resources/plus.svg")) self.add_attribute_action.setStatusTip("Add a new attribute to the document base.") self.add_attribute_action.triggered.connect(self.add_attribute_task) self.add_attribute_action.setEnabled(False) self._all_actions.append(self.add_attribute_action) self.remove_attribute_action = QAction("&Remove attribute", self) self.remove_attribute_action.setIcon(QIcon("aset_ui/resources/trash.svg")) self.remove_attribute_action.setStatusTip("Remove an attribute from the document base.") self.remove_attribute_action.triggered.connect(self.remove_attribute_task) self.remove_attribute_action.setEnabled(False) self._all_actions.append(self.remove_attribute_action) self.forget_matches_for_attribute_action = QAction("&Forget matches for attribute", self) self.forget_matches_for_attribute_action.setIcon(QIcon("aset_ui/resources/redo.svg")) self.forget_matches_for_attribute_action.setStatusTip("Forget the matches for a single attribute.") self.forget_matches_for_attribute_action.triggered.connect(self.forget_matches_for_attribute_task) self.forget_matches_for_attribute_action.setEnabled(False) self._all_actions.append(self.forget_matches_for_attribute_action) self.load_document_base_from_bson_action = QAction("&Load document base", self) self.load_document_base_from_bson_action.setIcon(QIcon("aset_ui/resources/folder.svg")) self.load_document_base_from_bson_action.setStatusTip("Load an existing document base from a .bson file.") self.load_document_base_from_bson_action.triggered.connect(self.load_document_base_from_bson_task) self._all_actions.append(self.load_document_base_from_bson_action) self.save_document_base_to_bson_action = QAction("&Save document base", self) self.save_document_base_to_bson_action.setIcon(QIcon("aset_ui/resources/save.svg")) self.save_document_base_to_bson_action.setStatusTip("Save the document base in a .bson file.") self.save_document_base_to_bson_action.triggered.connect(self.save_document_base_to_bson_task) self.save_document_base_to_bson_action.setEnabled(False) self._all_actions.append(self.save_document_base_to_bson_action) self.save_table_to_csv_action = QAction("&Export table to CSV", self) self.save_table_to_csv_action.setIcon(QIcon("aset_ui/resources/table.svg")) self.save_table_to_csv_action.setStatusTip("Save the table to a .csv file.") self.save_table_to_csv_action.triggered.connect(self.save_table_to_csv_task) self.save_table_to_csv_action.setEnabled(False) self._all_actions.append(self.save_table_to_csv_action) self.forget_matches_action = QAction("&Forget all matches", self) self.forget_matches_action.setIcon(QIcon("aset_ui/resources/redo.svg")) self.forget_matches_action.setStatusTip("Forget the matches for all attributes.") self.forget_matches_action.triggered.connect(self.forget_matches_task) self.forget_matches_action.setEnabled(False) self._all_actions.append(self.forget_matches_action) self.load_and_run_default_preprocessing_phase_action = QAction( "&Load and run default preprocessing phase", self ) self.load_and_run_default_preprocessing_phase_action.setStatusTip( "Load the default preprocessing phase and run it on the document collection." ) self.load_and_run_default_preprocessing_phase_action.setIcon(QIcon("aset_ui/resources/run_run.svg")) self.load_and_run_default_preprocessing_phase_action.setDisabled(True) self.load_and_run_default_preprocessing_phase_action.triggered.connect( self.load_and_run_default_preprocessing_phase_task ) self._all_actions.append(self.load_and_run_default_preprocessing_phase_action) self.load_preprocessing_phase_from_config_action = QAction("&Load preprocessing phase", self) self.load_preprocessing_phase_from_config_action.setStatusTip( "Load a preprocessing phase from a .json configuration file." ) self.load_preprocessing_phase_from_config_action.triggered.connect( self.load_preprocessing_phase_from_config_task ) self._all_actions.append(self.load_preprocessing_phase_from_config_action) self.save_preprocessing_phase_to_config_action = QAction("&Save preprocessing phase", self) self.save_preprocessing_phase_to_config_action.setStatusTip( "Save the preprocessing phase in a .json configuration file." ) self.save_preprocessing_phase_to_config_action.triggered.connect(self.save_preprocessing_phase_to_config_task) self.save_preprocessing_phase_to_config_action.setEnabled(False) self._all_actions.append(self.save_preprocessing_phase_to_config_action) self.run_preprocessing_phase_action = QAction("Run preprocessing phase", self) self.run_preprocessing_phase_action.setIcon(QIcon("aset_ui/resources/run.svg")) self.run_preprocessing_phase_action.setStatusTip("Run the preprocessing phase on the document collection.") self.run_preprocessing_phase_action.triggered.connect(self.run_preprocessing_phase_task) self.run_preprocessing_phase_action.setEnabled(False) self._all_actions.append(self.run_preprocessing_phase_action) self.load_and_run_default_matching_phase_action = QAction( "&Load and run default matching phase", self ) self.load_and_run_default_matching_phase_action.setStatusTip( "Load the default matching phase and run it on the document collection." ) self.load_and_run_default_matching_phase_action.setIcon(QIcon("aset_ui/resources/run_run.svg")) self.load_and_run_default_matching_phase_action.setDisabled(True) self.load_and_run_default_matching_phase_action.triggered.connect( self.load_and_run_default_preprocessing_phase_task ) self._all_actions.append(self.load_and_run_default_matching_phase_action) self.load_matching_phase_from_config_action = QAction("&Load matching phase", self) self.load_matching_phase_from_config_action.setStatusTip( "Load a matching phase from a .json configuration file." ) self.load_matching_phase_from_config_action.triggered.connect(self.load_matching_phase_from_config_task) self._all_actions.append(self.load_matching_phase_from_config_action) self.save_matching_phase_to_config_action = QAction("&Save matching phase", self) self.save_matching_phase_to_config_action.setStatusTip("Save the matching phase in a .json configuration file.") self.save_matching_phase_to_config_action.triggered.connect(self.save_matching_phase_to_config_task) self.save_matching_phase_to_config_action.setEnabled(False) self._all_actions.append(self.save_matching_phase_to_config_action) self.run_matching_phase_action = QAction("Run matching phase", self) self.run_matching_phase_action.setIcon(QIcon("aset_ui/resources/run.svg")) self.run_matching_phase_action.setStatusTip("Run the matching phase on the document collection.") self.run_matching_phase_action.triggered.connect(self.run_matching_phase_task) self.run_matching_phase_action.setEnabled(False) self._all_actions.append(self.run_matching_phase_action) self.enable_collect_statistics_action = QAction("&Enable statistics", self) self.enable_collect_statistics_action.setIcon(QIcon("aset_ui/resources/statistics.svg")) self.enable_collect_statistics_action.setStatusTip("Enable collecting statistics.") self.enable_collect_statistics_action.triggered.connect(self.enable_collect_statistics_task) self.enable_collect_statistics_action.setEnabled(False) self._all_actions.append(self.enable_collect_statistics_action) self.disable_collect_statistics_action = QAction("&Disable statistics", self) self.disable_collect_statistics_action.setIcon(QIcon("aset_ui/resources/statistics_incorrect.svg")) self.disable_collect_statistics_action.setStatusTip("Disable collecting statistics.") self.disable_collect_statistics_action.triggered.connect(self.disable_collect_statistics_task) self._all_actions.append(self.disable_collect_statistics_action) self.save_statistics_to_json_action = QAction("&Save statistics", self) self.save_statistics_to_json_action.setIcon(QIcon("aset_ui/resources/statistics_save.svg")) self.save_statistics_to_json_action.setStatusTip("Save the statistics to a .json file.") self.save_statistics_to_json_action.triggered.connect(self.save_statistics_to_json_task) self.save_statistics_to_json_action.setEnabled(False) self._all_actions.append(self.save_statistics_to_json_action) # set up the menu bar self.menubar = self.menuBar() self.menubar.setFont(MENU_FONT) self.file_menu = self.menubar.addMenu("&File") self.file_menu.setFont(MENU_FONT) self.file_menu.addAction(self.exit_action) self.document_base_menu = self.menubar.addMenu("&Document Base") self.document_base_menu.setFont(MENU_FONT) self.document_base_menu.addAction(self.show_document_base_creator_widget_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.load_document_base_from_bson_action) self.document_base_menu.addAction(self.save_document_base_to_bson_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.save_table_to_csv_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.add_attribute_action) self.document_base_menu.addAction(self.remove_attribute_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.forget_matches_for_attribute_action) self.document_base_menu.addAction(self.forget_matches_action) self.preprocessing_menu = self.menubar.addMenu("&Preprocessing") self.preprocessing_menu.setFont(MENU_FONT) self.preprocessing_menu.addAction(self.load_and_run_default_preprocessing_phase_action) self.preprocessing_menu.addSeparator() self.preprocessing_menu.addAction(self.load_preprocessing_phase_from_config_action) self.preprocessing_menu.addAction(self.save_preprocessing_phase_to_config_action) self.preprocessing_menu.addSeparator() self.preprocessing_menu.addAction(self.run_preprocessing_phase_action) self.matching_menu = self.menubar.addMenu("&Matching") self.matching_menu.setFont(MENU_FONT) self.matching_menu.addAction(self.load_and_run_default_matching_phase_action) self.matching_menu.addSeparator() self.matching_menu.addAction(self.load_matching_phase_from_config_action) self.matching_menu.addAction(self.save_matching_phase_to_config_action) self.matching_menu.addSeparator() self.matching_menu.addAction(self.run_matching_phase_action) self.statistics_menu = self.menubar.addMenu("&Statistics") self.statistics_menu.setFont(MENU_FONT) self.statistics_menu.addAction(self.enable_collect_statistics_action) self.statistics_menu.addAction(self.disable_collect_statistics_action) self.statistics_menu.addSeparator() self.statistics_menu.addAction(self.save_statistics_to_json_action) # start menu self.start_menu_widget = QWidget() self.start_menu_layout = QVBoxLayout(self.start_menu_widget) self.start_menu_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_layout.setSpacing(30) self.start_menu_layout.setAlignment(Qt.AlignmentFlag.AlignTop) self.start_menu_widget.setMaximumWidth(400) self.start_menu_header = QLabel("Welcome to ASET!") self.start_menu_header.setFont(HEADER_FONT) self.start_menu_layout.addWidget(self.start_menu_header) self.start_menu_create_new_document_base_widget = QWidget() self.start_menu_create_new_document_base_layout = QVBoxLayout(self.start_menu_create_new_document_base_widget) self.start_menu_create_new_document_base_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_create_new_document_base_layout.setSpacing(10) self.start_menu_layout.addWidget(self.start_menu_create_new_document_base_widget) self.start_menu_create_new_document_base_subheader = QLabel("Create a new document base.") self.start_menu_create_new_document_base_subheader.setFont(SUBHEADER_FONT) self.start_menu_create_new_document_base_layout.addWidget(self.start_menu_create_new_document_base_subheader) self.start_menu_create_new_document_base_wrapper_widget = QWidget() self.start_menu_create_new_document_base_wrapper_layout = QHBoxLayout( self.start_menu_create_new_document_base_wrapper_widget) self.start_menu_create_new_document_base_wrapper_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_create_new_document_base_wrapper_layout.setSpacing(20) self.start_menu_create_new_document_base_wrapper_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_create_new_document_base_layout.addWidget( self.start_menu_create_new_document_base_wrapper_widget) self.start_menu_create_document_base_button = QPushButton() self.start_menu_create_document_base_button.setFixedHeight(45) self.start_menu_create_document_base_button.setFixedWidth(45) self.start_menu_create_document_base_button.setIcon(QIcon("aset_ui/resources/two_documents.svg")) self.start_menu_create_document_base_button.clicked.connect(self.show_document_base_creator_widget_task) self.start_menu_create_new_document_base_wrapper_layout.addWidget(self.start_menu_create_document_base_button) self.start_menu_create_document_base_label = QLabel( "Create a new document base from a directory\nof .txt files and a list of attribute names.") self.start_menu_create_document_base_label.setFont(LABEL_FONT) self.start_menu_create_new_document_base_wrapper_layout.addWidget(self.start_menu_create_document_base_label) self.start_menu_load_document_base_widget = QWidget() self.start_menu_load_document_base_layout = QVBoxLayout(self.start_menu_load_document_base_widget) self.start_menu_load_document_base_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_load_document_base_layout.setSpacing(10) self.start_menu_layout.addWidget(self.start_menu_load_document_base_widget) self.start_menu_load_document_base_subheader = QLabel("Load an existing document base.") self.start_menu_load_document_base_subheader.setFont(SUBHEADER_FONT) self.start_menu_load_document_base_layout.addWidget(self.start_menu_load_document_base_subheader) self.start_menu_load_document_base_wrapper_widget = QWidget() self.start_menu_load_document_base_wrapper_layout = QHBoxLayout( self.start_menu_load_document_base_wrapper_widget) self.start_menu_load_document_base_wrapper_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_load_document_base_wrapper_layout.setSpacing(20) self.start_menu_load_document_base_wrapper_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_load_document_base_layout.addWidget(self.start_menu_load_document_base_wrapper_widget) self.start_menu_load_document_base_button = QPushButton() self.start_menu_load_document_base_button.setFixedHeight(45) self.start_menu_load_document_base_button.setFixedWidth(45) self.start_menu_load_document_base_button.setIcon(QIcon("aset_ui/resources/folder.svg")) self.start_menu_load_document_base_button.clicked.connect(self.load_document_base_from_bson_task) self.start_menu_load_document_base_wrapper_layout.addWidget(self.start_menu_load_document_base_button) self.start_menu_load_document_base_label = QLabel("Load an existing document base\nfrom a .bson file.") self.start_menu_load_document_base_label.setFont(LABEL_FONT) self.start_menu_load_document_base_wrapper_layout.addWidget(self.start_menu_load_document_base_label) # main UI self.central_widget = QWidget(self) self.central_widget_layout = QHBoxLayout(self.central_widget) self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setCentralWidget(self.central_widget) self.document_base_creator_widget = DocumentBaseCreatorWidget(self) self.document_base_viewer_widget = DocumentBaseViewerWidget(self) self.interactive_matching_widget = InteractiveMatchingWidget(self) self.document_base_creator_widget.hide() self.document_base_viewer_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.addWidget(self.start_menu_widget) self.central_widget_layout.update() self.resize(1400, 800) self.show() logger.info("Initialized MainWindow.")