class Layout(Slots): def __init__(self): super().__init__() def stored_location_layout(self): self.stored_directories_title = QLabel(constants.stored_dir_str) # Combo box and its properties self.stored_dir_dropdown = QComboBox() self.stored_dir_dropdown.addItems(self.get_list_items()) self.stored_dir_dropdown.setCursor(QCursor(Qt.PointingHandCursor)) self.stored_dir_dropdown.setStyleSheet(stored_dir_dropdown_styles) # Layout grid for combo box widget self.stored_dirs_layout = QGridLayout() self.stored_dirs_layout.addWidget(self.stored_directories_title, 0, 0) self.stored_dirs_layout.addWidget(self.stored_dir_dropdown, 0, 1) self.stored_dirs_layout.setColumnStretch(1, 2) self.stored_dirs_layout.setContentsMargins(0, 16, 0, 32) return self.stored_dirs_layout def push_to_group_layout(self): # Create a group self.group_push_to = QGroupBox(constants.push_branch_str) self.group_push_to.setStyleSheet(group_widgets_styles) # Create the layout for the branch widgets self.pushToLayout = QVBoxLayout() self.pushToLayout.setAlignment(Qt.AlignTop) self.pushToLayout.setContentsMargins(16, 24, 16, 24) # Set the layout to the group self.group_push_to.setLayout(self.pushToLayout) # Create the staging button and its properties self.staging_btn = QPushButton(constants.master_to_staging_str) self.staging_btn.clicked.connect( lambda: self.handle_branch_push_to_git(constants.master, constants. staging)) self.staging_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.staging_btn.setStyleSheet(button_styles) # Create the production button and its properties self.prod_btn = QPushButton(constants.staging_to_prod_str) self.prod_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.prod_btn.clicked.connect(lambda: self.handle_branch_push_to_git( constants.staging, constants.production)) self.prod_btn.setStyleSheet(button_styles) self.thread = Thread() self.thread.finished.connect(lambda: self.staging_btn.setEnabled(True)) self.thread.finished.connect(lambda: self.prod_btn.setEnabled(True)) # Add the button widgets to the layout self.pushToLayout.addWidget(self.staging_btn) self.pushToLayout.addWidget(self.prod_btn) return self.group_push_to
class ArrayRequirementEditor: def __init__(self, parent: QWidget, parent_layout: QVBoxLayout, resource_database: ResourceDatabase, requirement: Union[RequirementOr, RequirementAnd]): self._editors = [] self.resource_database = resource_database self._array_type = type(requirement) self.group_box = QGroupBox(parent) self.group_box.setStyleSheet("QGroupBox { margin-top: 2px; }") parent_layout.addWidget(self.group_box) self.item_layout = QVBoxLayout(self.group_box) self.item_layout.setContentsMargins(8, 2, 2, 6) self.item_layout.setAlignment(Qt.AlignTop) self.new_item_button = QPushButton(self.group_box) self.new_item_button.setMaximumWidth(75) self.new_item_button.setText("New Row") self.new_item_button.clicked.connect(self.new_item) for item in requirement.items: self._create_item(item) self.item_layout.addWidget(self.new_item_button) def _create_item(self, item: Requirement): def on_remove(): self._editors.remove(nested_editor) nested_editor.deleteLater() nested_editor = RequirementEditor(self.group_box, self.item_layout, self.resource_database, on_remove=on_remove) nested_editor.create_specialized_editor(item) self._editors.append(nested_editor) def new_item(self): self._create_item( _create_default_resource_requirement(self.resource_database)) self.item_layout.removeWidget(self.new_item_button) self.item_layout.addWidget(self.new_item_button) def deleteLater(self): self.group_box.deleteLater() for editor in self._editors: editor.deleteLater() self.new_item_button.deleteLater() @property def current_requirement(self) -> Union[RequirementOr, RequirementAnd]: return self._array_type( [editor.current_requirement for editor in self._editors])
def gui_init(self): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) group = QGroupBox("{} {}".format(self.__label, self.qapp.tr("axis")), self) group.setStyleSheet("QGroupBox::title {" "text-align: left;" "font: bold 14px;" "})") layout.addWidget(group) group_layout = QVBoxLayout() group.setLayout(group_layout) self.dir_buttons = dirButtons(self.__delay, buttons_action=self.axis_callback) group_layout.addWidget(self.dir_buttons) other_options = QWidget() group_layout.addWidget(other_options) other_layout = QHBoxLayout() other_layout.setContentsMargins(0, 10, 0, 0) other_options.setLayout(other_layout) speed_field = inputField(self.qapp.tr("Speed"), self.__speed, value_type=VALUETYPE.VALUE, parent=self, callback=self.speed_changed) other_layout.addWidget(speed_field, Qt.AlignLeft) value_field = inputField( self.qapp.tr("Value"), self.__dir_value, value_type=VALUETYPE.VALUE, ipRegex=QRegExp("^((-[1-9]\\d{,3})|([1-9]\\d{,3}))|[0]$"), parent=self, runner=self.axis_callback) other_options.layout().addWidget(value_field, Qt.AlignRight)
def initUI(self): self.image = DicomImage() self.pixmap = QPixmap() self.image_label = QLabel() self.image_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.image_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.image_label.setPixmap(self.pixmap) self.tags_view = Dicom_Tags_Widget(['']) self.tools = Dicom_ImageToolsWidget() self.tabs_widget = self.__inti_tab_widget__( [self.tags_view, self.tools]) self.tabs_widget.setMaximumWidth(600) image_layout = QVBoxLayout() image_layout.setContentsMargins(0, 0, 0, 0) image_layout.addWidget(self.image_label) image_group = QGroupBox() image_group.setStyleSheet("margin:0; padding: 0; border: 0;") image_group.setContentsMargins(0, 0, 0, 0) image_group.setLayout(image_layout) splitter = QSplitter() splitter.addWidget(image_group) splitter.addWidget(self.tabs_widget) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(splitter) self.tools.pen_selected.connect(self.pen_select) self.tools.erase_btn.clicked.connect(self.erase_btn_click) self.tools.slider.valueChanged.connect(self.slider_changed) self.tools.processing_btn.clicked.connect(self.send_nn_segmentation) self.tools.load_mask_btn.clicked.connect(self.load_nifti_mask_click) self.tools.save_mask_btn.clicked.connect(self.save_nifti_mask_click) self.tools.nj_segment_btn.clicked.connect(self.nj_segment_click) self.nj_points_ready.connect(self.nj_segment)
class ToolBox(QVBoxLayout): sig = QtCore.Signal(object) listThread = None groupBoxThreadInfo = None threadvbox = None mode = None def __init__(self, mode, parentQWidget=None): QVBoxLayout.__init__(self) self.sig.connect(self.addThreadList) self.mode = mode self.sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.groupBoxSearch = QGroupBox() self.groupBoxSearch.setStyleSheet( "QGroupBox {border: 1px solid gray; border-radius: 4px; };") vboxSearch = QVBoxLayout() self.searchTitle = QLabel("Search Messages") vboxSearch.addWidget(self.searchTitle) self.searchHLayout = QHBoxLayout() self.editTextSearch = QTextEdit('') self.editTextSearch.setFixedSize(200, 30) self.buttonSearch = QPushButton('Search') self.buttonSearch.setFixedSize(100, 30) self.buttonSearch.clicked.connect(self.searchMsg) vboxSearch.addWidget(self.editTextSearch) self.searchHLayout.addWidget(self.buttonSearch) self.searchCursor = QLabel() self.searchHLayout.addWidget(self.searchCursor) vboxSearch.addLayout(self.searchHLayout) self.browseHLayout = QHBoxLayout() self.buttonLookUp = QPushButton('\u21e7') #Arrow up self.buttonLookUp.setFixedWidth(100) self.buttonLookUp.clicked.connect(self.moveToPrev) self.buttonLookDown = QPushButton('\u21e9') #Arrow down self.buttonLookDown.setFixedWidth(100) self.buttonLookDown.clicked.connect(self.moveToNext) self.browseHLayout.addWidget(self.buttonLookUp) self.browseHLayout.addWidget(self.buttonLookDown) vboxSearch.addLayout(self.browseHLayout) self.groupBoxSearch.setLayout(vboxSearch) self.addWidget(self.groupBoxSearch) self.groupBoxSearch.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.buttonHiddenLifelines = QPushButton('Show hidden life-lines') self.buttonHiddenLifelines.setFixedWidth(200) self.buttonHiddenLifelines.clicked.connect(self.showHiddenLifelines) self.addWidget(self.buttonHiddenLifelines) self.buttonHiddenMessages = QPushButton('Show hidden Messages') self.buttonHiddenMessages.setFixedWidth(200) self.buttonHiddenMessages.clicked.connect(self.showHiddenMessages) self.addWidget(self.buttonHiddenMessages) if const.mode_interactive == mode: self.buttonCapture = QPushButton('Capture') self.buttonCapture.setFixedWidth(200) self.buttonCapture.clicked.connect(self.notifyCapture) self.addWidget(self.buttonCapture) self.msgRcv = [] self.msgInfo = QLabel("Message Info.") self.groupBoxMessageInfo = QGroupBox() self.groupBoxMessageInfo.setStyleSheet( "QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;" ) vbox = QVBoxLayout() vbox.addWidget(self.msgInfo) self.tableTime = QTableWidget(3, 2) self.tableTime.setHorizontalHeaderLabels(['-', 'time']) self.tableTime.setColumnWidth(0, 80) self.tableTime.setColumnWidth(1, 150) vwidth = self.tableTime.verticalHeader().length() hwidth = self.tableTime.horizontalHeader().height() fwidth = self.tableTime.frameWidth() * 2 self.tableTime.setFixedHeight(vwidth + hwidth + fwidth) self.tableTime.horizontalHeader().setStretchLastSection(True) self.tableTime.setItem(0, 0, QTableWidgetItem('begin')) self.tableTime.setItem(0, 1, QTableWidgetItem(' - ')) self.tableTime.setItem(1, 0, QTableWidgetItem('end')) self.tableTime.setItem(1, 1, QTableWidgetItem(' - ')) self.tableTime.setItem(2, 0, QTableWidgetItem('duration')) self.tableTime.setItem(2, 1, QTableWidgetItem(' - ')) vbox.addWidget(self.tableTime) self.titleArg = QLabel('Argument List') vbox.addWidget(self.titleArg) max_arg_num = 10 self.tableArgs = QTableWidget(max_arg_num, 2) self.tableArgs.setHorizontalHeaderLabels(['type', 'value']) for idx in range(0, max_arg_num): self.tableArgs.setItem(idx, 0, QTableWidgetItem()) self.tableArgs.setItem(idx, 1, QTableWidgetItem()) self.tableArgs.horizontalHeader().setStretchLastSection(True) vbox.addWidget(self.tableArgs) self.titleArg = QLabel('Return Value List') vbox.addWidget(self.titleArg) max_ret_num = 4 self.tableRet = QTableWidget(max_ret_num, 2) self.tableRet.setHorizontalHeaderLabels(['type', 'value']) for idx in range(0, max_ret_num): self.tableRet.setItem(idx, 0, QTableWidgetItem()) self.tableRet.setItem(idx, 1, QTableWidgetItem()) self.tableRet.horizontalHeader().setStretchLastSection(True) vwidth = self.tableRet.verticalHeader().length() hwidth = self.tableRet.horizontalHeader().height() fwidth = self.tableRet.frameWidth() * 2 self.tableRet.setFixedHeight(vwidth + hwidth + fwidth) vbox.addWidget(self.tableRet) self.buttonSrcView = QPushButton('view code') self.buttonSrcView.setFixedWidth(200) self.buttonSrcView.clicked.connect(self.openSourceViewer) self.buttonHide = QPushButton('Hide') self.buttonHide.setFixedWidth(200) self.buttonHide.clicked.connect(self.notifyHide) self.buttonHideAllMsg = QPushButton('Hide All') self.buttonHideAllMsg.setFixedWidth(200) self.buttonHideAllMsg.clicked.connect(self.hideAllMsgNamedAsSelected) self.groupBoxMessageInfo.setLayout(vbox) self.checkHideCircular = QCheckBox('Hide Circular Messages') self.checkHideCircular.setCheckState(QtCore.Qt.Unchecked) self.checkHideCircular.stateChanged.connect( self.changeHideCircularMessage) self.addWidget(self.checkHideCircular) self.addWidget(self.groupBoxMessageInfo) self.groupBoxMessageInfo.setSizePolicy(self.sizePolicy) def reset(self): for idx in reversed(range(0, self.listThread.count())): self.listThread.takeItem(idx) def setMsgInfoMessage(self, msg): self.strMessage = msg def changeHideCircularMessage(self, state): if state == QtCore.Qt.Unchecked: self.diagramView.hideCircularChanged(False) elif state == QtCore.Qt.Checked: self.diagramView.hideCircularChanged(True) def setMsgInfoModule(self, module): self.strModule = module def updateSearchStatus(self, curr, number): self.searchCursor.setText("%d/%d" % (curr, number)) def connectSourceViewer(self, viewer): self.srcViewer = viewer def openSourceViewer(self): self.srcViewer.openViewer(self.strModule, self.strMessage) def setMessageInfoTime(self, begin, end, duration): self.tableTime.item(0, 1).setText(begin) self.tableTime.item(1, 1).setText(end) self.tableTime.item(2, 1).setText(duration + ' msec') def setMessageInfoArg(self, listParam, listArg): # Clear the contents in the table max_arg_num = 10 for idx in range(0, max_arg_num): self.tableArgs.item(idx, 0).setText('') self.tableArgs.item(idx, 1).setText('') if listArg: for idx, text in enumerate(listArg): self.tableArgs.item(idx, 1).setText(text) for idx, text in enumerate(listParam): self.tableArgs.item(idx, 0).setText(text) else: for idx in range(0, self.tableArgs.rowCount()): self.tableArgs.item(idx, 1).setText('') self.tableArgs.item(idx, 0).setText('') def setMessageInfoRet(self, listRet): if listRet: for idx, text in enumerate(listRet): self.tableRet.item(idx, 1).setText(text) else: for idx in range(0, self.tableRet.rowCount()): self.tableRet.item(idx, 1).setText('') self.tableRet.item(idx, 0).setText('') def notifyInteractiveStateChanged(self, state): if const.mode_interactive != self.mode: return if const.STATE_INTERACTIVE_CAPTURING == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Stop Capture') if const.STATE_INTERACTIVE_PROCESSING == state: self.buttonCapture.setEnabled(False) if const.STATE_INTERACTIVE_IDLE == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') if const.STATE_INTERACTIVE_RESET == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') elif const.STATE_INTERACTIVE_ACTIVE == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') def setMessageInfo(self, info): self.msgInfo.setText(info) def setAvailable(self, threads): self.sig.emit(threads) def toggleThreadDisplay(self, item): print(self.listThread.currentRow()) #if item.isSelected(): # print(item.text() + " is selected") #else: # print(item.text() + " is not selected") self.diagramView.showThread(self.listThread.currentRow(), item.isSelected()) def hideAllMsgNamedAsSelected(self): self.diagramView.hideAllMessageSelected() def addThreadList(self, threads): if not self.groupBoxThreadInfo: self.groupBoxThreadInfo = QGroupBox() self.threadInfo = QLabel("Thread Info.") self.groupBoxThreadInfo.setStyleSheet( "QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;" ) if not self.threadvbox: self.threadvbox = QVBoxLayout() if not self.listThread: self.listThread = QListWidget() self.listThread.setFixedWidth(200) self.listThread.setSelectionMode(QAbstractItemView.MultiSelection) QtCore.QObject.connect(self.listThread, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.toggleThreadDisplay) self.threadvbox.addWidget(self.threadInfo) self.threadvbox.addWidget(self.listThread) self.groupBoxThreadInfo.setLayout(self.threadvbox) self.addWidget(self.groupBoxThreadInfo) self.groupBoxThreadInfo.setSizePolicy(self.sizePolicy) for id in threads: item = QListWidgetItem(id) self.listThread.addItem(item) def connectController(self, controller): self.controller = controller self.connect(controller, QtCore.SIGNAL('setAvailable()'), self.setAvailable) def connectDiagramView(self, view): self.diagramView = view def disconnectMsgRcv(self, receiver): print("Implement this method !!! disconnectMsgRcv") def connectMsgRcv(self, receiver): self.msgRcv.append(receiver) def notifyHide(self): for rcv in self.msgRcv: rcv.activateHide(True) def showHiddenLifelines(self): response, selected_items = HiddenDialog.HiddenDialog.getSelectedItems( self.diagramView.getHiddenLifeLines()) if response: self.diagramView.showLifelines(selected_items) def showHiddenMessages(self): response, selected_items = HiddenMessageDialog.HiddenMessageDialog.getSelectedItems( self.diagramView.getHiddenMessages(), self.diagramView.getHiddenLifeLines()) if response: if selected_items[3] in self.diagramView.getHiddenLifeLines(): confirmation = ShowLifeLineDialog.ShowLifeLineDialog.confirmToShowLifeLine( selected_items[3]) if confirmation: self.diagramView.showLifelines([selected_items[3]]) self.diagramView.showMessages(selected_items) else: self.diagramView.showMessages(selected_items) def notifyCapture(self): for rcv in self.msgRcv: rcv.activateCapture(True) def moveToPrev(self): for rcv in self.msgRcv: rcv.moveToPrev() def moveToNext(self): for rcv in self.msgRcv: rcv.moveToNext() def searchMsg(self): str = self.editTextSearch.toPlainText() for rcv in self.msgRcv: rcv.searchMessage(str)
class MyDockWidget(cutter.CutterDockWidget): def __init__(self, parent, action): super(MyDockWidget, self).__init__(parent, action) self.setObjectName("Capa explorer") self.setWindowTitle("Capa explorer") self._config = CutterBindings.Configuration.instance() self.model_data = CapaExplorerDataModel() self.range_model_proxy = CapaExplorerRangeProxyModel() self.range_model_proxy.setSourceModel(self.model_data) self.search_model_proxy = CapaExplorerSearchProxyModel() self.search_model_proxy.setSourceModel(self.range_model_proxy) self.create_view_tabs() self.create_menu() self.create_tree_tab_ui() self.create_view_attack() self.connect_signals() self.setWidget(self.tabs) self.show() def create_view_tabs(self): # Create tabs container self.tabs = QTabWidget() # Create the tabs self.tab_attack = QWidget(self.tabs) self.tab_tree_w_model = QWidget(self.tabs) self.tabs.addTab(self.tab_tree_w_model, "Tree View") self.tabs.addTab(self.tab_attack, "MITRE") def create_menu(self): # Define menu actions # Text, tooltip, function, enabled before file load self.disabled_menu_items = [] menu_actions = [ ("Load JSON file", '', self.cma_load_file, True), (), ("Auto rename functions", 'Auto renames functions according to capa detections, can result in very long function names.', self.cma_analyze_and_rename, False), ("Create flags", 'Creates flagspaces and flags from capa detections.', self.cma_create_flags, False), (), ("About", '', self.cma_display_about, True), ] self.capa_menu = QMenu() self.capa_menu.setToolTipsVisible(True) # Create qactions for action in menu_actions: if not len(action): # Create separator on empty self.capa_menu.addSeparator() continue a = QAction(self) a.setText(action[0]) a.setToolTip(action[1]) a.triggered.connect(action[2]) a.setEnabled(action[3]) if not action[3]: self.disabled_menu_items.append(a) self.capa_menu.addAction(a) # Create menu button font = QFont() font.setBold(True) self.btn_menu = QToolButton() self.btn_menu.setText('...') self.btn_menu.setFont(font) self.btn_menu.setPopupMode(QToolButton.InstantPopup) self.btn_menu.setMenu(self.capa_menu) self.btn_menu.setStyleSheet( 'QToolButton::menu-indicator { image: none; }') self.tabs.setCornerWidget(self.btn_menu, corner=Qt.TopRightCorner) def create_tree_tab_ui(self): self.capa_tree_view_layout = QVBoxLayout() self.capa_tree_view_layout.setAlignment(Qt.AlignTop) self.chk_fcn_scope = QCheckBox("Limit to Current function") #TODO: reset state on load file self.chk_fcn_scope.setChecked(False) self.chk_fcn_scope.stateChanged.connect( self.slot_checkbox_limit_by_changed) self.input_search = QLineEdit() self.input_search.setStyleSheet("margin:0px; padding:0px;") self.input_search.setPlaceholderText("search...") self.input_search.textChanged.connect( self.slot_limit_results_to_search) self.filter_controls_container = QGroupBox() self.filter_controls_container.setObjectName("scope") self.filter_controls_container.setFlat(True) self.filter_controls_container.setStyleSheet( "#scope{border:0px; padding:0px; margin:0px;subcontrol-origin: padding; subcontrol-position: left top;}" ) self.filter_controls_layout = QHBoxLayout( self.filter_controls_container) self.filter_controls_layout.setContentsMargins(0, 0, 0, 0) self.filter_controls_layout.addWidget(self.input_search) self.filter_controls_layout.addWidget(self.chk_fcn_scope) self.view_tree = CapaExplorerQtreeView(self.search_model_proxy) self.view_tree.setModel(self.search_model_proxy) # Make it look a little nicer when no results are loaded self.view_tree.header().setStretchLastSection(True) self.capa_tree_view_layout.addWidget(self.filter_controls_container) self.capa_tree_view_layout.addWidget(self.view_tree) self.tab_tree_w_model.setLayout(self.capa_tree_view_layout) def create_view_attack(self): table_headers = [ "ATT&CK Tactic", "ATT&CK Technique ", ] table = QTableWidget() table.setColumnCount(len(table_headers)) table.verticalHeader().setVisible(False) table.setSortingEnabled(False) table.setEditTriggers(QAbstractItemView.NoEditTriggers) table.setFocusPolicy(Qt.NoFocus) table.setSelectionMode(QAbstractItemView.NoSelection) table.setHorizontalHeaderLabels(table_headers) table.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) table.horizontalHeader().setStretchLastSection(True) table.setShowGrid(False) table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) #table.setStyleSheet("QTableWidget::item { padding: 25px; }") attack_view_layout = QVBoxLayout() attack_view_layout.setAlignment(Qt.AlignTop) self.attack_table = table attack_view_layout.addWidget(self.attack_table) self.tab_attack.setLayout(attack_view_layout) return table def connect_signals(self): QObject.connect(cutter.core(), SIGNAL("functionRenamed(RVA, QString)"), self.model_data.refresh_function_names) QObject.connect(cutter.core(), SIGNAL("functionsChanged()"), self.model_data.refresh_function_names) QObject.connect(cutter.core(), SIGNAL("seekChanged(RVA)"), self.signal_shim_slot_checkbox_limit_by_changed) def render_new_table_header_item(self, text): """create new table header item with our style @param text: header text to display """ item = QTableWidgetItem(text) item.setForeground(self._config.getColor("graph.true")) font = QFont() font.setBold(True) item.setFont(font) return item def fill_attack_table(self, rules): tactics = collections.defaultdict(set) for key, rule in rules.items(): if not rule["meta"].get("att&ck"): continue for attack in rule["meta"]["att&ck"]: tactic, _, rest = attack.partition("::") if "::" in rest: technique, _, rest = rest.partition("::") subtechnique, _, id = rest.rpartition(" ") tactics[tactic].add((technique, subtechnique, id)) else: technique, _, id = rest.rpartition(" ") tactics[tactic].add((technique, id)) column_one = [] column_two = [] for (tactic, techniques) in sorted(tactics.items()): column_one.append(tactic.upper()) # add extra space when more than one technique column_one.extend(["" for i in range(len(techniques) - 1)]) for spec in sorted(techniques): if len(spec) == 2: technique, id = spec column_two.append("%s %s" % (technique, id)) elif len(spec) == 3: technique, subtechnique, id = spec column_two.append("%s::%s %s" % (technique, subtechnique, id)) else: raise RuntimeError("unexpected ATT&CK spec format") self.attack_table.setRowCount(max(len(column_one), len(column_two))) for (row, value) in enumerate(column_one): self.attack_table.setItem(row, 0, self.render_new_table_header_item(value)) for (row, value) in enumerate(column_two): self.attack_table.setItem(row, 1, QTableWidgetItem(value)) def enable_menu_items_after_load(self): # enables menu actions after file is loaded for action in self.disabled_menu_items: action.setEnabled(True) def slot_limit_results_to_search(self, text): """limit tree view results to search matches reset view after filter to maintain level 1 expansion """ self.search_model_proxy.set_query(text) self.view_tree.reset_ui(should_sort=False) def signal_shim_slot_checkbox_limit_by_changed(self): if self.chk_fcn_scope.isChecked(): self.slot_checkbox_limit_by_changed(Qt.Checked) def slot_checkbox_limit_by_changed(self, state): """slot activated if checkbox clicked if checked, configure function filter if screen location is located in function, otherwise clear filter @param state: checked state """ invoke_reset = True if state == Qt.Checked: minbound, maxbound = util.get_function_boundries_at_current_location( ) if self.range_model_proxy.min_ea == minbound and self.range_model_proxy.max_ea == maxbound: # Seek only changed within current function, avoid resetting tree invoke_reset = False self.limit_results_to_function((minbound, maxbound)) else: self.range_model_proxy.reset_address_range_filter() if invoke_reset: self.view_tree.reset_ui() def limit_results_to_function(self, f): """add filter to limit results to current function adds new address range filter to include function bounds, allowing basic blocks matched within a function to be included in the results @param f: (tuple (maxbound, minbound)) """ if f: self.range_model_proxy.add_address_range_filter(f[0], f[1]) else: # if function not exists don't display any results (assume address never -1) self.range_model_proxy.add_address_range_filter(-1, -1) # --- Menu Actions def cma_analyze_and_rename(self): message_box = QMessageBox() message_box.setStyleSheet("QLabel{min-width: 370px;}") message_box.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok) message_box.setEscapeButton(QMessageBox.Cancel) message_box.setDefaultButton(QMessageBox.Ok) message_box.setWindowTitle('Warning') message_box.setText( 'Depending on the size of the binary and the' ' amount of \n' 'capa matches this feature can take some time to \n' 'complete and might make the UI freeze temporarily.') message_box.setInformativeText('Are you sure you want to proceed ?') ret = message_box.exec_() # Ok = 1024 if ret == 1024: self.model_data.auto_rename_functions() def cma_create_flags(self): self.model_data.create_flags() def cma_display_about(self): c = CAPAExplorerPlugin() info_text = ("{description}\n\n" "https://github.com/ninewayhandshake/capa-explorer\n\n" "Version: {version}\n" "Author: {author}\n" "License: Apache License 2.0\n").format( version=c.version, author=c.author, description=c.description, ) text = CAPAExplorerPlugin().name message_box = QMessageBox() message_box.setStyleSheet("QLabel{min-width: 370px;}") message_box.setWindowTitle('About') message_box.setText(text) message_box.setInformativeText(info_text) message_box.setStandardButtons(QMessageBox.Close) for i in message_box.findChildren(QLabel): i.setFocusPolicy(Qt.NoFocus) message_box.exec_() def cma_load_file(self): filename = QFileDialog.getOpenFileName() path = filename[0] if len(path): try: data = util.load_capa_json(path) self.fill_attack_table(data['rules']) self.model_data.clear() self.model_data.render_capa_doc(data) # Restore ability to scroll on last column self.view_tree.header().setStretchLastSection(False) self.view_tree.slot_resize_columns_to_content() self.enable_menu_items_after_load() except Exception as e: util.log('Could not load json file.') else: util.log('No file selected.')
class MainWindow(QDialog): signals = signal.signalClass() # message signal settings = None settings_batch = None Well_Map = None Well_Targets = None ## @brief MainWindow::__init__ initializes the window with widgets, layouts and groupboxes and opens initialization files. def __init__(self): super().__init__() ## Create QSettings variables in order to be able to access the initialisation parameters self.openBatchIniFile() self.openSettingsIniFile() ## Load wells to process in batch from batch settings initialisation file and calculate the coordinates self.wellInitialisation() self.Well_Scanner = Scanner() ## Overall gridlayout self.mainWindowLayout = QGridLayout() ## @param mgb is a groupbox with manual control widgets mgb = self.createManualGroupBox() ## @param is a groupbox with batch process control widgets bgb = self.createBatchGroupBox() ## @param is a groupbox with log window lgb = self.createLogWindow() ## @param is a groupbox with video stream window vgb = self.Well_Scanner.createVideoWindow() #self.createVideoWindow() ## Fill mainWindowLayout with the just created groupboxes in the mainWindowLayout gridlayout self.mainWindowLayout.addWidget(bgb, 0, 0) self.mainWindowLayout.addWidget(mgb, 1, 0) self.mainWindowLayout.addWidget(vgb, 0, 1) self.mainWindowLayout.addWidget(lgb, 1, 1) self.setWindowTitle("WELL READER") #self.mainWindowLayout.setStyleSheet('background-color: #a9a9a9') self.backgroundPalette = QPalette() self.backgroundColor = QColor(50, 50, 50) self.backgroundPalette.setColor(QPalette.Background, self.backgroundColor) self.setPalette(self.backgroundPalette) self.setLayout(self.mainWindowLayout) self.resize(self.width(), self.height()) ## @brief Mainwindow(QDialog)::msg(self, message) emits the message signal. This emit will be catched by the logging slot function in main.py. ## @param message is the string message to be emitted. def msg(self, message): if message is not None: self.signals.mes.emit(self.__class__.__name__ + ": " + str(message)) return ## @brief MainWindow::LogWindowInsert(self, message) appends the message to the log window. This is a slot function called when a mesnal message is emitted from any class which uses the message signal. This Slot is connected which each class which uses this signal. # @param message is the message to be displayed. @Slot(str) def LogWindowInsert(self, message): self.log.appendPlainText(str(message) + "\n") return ## @brief MainWindow::wait_ms(self, milliseconds) is a delay function. ## @param milliseconds is the number of milliseconds to wait. def wait_ms(self, milliseconds): GeneralEventLoop = QEventLoop() QTimer.singleShot(milliseconds, GeneralEventLoop.exit) GeneralEventLoop.exec_() return ## @brief MainWindow::createBatchGroupBox(self) creates the groupbox and the widgets in it which are used for the batch control. # @return self.batchGroupBox. This is the groupbox containing the Batch process widgets. def createBatchGroupBox(self): self.processControlGridLayout = QGridLayout() self.batchGroupBox = QGroupBox() self.batchGroupBox.setStyleSheet("color: #000000;") ## label of QGroupbox content self.gb_label = QLabel("Batch control") self.gb_label.setStyleSheet( 'QLabel {color: #ffffff; font-weight: bold}') self.gb_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.gb_label, 0, 0, 1, 3, Qt.AlignHCenter) ## Button FIRMWARE_RESTART self.b_firmware_restart = QPushButton("FIRMWARE_RESTART") self.b_firmware_restart.setStyleSheet( 'QPushButton {background-color: #AAAAAA; border: none}') self.b_firmware_restart.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_firmware_restart, 1, 0, 1, 1) ## Button Read STM buffer self.b_stm_read = QPushButton("STM READ") self.b_stm_read.setStyleSheet( 'QPushButton {background-color: #AAAAAA; border: none}') self.b_stm_read.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_stm_read, 1, 1, 1, 1) ## Button START BATCH self.b_start_batch = QPushButton("START BATCH") self.b_start_batch.setStyleSheet( 'QPushButton {background-color: #AAAAAA; border: none}') self.b_start_batch.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_start_batch, 2, 0, 1, 2) ## Button STOP BATCH self.b_stop_batch = QPushButton("STOP BATCH") self.b_stop_batch.setStyleSheet( 'QPushButton {background-color: #AAAAAA; border: none}') self.b_stop_batch.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_stop_batch, 3, 0, 1, 2) ## Button Snapshot. self.b_snapshot = QPushButton("Snapshot") self.b_snapshot.setStyleSheet( 'QPushButton {background-color: #AAAAAA; border: none}') self.b_snapshot.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_snapshot, 4, 0, 1, 2) ## Button Doxygen. Creates and opens Doxygen documentation self.b_doxygen = QPushButton("Doxygen") self.b_doxygen.setStyleSheet( 'QPushButton {background-color: #ffa500; border: none}') self.b_doxygen.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.processControlGridLayout.addWidget(self.b_doxygen, 5, 0, 1, 2) self.batchGroupBox.setLayout(self.processControlGridLayout) return self.batchGroupBox ## @brief MainWindow::createManualGroupBox(self) creates the groupbox and the widgets in it which are used for the manual motor control. # @return self.manualGroupBox. This is the groupbox containing the manual control process widgets. def createManualGroupBox(self): self.manualControlGridLayout = QGridLayout() self.manualGroupBox = QGroupBox() self.manualGroupBox.setStyleSheet("color: #000000;") ## label of QGroupbox content self.gb_label = QLabel("Manual XY-control") self.gb_label.setStyleSheet( 'QLabel {color: #ffffff; font-weight: bold}') self.gb_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.gb_label, 0, 0, 1, 4, Qt.AlignHCenter) ## Button HOME X self.b_home_x = QPushButton("HOME X0 Y0") self.b_home_x.setStyleSheet( 'QPushButton {background-color: #55afff; border: none}') self.b_home_x.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_home_x, 1, 0, 1, 4) ## Button GET_POSITION self.b_get_pos = QPushButton("GET_POSITION") self.b_get_pos.setStyleSheet( 'QPushButton {background-color: #55afff; border: none}') self.b_get_pos.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_get_pos, 2, 0, 1, 4) ## Row selection label self.x_label = QLabel("X") self.x_label.setStyleSheet('QLabel {color: #ffffff}') self.x_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.x_label, 3, 0, 1, 1) ## X position input field self.x_pos = QLineEdit() self.x_pos.setStyleSheet( 'QLineEdit {background-color: #AAAAAA; color: #000000; border: none}' ) self.x_pos.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.x_pos.setText('0.00') self.x_pos.setFont(QFont("Arial", 20)) self.manualControlGridLayout.addWidget(self.x_pos, 4, 0) ## Row selection label self.y_label = QLabel("Y") self.y_label.setStyleSheet('QLabel {color: #ffffff}') self.y_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.y_label, 3, 1, 1, 1) ## Y position input field self.y_pos = QLineEdit() self.y_pos.setStyleSheet( 'QLineEdit {background-color: #AAAAAA; color: #000000; border: none}' ) self.y_pos.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.y_pos.setText('0.00') self.y_pos.setFont(QFont("Arial", 20)) self.manualControlGridLayout.addWidget(self.y_pos, 4, 1) ## Button goto XY self.b_gotoXY = QPushButton("Goto XY") self.b_gotoXY.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_gotoXY.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_gotoXY, 5, 0, 1, 2) ## Row selection label self.row_label = QLabel("Row") self.row_label.setStyleSheet('QLabel {color: #ffffff}') self.row_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.row_label, 3, 2, 1, 1) ## Row well combobox self.row_well_combo_box = QComboBox(self) self.row_well_combo_box.setStyleSheet( 'QComboBox {background-color: #AAAAAA; border: none}') self.row_well_combo_box.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.row_well_combo_box, 4, 2, 1, 1) self.row_well_combo_box.addItem(str(0) + " position") for row in range(0, self.Well_Map.shape[0] - 1, 1): self.row_well_combo_box.addItem(chr(ord('A') + row)) ## Column selection label self.column_label = QLabel("Column") self.column_label.setStyleSheet('QLabel {color: #ffffff}') self.column_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.column_label, 3, 3, 1, 1) ## Column well combobox self.column_well_combo_box = QComboBox(self) self.column_well_combo_box.setStyleSheet( 'QComboBox {background-color: #AAAAAA; border: none}') self.column_well_combo_box.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.column_well_combo_box, 4, 3, 1, 1) self.column_well_combo_box.addItem(str(0) + " position") for column in range(1, self.Well_Map.shape[1], 1): self.column_well_combo_box.addItem(str(column)) ## Button Goto well self.b_goto_well = QPushButton("Goto well") self.b_goto_well.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_goto_well.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_goto_well, 5, 2, 1, 2) ## Button TURN UP self.b_turn_up = QPushButton("^") self.b_turn_up.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_turn_up.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_turn_up, 6, 0, 1, 4) ## Button TURN LEFT self.b_turn_left = QPushButton("<") self.b_turn_left.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_turn_left.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_turn_left, 7, 0, 1, 2) ## Button TURN RIGHT self.b_turn_right = QPushButton(">") self.b_turn_right.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_turn_right.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_turn_right, 7, 2, 1, 2) ## Button TURN DOWN self.b_turn_down = QPushButton("v") self.b_turn_down.setStyleSheet( 'QPushButton {background-color: #00cc33; border: none}') self.b_turn_down.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.manualControlGridLayout.addWidget(self.b_turn_down, 8, 0, 1, 4) ## Button Emergency break self.b_emergency_break = QPushButton("Emergency break") self.b_emergency_break.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.b_emergency_break.setStyleSheet( 'QPushButton {background-color: #cc0000; border: none}') self.manualControlGridLayout.addWidget(self.b_emergency_break, 9, 0, 1, 4) self.manualGroupBox.setLayout(self.manualControlGridLayout) return self.manualGroupBox ## @brief MainWindow::createLogWindow(self) creates the groupbox and the log widget in it which is used for displaying debug messages. # @return self.logGroupBox. This is the groupbox containing the Log window widgets. def createLogWindow(self): self.logGridLayout = QGridLayout() self.logGroupBox = QGroupBox() self.logGroupBox.setStyleSheet("color: #000000;") ## label of QGroupbox content self.gb_label = QLabel("Debug information") self.gb_label.setStyleSheet( 'QLabel {color: #ffffff; font-weight: bold}') self.gb_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.logGridLayout.addWidget(self.gb_label, 0, 0, 1, 1, Qt.AlignHCenter) ## Logger screen widget (QPlainTextEdit) self.log = QPlainTextEdit() self.log.setReadOnly(True) self.log.setStyleSheet("background-color: #AAAAAA;") self.logGridLayout.addWidget(self.log, 1, 0, 1, 1) self.logGroupBox.setLayout(self.logGridLayout) return self.logGroupBox ## @brief MainWindow::setBatchWindow disables buttons which should not be used during the batch process. This function is called when the batch process is started. @Slot() def setBatchWindow(self): self.b_snapshot.setVisible(False) self.b_home_x.setVisible(False) self.b_get_pos.setVisible(False) self.x_label.setVisible(False) self.x_pos.setVisible(False) self.y_label.setVisible(False) self.y_pos.setVisible(False) self.b_gotoXY.setVisible(False) self.row_label.setVisible(False) self.row_well_combo_box.setVisible(False) self.column_label.setVisible(False) self.column_well_combo_box.setVisible(False) self.b_goto_well.setVisible(False) self.b_turn_up.setVisible(False) self.b_turn_right.setVisible(False) self.b_turn_left.setVisible(False) self.b_turn_down.setVisible(False) return ## @brief MainWindow::setBatchWindow enables all buttons. This function is called when the batch process is stopped. @Slot() def setFullWindow(self): self.b_snapshot.setVisible(True) self.b_home_x.setVisible(True) self.b_get_pos.setVisible(True) self.x_label.setVisible(True) self.x_pos.setVisible(True) self.y_label.setVisible(True) self.y_pos.setVisible(True) self.b_gotoXY.setVisible(True) self.row_label.setVisible(True) self.row_well_combo_box.setVisible(True) self.column_label.setVisible(True) self.column_well_combo_box.setVisible(True) self.b_goto_well.setVisible(True) self.b_turn_up.setVisible(True) self.b_turn_right.setVisible(True) self.b_turn_left.setVisible(True) self.b_turn_down.setVisible(True) return ## @brief MainWindow::wellInitialisation(self) declares and defines the wellpositions in millimeters of the specified targets using the batch initialisation file. ## @author Robin Meekers ## @author Gert van lagen (ported to new well reader prototype software) def wellInitialisation(self): ## Declare well map self.Well_Map = np.empty( (int(self.settings_batch.value("Plate/rows")) + 1, int(self.settings_batch.value("Plate/columns")) + 1, 2), dtype=object) ## Position 00 on the wellplate derived from the calibration data self.Well_Map[0:][0:] = ((float( self.settings_batch.value("Plate/posColumn00"))), (float( self.settings_batch.value("Plate/posRow00")))) self.msg("Initialising well plate with " + str(self.Well_Map.shape[0]) + " rows and " + str(self.Well_Map.shape[1]) + " columns.") ## Fill Well_Map with well positions in mm based on the distances of batch.ini for row in range(1, self.Well_Map.shape[0], 1): for column in range(1, self.Well_Map.shape[1], 1): self.Well_Map[row][column] = ( (float(self.settings_batch.value("Plate/posColumn00")) + float(self.settings_batch.value("Plate/p1")) + ((column - 1) * float(self.settings_batch.value("Plate/p2")))), (float(self.settings_batch.value("Plate/posRow00")) + float(self.settings_batch.value("Plate/p3")) + ((row - 1) * float(self.settings_batch.value("Plate/p4"))))) ## load the wells to process size = self.settings_batch.beginReadArray("Wells") Well_KeyList = [] for i in range(0, size): self.settings_batch.setArrayIndex(i) Well_KeyList.append(self.settings_batch.childKeys()[0]) ## val = self.settings_batch.value(key) self.settings_batch.endArray() ## Well_KeyList = self.settings_batch.childKeys() print("Found (" + str(len(Well_KeyList)) + "): " + str(Well_KeyList)) self.Well_Targets = np.empty((len(Well_KeyList), 1), dtype=[('X', 'i2'), ('Y', 'i2'), ('POS', 'U3'), ('Description', 'U100')]) index = 0 for Well_Key in Well_KeyList: Key_Characters = list(Well_Key) X_POS = (int(Key_Characters[1]) * 10) + (int(Key_Characters[2])) Y_POS = ord(Key_Characters[0].lower()) - 96 self.Well_Targets[index] = ( X_POS, Y_POS, str(Well_Key), str(self.settings_batch.value("Wells/" + Well_Key))) index = index + 1 print("Well targets: ") print(self.Well_Targets) print("Well_Map: ") print(self.Well_Map) return ## @brief getSec(self, time_str) converts a current_milli_time() string into seconds ## @param time_str is the time string to be converted ## @return time in seconds def getSec(self, time_str): h, m, s = time_str.split(':') return int(h) * 3600 + int(m) * 60 + int(s) ## @brief MainWindow::openSettingsIniFile(self) opens the initialisation file with the technical settings of the device. def openSettingsIniFile(self): print("\nDEBUG: in function MainWindow::openSettingsIniFile()") self.settings = QSettings( os.path.dirname(os.path.realpath(__file__)) + "/system_config/settings.ini", QSettings.IniFormat) self.msg("Opened settingsfile: " + os.path.dirname(os.path.realpath(__file__)) + "/system_config/settings.ini\n") return ## @brief MainWindow::openBatchIniFile(self) opens the initialisation file with the batch process settings of the device and wells. def openBatchIniFile(self): print("\nDEBUG: in function MainWindow::openBatchIniFile()") self.settings_batch = QSettings( os.path.dirname(os.path.realpath(__file__)) + "/system_config/batch.ini", QSettings.IniFormat) self.msg("Opened batch file: " + os.path.dirname(os.path.realpath(__file__)) + "/system_config/batch.ini\n") return ## @brief mainWindow::doxygen(self) generates Doxygen documentation and opens a chromium-browser with the ./Documentation/html/index.html documentation website. def doxygen(self): os.system( "cd Documentation && if [ -d " "html" " ]; then rm -r html; fi && cd ../ && doxygen Documentation/Doxyfile && chromium-browser ./Documentation/html/index.html" ) self.msg("Generated Doxygen documentation") return def closeEvent(self, event): self.signals.windowClosing.emit() event.accept() return
class NavFrame(QFrame): def __init__(self, parent=None): QFrame.__init__(self, parent) self.setStyleSheet("""QFrame{ background-color:#43454f;}""") self.setFrameShape(QFrame.StyledPanel) self.setFrameShadow(QFrame.Raised) self.frame_nav = QFrame(self) self.frame_nav.setMinimumSize(QSize(220, 300)) self.frame_nav.setStyleSheet("""QFrame{ background-color:#43454f;}""") self.frame_nav.setFrameShape(QFrame.StyledPanel) self.frame_nav.setFrameShadow(QFrame.Raised) self.gridLayout = QGridLayout(self) self.gridLayout.setContentsMargins(11, -1, 11, -1) self.gridLayout.addWidget(self.frame_nav, 3, 0, 1, 4) # set program img and name self.label_img = QLabel(self) self.label_img.setFixedSize(QSize(60, 60)) self.label_img.setPixmap(QPixmap(os.path.join(path, 'img/icon.png'))) # self.label_img.setPixmap(QPixmap("../img/icon.png")) self.label_img.setScaledContents(True) self.gridLayout.addWidget(self.label_img, 2, 1, 1, 1) self.label_name = QLabel("WebCheck ", self) self.label_name.setStyleSheet(styles.label_icon_name) self.gridLayout.addWidget(self.label_name, 2, 2, 1, 1) self.spacer_name_l = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.spacer_name_r = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.spacer_name_t = QSpacerItem(20, 70, QSizePolicy.Minimum, QSizePolicy.Maximum) self.gridLayout.addItem(self.spacer_name_l, 2, 0, 1, 1) self.gridLayout.addItem(self.spacer_name_r, 2, 3, 1, 1) self.gridLayout.addItem(self.spacer_name_t, 1, 1, 1, 2) # set bottom layout for keeping gb in it self.gridLayout_b = QGridLayout(self.frame_nav) self.spacer_gb_l = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.spacer_gb_r = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.spacer_gb_t = QSpacerItem(0, 20, QSizePolicy.Minimum, QSizePolicy.Maximum) self.spacer_gb_b = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.gridLayout_b.addItem(self.spacer_gb_l, 1, 2, 1, 1) self.gridLayout_b.addItem(self.spacer_gb_r, 1, 0, 1, 1) self.gridLayout_b.addItem(self.spacer_gb_t, 0, 1, 1, 1) self.gridLayout_b.addItem(self.spacer_gb_b, 2, 1, 1, 1) # set gb and radio buttons self.groupBox = QGroupBox("", self.frame_nav) self.gridLayout_b.addWidget(self.groupBox, 1, 1, 1, 1) self.groupBox.setMinimumSize(QSize(220, 350)) self.groupBox.setStyleSheet("""QGroupBox{background-image: url(ui/img/radioline.png); border: none;}""") self.verticalLayout_gb = QVBoxLayout(self.groupBox) self.radioButton_add = QRadioButton(" Add", self.groupBox) self.radioButton_add.setStyleSheet(styles.btn_radio) self.verticalLayout_gb.addWidget(self.radioButton_add) self.radioButton_monitored = QRadioButton(" Monitored", self.groupBox) self.radioButton_monitored.setStyleSheet(styles.btn_radio) self.verticalLayout_gb.addWidget(self.radioButton_monitored) self.radioButton_options = QRadioButton(" Options", self.groupBox) self.radioButton_options.setStyleSheet(styles.btn_radio) self.verticalLayout_gb.addWidget(self.radioButton_options) self.radioButton_about = QRadioButton(" About", self.groupBox) self.radioButton_about.setStyleSheet(styles.btn_radio) self.verticalLayout_gb.addWidget(self.radioButton_about)
def __init__(self, targetImage=None, axeSize=500, layer=None, parent=None): super().__init__(layer=layer, targetImage=targetImage, parent=parent) self.setMinimumSize(axeSize, axeSize+100) # contrast spline viewer self.contrastForm = None # options optionList1, optionNames1 = ['Multi-Mode', 'CLAHE'], ['Multi-Mode', 'CLAHE'] self.listWidget1 = optionsWidget(options=optionList1, optionNames=optionNames1, exclusive=True, changed=lambda: self.dataChanged.emit()) self.listWidget1.checkOption(self.listWidget1.intNames[0]) self.listWidget1.setStyleSheet("QListWidget {border: 0px;} QListWidget::item {border: 0px; padding-left: 0px;}") optionList2, optionNames2 = ['High', 'manualCurve'], ['Preserve Highlights', 'Show Contrast Curve'] def optionList2Change(item): if item.internalName == 'High': # force to recalculate the spline self.layer.autoSpline = True self.dataChanged.emit() self.listWidget2 = optionsWidget(options=optionList2, optionNames=optionNames2, exclusive=False, changed=optionList2Change) self.listWidget2.checkOption(self.listWidget2.intNames[0]) self.listWidget2.setStyleSheet("QListWidget {border: 0px;} QListWidget::item {border: 0px; padding-left: 0px;}") self.options = UDict((self.listWidget1.options, self.listWidget2.options)) # contrast slider self.sliderContrast = QbLUeSlider(Qt.Horizontal) self.sliderContrast.setStyleSheet(QbLUeSlider.bLueSliderDefaultIBWStylesheet) self.sliderContrast.setRange(0, 10) self.sliderContrast.setSingleStep(1) contrastLabel = QbLUeLabel() contrastLabel.setMaximumSize(150, 30) contrastLabel.setText("Contrast Level") contrastLabel.doubleClicked.connect(lambda: self.sliderContrast.setValue(self.contrast2Slider(self.contrastDefault))) self.contrastValue = QLabel() font = self.contrastValue.font() metrics = QFontMetrics(font) w = metrics.width("100") h = metrics.height() self.contrastValue.setMinimumSize(w, h) self.contrastValue.setMaximumSize(w, h) self.contrastValue.setText(str("{:d}".format(self.sliderContrast.value()))) # contrast changed event handler. def contrastUpdate(value): self.contrastValue.setText(str("{:d}".format(self.sliderContrast.value()))) # move not yet terminated or value not modified if self.sliderContrast.isSliderDown() or self.slider2Contrast(value) == self.contrastCorrection: return self.sliderContrast.valueChanged.disconnect() self.sliderContrast.sliderReleased.disconnect() self.contrastCorrection = self.slider2Contrast(self.sliderContrast.value()) # force to recalculate the spline self.layer.autoSpline = True self.dataChanged.emit() self.sliderContrast.valueChanged.connect(contrastUpdate) self.sliderContrast.sliderReleased.connect(lambda: contrastUpdate(self.sliderContrast.value())) self.sliderContrast.valueChanged.connect(contrastUpdate) self.sliderContrast.sliderReleased.connect(lambda: contrastUpdate(self.sliderContrast.value())) # saturation slider self.sliderSaturation = QbLUeSlider(Qt.Horizontal) self.sliderSaturation.setStyleSheet(QbLUeSlider.bLueSliderDefaultColorStylesheet) self.sliderSaturation.setRange(0, 100) self.sliderSaturation.setSingleStep(1) saturationLabel = QbLUeLabel() saturationLabel.setMaximumSize(150, 30) saturationLabel.setText("Saturation") saturationLabel.doubleClicked.connect(lambda: self.sliderSaturation.setValue(self.saturation2Slider(self.saturationDefault))) self.saturationValue = QLabel() font = self.saturationValue.font() metrics = QFontMetrics(font) w = metrics.width("100") h = metrics.height() self.saturationValue.setMinimumSize(w, h) self.saturationValue.setMaximumSize(w, h) self.saturationValue.setText(str("{:+d}".format(self.sliderContrast.value()))) # saturation changed event handler def saturationUpdate(value): self.saturationValue.setText(str("{:+d}".format(int(self.slidersaturation2User(self.sliderSaturation.value()))))) # move not yet terminated or value not modified if self.sliderSaturation.isSliderDown() or self.slider2Saturation(value) == self.satCorrection: return self.sliderSaturation.valueChanged.disconnect() self.sliderSaturation.sliderReleased.disconnect() self.satCorrection = self.slider2Saturation(self.sliderSaturation.value()) self.dataChanged.emit() self.sliderSaturation.valueChanged.connect(saturationUpdate) self.sliderSaturation.sliderReleased.connect(lambda: saturationUpdate(self.sliderSaturation.value())) self.sliderSaturation.valueChanged.connect(saturationUpdate) self.sliderSaturation.sliderReleased.connect(lambda: saturationUpdate(self.sliderSaturation.value())) # brightness slider self.sliderBrightness = QbLUeSlider(Qt.Horizontal) self.sliderBrightness.setStyleSheet(QbLUeSlider.bLueSliderDefaultBWStylesheet) self.sliderBrightness.setRange(0, 100) self.sliderBrightness.setSingleStep(1) brightnessLabel = QbLUeLabel() brightnessLabel.setMaximumSize(150, 30) brightnessLabel.setText("Brightness") brightnessLabel.doubleClicked.connect(lambda: self.sliderBrightness.setValue(self.brightness2Slider(self.brightnessDefault))) self.brightnessValue = QLabel() font = self.brightnessValue.font() metrics = QFontMetrics(font) w = metrics.width("100") h = metrics.height() self.brightnessValue.setMinimumSize(w, h) self.brightnessValue.setMaximumSize(w, h) self.brightnessValue.setText(str("{:+d}".format(self.sliderContrast.value()))) # brightness changed event handler def brightnessUpdate(value): self.brightnessValue.setText(str("{:+d}".format(int(self.sliderBrightness2User(self.sliderBrightness.value()))))) # move not yet terminated or value not modified if self.sliderBrightness.isSliderDown() or self.slider2Brightness(value) == self.brightnessCorrection: return self.sliderBrightness.valueChanged.disconnect() self.sliderBrightness.sliderReleased.disconnect() self.brightnessCorrection = self.slider2Brightness(self.sliderBrightness.value()) self.dataChanged.emit() self.sliderBrightness.valueChanged.connect(brightnessUpdate) self.sliderBrightness.sliderReleased.connect(lambda: brightnessUpdate(self.sliderBrightness.value())) self.sliderBrightness.valueChanged.connect(brightnessUpdate) self.sliderBrightness.sliderReleased.connect(lambda: brightnessUpdate(self.sliderBrightness.value())) # attributes initialized in setDefaults, declared here # for the sake of correctness self.contrastCorrection = None # range self.satCorrection = None # range -0.5..0.5 self.brightnessCorrection = None # range -0.5..0.5 # layout l = QVBoxLayout() l.setAlignment(Qt.AlignTop) gb1 = QGroupBox() gb1.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 4px}") l1 = QVBoxLayout() ct = QLabel() ct.setText('Contrast') l.setAlignment(Qt.AlignTop) l1.addWidget(ct) l1.addWidget(self.listWidget1) gb1.setLayout(l1) l.addWidget(gb1) l.addWidget(self.listWidget2) l.addWidget(contrastLabel) hl = QHBoxLayout() hl.addWidget(self.contrastValue) hl.addWidget(self.sliderContrast) l.addLayout(hl) l.addWidget(brightnessLabel) hl3 = QHBoxLayout() hl3.addWidget(self.brightnessValue) hl3.addWidget(self.sliderBrightness) l.addLayout(hl3) l.addWidget(saturationLabel) hl2 = QHBoxLayout() hl2.addWidget(self.saturationValue) hl2.addWidget(self.sliderSaturation) l.addLayout(hl2) self.setLayout(l) self.adjustSize() self.setStyleSheet("QListWidget, QLabel {font : 7pt;}") self.setDefaults() self.setWhatsThis( """<b>Contrast Brightness Saturation</b><br> <b>Contrast</b> is enhanced using one of these two methods:<br> - <b>CLAHE</b> : increases the local contrast.<br> - <b>Multi-Mode</b> : increases the local contrast and the contrast between regions of the image.<br> For both methods the contrast slider controls the level of the correction.<br> With Multi-Mode enabled, use the option <b>Show Contrast Curve</b> to edit the correction curve and check <b>Preserve Highlights</b> for softer highlights.<br> <b>Brightness</b> and <b>Saturation</b> corrections are non linear to limit clipping.<br> Sliders are <b>reset</b> to their default value by double clicking the name of the slider.<br> """ ) # end setWhatsThis
def __init__(self, targetImage=None, axeSize=500, layer=None, parent=None): super().__init__(layer=layer, targetImage=targetImage, parent=parent) ####################################### # Libraw correspondences: # rgb_xyz_matrix is libraw cam_xyz # camera_whitebalance is libraw cam_mul # daylight_whitebalance is libraw pre_mul # dng correspondences: # ASSHOTNEUTRAL tag value is (X,Y,Z) = 1 / rawpyObj.camera_whitebalance ########################################## rawpyObj = layer.parentImage.rawImage # constants and as shot values self.XYZ2CameraMatrix = rawpyObj.rgb_xyz_matrix[:3, :] self.XYZ2CameraInverseMatrix = np.linalg.inv(self.XYZ2CameraMatrix) # initial post processing multipliers (as shot) m1, m2, m3, m4 = rawpyObj.camera_whitebalance self.asShotMultipliers = (m1/m2, 1.0, m3/m2, m4/m2) # normalization is mandatory : for nef files white balance is around 256 self.asShotTemp, self.asShotTint = multipliers2TemperatureAndTint(*1 / np.array(self.asShotMultipliers[:3]), self.XYZ2CameraMatrix) self.rawMultipliers = self.asShotMultipliers # rawpyObj.camera_whitebalance # = 1/(dng ASSHOTNEUTRAL tag value) self.sampleMultipliers = False self.samples = [] ######################################## # XYZ-->Camera conversion matrix: # Last row is zero for RGB cameras (cf. rawpy and libraw docs). # type ndarray, shape (4,3) ######################################### # attributes initialized in setDefaults, declared here for the sake of correctness self.tempCorrection, self.tintCorrection, self.expCorrection, self.highCorrection,\ self.contCorrection, self.satCorrection, self.brCorrection = [None] * 7 # contrast spline vie (initialized by setContrastSpline) self.contrastForm = None # tone spline view (initialized by setToneSpline) self.toneForm = None # dock containers for contrast and tome forms self.dockC, self.dockT = None, None # options optionList0, optionNames0 = ['Auto Brightness', 'Preserve Highlights'], ['Auto Expose', 'Preserve Highlights'] optionList1, optionNames1 = ['Auto WB', 'Camera WB', 'User WB'], ['Auto', 'Camera (As Shot)', 'User'] optionList2, optionNames2 = ['cpLookTable', 'cpToneCurve', 'manualCurve'], ['Use Camera Profile Look Table', 'Show Tone Curves', 'Show Contrast Curve'] self.listWidget1 = optionsWidget(options=optionList0, optionNames=optionNames0, exclusive=False, changed=lambda: self.dataChanged.emit(1)) self.listWidget2 = optionsWidget(options=optionList1, optionNames=optionNames1, exclusive=True, changed=lambda: self.dataChanged.emit(1)) self.listWidget3 = optionsWidget(options=optionList2, optionNames=optionNames2, exclusive=False, changed=lambda: self.dataChanged.emit(2)) self.options = UDict((self.listWidget1.options, self.listWidget2.options, self.listWidget3.options)) # display the 'as shot' temperature item = self.listWidget2.item(1) item.setText(item.text() + ' : %d' % self.asShotTemp) # temperature slider self.sliderTemp = QbLUeSlider(Qt.Horizontal) self.sliderTemp.setStyleSheet(QbLUeSlider.bLueSliderDefaultColorStylesheet) self.sliderTemp.setRange(0, 100) self.sliderTemp.setSingleStep(1) self.tempLabel = QLabel() self.tempLabel.setText("Temp") self.tempValue = QLabel() font = self.tempValue.font() metrics = QFontMetrics(font) w = metrics.width("10000") h = metrics.height() self.tempValue.setMinimumSize(w, h) self.tempValue.setMaximumSize(w, h) self.tempValue.setText(str("{:.0f}".format(self.slider2Temp(self.sliderTemp.value())))) self.sliderTemp.valueChanged.connect(self.tempUpdate) # signal send new value as parameter self.sliderTemp.sliderReleased.connect(lambda: self.tempUpdate(self.sliderTemp.value())) # signal pass no parameter # tint slider self.sliderTint = QbLUeSlider(Qt.Horizontal) self.sliderTint.setStyleSheet(QbLUeSlider.bLueSliderDefaultIMGColorStylesheet) self.sliderTint.setRange(0, 150) self.sliderTint.setSingleStep(1) self.tintLabel = QLabel() self.tintLabel.setText("Tint") self.tintValue = QLabel() font = self.tempValue.font() metrics = QFontMetrics(font) w = metrics.width("100") h = metrics.height() self.tintValue.setMinimumSize(w, h) self.tintValue.setMaximumSize(w, h) self.tintValue.setText(str("{:.0f}".format(self.sliderTint2User(self.sliderTint.value())))) self.sliderTint.valueChanged.connect(self.tintUpdate) self.sliderTint.sliderReleased.connect(lambda: self.tintUpdate(self.sliderTint.value())) # signal pass no parameter) ###################### # From libraw and dcraw sources: # Exposure and brightness are curve transformations. # Exposure curve is y = alpha*x, with cubic root ending; it is applied before demosaicing. # Brightness is (similar to) y = x**alpha and part of gamma transformation from linear sRGB to RGB. # Exposure and brightness both dilate the histogram towards highlights. # Exposure dilatation is uniform (homothety), brightness dilataion is # maximum for the midtones and the highlghts are preserved. # As a consequence, normal workflow begins with the adjustment of exposure, # to fill the entire range of the histogram and to adjust the highlights. Next, # one adjusts the brightness to put the midtones at the level we want them to be. # Cf. https://www.cambridgeincolour.com/forums/thread653.htm ##################### # profile combo self.dngDict = self.setCameraProfilesCombo() # cameraProfilesCombo index changed event handler def cameraProfileUpdate(value): self.dngDict = self.cameraProfilesCombo.itemData(value) if self.options['cpToneCurve']: toneCurve = dngProfileToneCurve(self.dngDict.get('ProfileToneCurve', [])) self.toneForm.baseCurve = [QPointF(x * axeSize, -y * axeSize) for x, y in zip(toneCurve.dataX, toneCurve.dataY)] self.toneForm.update() # recompute as shot temp and tint using new profile self.asShotTemp, self.asShotTint = multipliers2TemperatureAndTint(*1 / np.array(self.asShotMultipliers[:3]), self.XYZ2CameraMatrix, self.dngDict) # display updated as shot temp item = self.listWidget2.item(1) item.setText(item.text().split(":")[0] + ': %d' % self.asShotTemp) # invalidate cache self.layer.bufCache_HSV_CV32 = None self.dataChanged.emit(2) # 2 = no postprocessing self.cameraProfilesCombo.currentIndexChanged.connect(cameraProfileUpdate) # denoising combo self.denoiseCombo = QComboBox() items = OrderedDict([('Off', 0), ('Medium', 1), ('Full', 2)]) for key in items: self.denoiseCombo.addItem(key, items[key]) # denoiseCombo index changed event handler def denoiseUpdate(value): self.denoiseValue = self.denoiseCombo.itemData(value) self.dataChanged.emit(1) self.denoiseCombo.currentIndexChanged.connect(denoiseUpdate) # overexposed area restoration self.overexpCombo = QComboBox() items = OrderedDict([('Clip', 0), ('Ignore', 1), ('Blend', 2), ('Reconstruct', 3)]) for key in items: self.overexpCombo.addItem(key, items[key]) # overexpCombo index changed event handler def overexpUpdate(value): self.overexpValue = self.overexpCombo.itemData(value) self.dataChanged.emit(1) self.overexpCombo.currentIndexChanged.connect(overexpUpdate) # exp slider self.sliderExp = QbLUeSlider(Qt.Horizontal) self.sliderExp.setStyleSheet(QbLUeSlider.bLueSliderDefaultBWStylesheet) self.sliderExp.setRange(0, 100) self.sliderExp.setSingleStep(1) self.expLabel = QLabel() self.expLabel.setText("Exp.") self.expValue = QLabel() font = self.expValue.font() metrics = QFontMetrics(font) w = metrics.width("+1.0") h = metrics.height() self.expValue.setMinimumSize(w, h) self.expValue.setMaximumSize(w, h) self.expValue.setText(str("{:.1f}".format(self.slider2Exp(self.sliderExp.value())))) # exp done event handler def expUpdate(value): self.expValue.setText(str("{:+.1f}".format(self.sliderExp2User(self.sliderExp.value())))) # move not yet terminated or value not modified if self.sliderExp.isSliderDown() or self.slider2Exp(value) == self.expCorrection: return try: self.sliderExp.valueChanged.disconnect() self.sliderExp.sliderReleased.disconnect() except RuntimeError: pass # rawpy: expCorrection range is -2.0...3.0, boiling down to exp_shift range 2**(-2)=0.25...2**3=8.0 self.expCorrection = self.slider2Exp(self.sliderExp.value()) self.dataChanged.emit(1) self.sliderExp.valueChanged.connect(expUpdate) # send new value as parameter self.sliderExp.sliderReleased.connect(lambda: expUpdate(self.sliderExp.value())) # signal pass no parameter self.sliderExp.valueChanged.connect(expUpdate) # send new value as parameter self.sliderExp.sliderReleased.connect(lambda: expUpdate(self.sliderExp.value())) # signal pass no parameter # brightness slider brSlider = QbLUeSlider(Qt.Horizontal) brSlider.setRange(1, 101) self.sliderExp.setSingleStep(1) brSlider.setStyleSheet(QbLUeSlider.bLueSliderDefaultBWStylesheet) self.sliderBrightness = brSlider brLabel = QLabel() brLabel.setText("Bright.") self.brValue = QLabel() font = self.expValue.font() metrics = QFontMetrics(font) w = metrics.width("+99") h = metrics.height() self.brValue.setMinimumSize(w, h) self.brValue.setMaximumSize(w, h) self.brValue.setText(str("{:+d}".format(int(self.brSlider2User(self.sliderBrightness.value()))))) # brightness done event handler def brUpdate(value): self.brValue.setText(str("{:+d}".format(int(self.brSlider2User(self.sliderBrightness.value()))))) # move not yet terminated or value not modified if self.sliderBrightness.isSliderDown() or self.slider2Br(value) == self.brCorrection: return try: self.sliderBrightness.valueChanged.disconnect() self.sliderBrightness.sliderReleased.disconnect() except RuntimeError: pass self.brCorrection = self.slider2Br(self.sliderBrightness.value()) self.dataChanged.emit(1) self.sliderBrightness.sliderReleased.connect(lambda: brUpdate(self.sliderBrightness.value())) self.sliderBrightness.valueChanged.connect(brUpdate) # send new value as parameter self.sliderBrightness.valueChanged.connect(brUpdate) # send new value as parameter self.sliderBrightness.sliderReleased.connect(lambda: brUpdate(self.sliderBrightness.value())) # contrast slider self.sliderCont = QbLUeSlider(Qt.Horizontal) self.sliderCont.setStyleSheet(QbLUeSlider.bLueSliderDefaultBWStylesheet) self.sliderCont.setRange(0, 20) self.sliderCont.setSingleStep(1) self.contLabel = QLabel() self.contLabel.setText("Cont.") self.contValue = QLabel() font = self.contValue.font() metrics = QFontMetrics(font) w = metrics.width("100") h = metrics.height() self.contValue.setMinimumSize(w, h) self.contValue.setMaximumSize(w, h) self.contValue.setText(str("{:.0f}".format(self.slider2Cont(self.sliderCont.value())))) # cont done event handler def contUpdate(value): self.contValue.setText(str("{:.0f}".format(self.slider2Cont(self.sliderCont.value())))) # move not yet terminated or value not modified if self.sliderCont.isSliderDown() or self.slider2Cont(value) == self.tempCorrection: return try: self.sliderCont.valueChanged.disconnect() self.sliderCont.sliderReleased.disconnect() except RuntimeError: pass self.contCorrection = self.slider2Cont(self.sliderCont.value()) self.contValue.setText(str("{:+d}".format(self.contCorrection))) # force to recalculate the spline self.layer.autoSpline = True self.dataChanged.emit(3) # no postprocessing and no camera profile stuff self.sliderCont.valueChanged.connect(contUpdate) # send new value as parameter self.sliderCont.sliderReleased.connect(lambda: contUpdate(self.sliderCont.value())) # signal has no parameter self.sliderCont.valueChanged.connect(contUpdate) # send new value as parameter self.sliderCont.sliderReleased.connect(lambda: contUpdate(self.sliderCont.value())) # signal has no parameter # saturation slider self.sliderSat = QbLUeSlider(Qt.Horizontal) self.sliderSat.setStyleSheet(QbLUeSlider.bLueSliderDefaultColorStylesheet) self.sliderSat.setRange(0, 100) self.sliderSat.setSingleStep(1) satLabel = QLabel() satLabel.setText("Sat.") self.satValue = QLabel() font = self.satValue.font() metrics = QFontMetrics(font) w = metrics.width("+10") h = metrics.height() self.satValue.setMinimumSize(w, h) self.satValue.setMaximumSize(w, h) self.satValue.setText(str("{:+d}".format(self.slider2Sat(self.sliderSat.value())))) """sat done event handler""" def satUpdate(value): self.satValue.setText(str("{:+d}".format(self.slider2Sat(self.sliderSat.value())))) # move not yet terminated or value not modified if self.sliderSat.isSliderDown() or self.slider2Sat(value) == self.satCorrection: return try: self.sliderSat.valueChanged.disconnect() self.sliderSat.sliderReleased.disconnect() except RuntimeError: pass self.satCorrection = self.slider2Sat(self.sliderSat.value()) self.dataChanged.emit(3) # no post processing and no camera profile stuff self.sliderSat.valueChanged.connect(satUpdate) # send new value as parameter self.sliderSat.sliderReleased.connect(lambda: satUpdate(self.sliderSat.value())) # signal has no parameter self.sliderSat.valueChanged.connect(satUpdate) # send new value as parameter self.sliderSat.sliderReleased.connect(lambda: satUpdate(self.sliderSat.value())) # signal has no parameter self.setStyleSheet("QListWidget, QLabel {font : 7pt;}") # layout l = QVBoxLayout() l.addWidget(self.listWidget3) hl01 = QHBoxLayout() hl01.addWidget(QLabel('Camera Profile')) hl01.addWidget(self.cameraProfilesCombo) l.addLayout(hl01) hl0 = QHBoxLayout() hl0.addWidget(QLabel('Denoising')) hl0.addWidget(self.denoiseCombo) l.addLayout(hl0) hl00 = QHBoxLayout() hl00.addWidget(QLabel('Overexp. Restoration')) hl00.addWidget(self.overexpCombo) l.addLayout(hl00) hl1 = QHBoxLayout() hl1.addWidget(self.expLabel) hl1.addWidget(self.expValue) hl1.addWidget(self.sliderExp) l.addLayout(hl1) hl8 = QHBoxLayout() hl8.addWidget(brLabel) hl8.addWidget(self.brValue) hl8.addWidget(self.sliderBrightness) l.addLayout(hl8) l.addWidget(self.listWidget1) self.listWidget2.setStyleSheet("QListWidget {border: 0px;} QListWidget::item {border: 0px; padding-left: 20px;}") vl1 = QVBoxLayout() vl1.addWidget(QLabel('White Balance')) vl1.addWidget(self.listWidget2) gb1 = QGroupBox() gb1.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 4px}") hl2 = QHBoxLayout() hl2.addWidget(self.tempLabel) hl2.addWidget(self.tempValue) hl2.addWidget(self.sliderTemp) hl3 = QHBoxLayout() hl3.addWidget(self.tintLabel) hl3.addWidget(self.tintValue) hl3.addWidget(self.sliderTint) vl1.addLayout(hl2) vl1.addLayout(hl3) gb1.setLayout(vl1) l.addWidget(gb1) hl4 = QHBoxLayout() hl4.addWidget(self.contLabel) hl4.addWidget(self.contValue) hl4.addWidget(self.sliderCont) hl7 = QHBoxLayout() hl7.addWidget(satLabel) hl7.addWidget(self.satValue) hl7.addWidget(self.sliderSat) # separator sep = QFrame() sep.setFrameShape(QFrame.HLine) sep.setFrameShadow(QFrame.Sunken) l.addWidget(sep) l.addLayout(hl4) l.addLayout(hl7) l.addStretch(1) self.setLayout(l) self.adjustSize() self.setDefaults() self.setWhatsThis( """<b>Development of raw files</b><br> <b>Default settings</b> are a good starting point.<br> A <b>Tone Curve</b> is applied to the raw image prior to postprocessing.<br> The cuvre can be edited by checking the option <b>Show Tone Curve</b>; this option works best with manual exposure.<br> <b>Contrast</b> correction is based on an automatic algorithm well suited to multi-mode histograms.<br> <b>Brightness, Contrast</b> and <b>Saturation</b> levels</b> are adjustable with the correponding sliders.<br> The <b>Contrast Curve</b> can be edited manually by checking the option <b>Show Contrast Curve</b>.<br> Uncheck <b>Auto Expose</b> to adjust the exposure manually.<br> The <b>OverExp. Rest.</b> slider controls the mode of restoration of overexposed areas. Valid values are 0 to 3 (0=clip;1=unclip;2=blend;3=rebuild); (with Auto Exposed checked the mode is clip).<br> """ ) # end of setWhatsThis
class AddNew(QWidget): def __init__(self, main_table): super(AddNew, self).__init__() self.table = main_table self.headers = main_table.model_c.metadata_c.metadata["headers"] self.title = f'Add New - {self.table.model_c.path_c.get_file_name()}' # DESCRIPTION self.setWindowTitle(self.title) self.setWindowState(Qt.WindowMaximized) self.setStyleSheet(styles.main_dark) # MAIN LAYOUT self.main_v_layout = QVBoxLayout() # SPLITTER self.splitter = QSplitter(self) # MAIN TOOL BAR self.toolbar = QGroupBox(self) self.set_up_toolbar() # SIDE WORKSPACE self.side_widget = None # MAIN WORKSPACE main_workspace_layout = QVBoxLayout() self.main_widget = QWidget(self) self.headers_inputs = HeadersInput(self, self.headers) # MAIN WORKSPACE BUTTONS button_h_layout = QHBoxLayout() self.button_add = QPushButton("ADD", self) self.button_add.clicked.connect(self.add_new) self.button_clear = QPushButton("Clear", self) self.button_clear.clicked.connect(self.clear) button_h_layout.addWidget(self.button_add) button_h_layout.addWidget(self.button_clear) # SET UP main_workspace_layout.addWidget(self.headers_inputs) main_workspace_layout.addLayout(button_h_layout) self.main_widget.setLayout(main_workspace_layout) self.splitter.addWidget(self.main_widget) self.main_v_layout.addWidget(self.toolbar) self.main_v_layout.addWidget(self.splitter) self.setLayout(self.main_v_layout) self.show() def add_new(self): item = self.headers_inputs.get_values() if not item: return _, contains_in_self = self.table.add(item) self.open_home_table() def clear(self): self.headers_inputs.clear() def open_home_table(self): if self.side_widget is not None: self.side_widget.close() self.side_widget = SideTable(self, self.table.model_c) self.splitter.insertWidget(-1, self.side_widget) def set_up_toolbar(self): vbox = QHBoxLayout() self.toolbar.setStyleSheet(styles.tool_bar_groupbox_dark) vbox.setAlignment(Qt.AlignLeft) vbox.setContentsMargins(10, 0, 0, 0) self.toolbar.setLayout(vbox) self.toolbar.setFixedHeight(40) home_table = QPushButton(QIcon(icon.HOME_SCREEN_I()), "", self.toolbar) vbox.addWidget(home_table) parent_relation_option = (list( map( lambda relation: { "text": relation["name_of_child_table"], "parm": relation["path_of_child_table"], "icon": icon.MULTICAST_I(), "callback": self.open_parent, "tooltip": relation["name_of_relation"] }, self.table.model_c.metadata_c.metadata["sequential_info"] ["parent_relation"]))) if len(parent_relation_option) > 0: select_parent = ButtonOptions(self.toolbar, parent_relation_option, icon.MULTICAST_I()) vbox.addWidget(select_parent) child_relations_options = (list( map( lambda relation: { "text": relation["name_of_child_table"], "parm": relation["path_of_child_table"], "icon": icon.MULTICAST_I(), "callback": self.open_parent, "tooltip": relation["name_of_relation"] }, self.table.model_c.metadata_c.metadata["sequential_info"] ["child_relation"]))) if len(child_relations_options) > 0: add_child = ButtonOptions(self.toolbar, child_relations_options, icon.DOWN_BUTTON_I()) vbox.addWidget(add_child) home_table.setStatusTip(f"Open '{self.table.model_c.path_c.path}'") home_table.clicked.connect(self.open_home_table) def open_parent(self, path): if self.side_widget is not None: self.side_widget.close() self.side_widget = SideTableSelectParent( self, SQFile(Path(path), True), self.headers_inputs.set_parent, self.table.model_c.path_c) self.splitter.insertWidget(-1, self.side_widget) def open_child(self, path): ...
class Main(QWidget): def __init__(self): super().__init__() self.user_entry = QLineEdit("user5301") # self.user_entry.setStyleSheet("font: corbel; font-size: 12px;") self.pass_entry = QLineEdit("e", self) self.odbc = "" self.bars = "" self.table_query = "" self.pass_entry.setEchoMode(QLineEdit.PasswordEchoOnEdit) self.ru_entry = QLineEdit("328845", self) # self.ru_entry.setStyleSheet("font: corbel; font-size: 12px;") self.cur_entry = QLineEdit("840") # self.cur_entry.setStyleSheet("font: corbel; font-size: 12px;") self.balance_entry = QLineEdit("213000001") # self.balance_entry.setStyleSheet("font: corbel; font-size: 12px;") self.ok_button = QPushButton( "Запрос (Пользователь и пароль должны быть правильными.)") self.ok_button.setStyleSheet( "font: corbel; font-size: 12px; color: rgb(0, 0, 255)") # self.ok_button.setStyleSheet("color: rgb(160, 70, 70)") self.error_label = QLabel("Количество строк или ошибки будут тут") self.error_label.setStyleSheet("color: rgb(255, 0, 0)") self.start_button1 = QPushButton("Старт") self.stop_button1 = QPushButton("Стоп") self.start_button1.setEnabled(True) self.stop_button1.setEnabled(False) self.start_button1.setStyleSheet("background-color: rgb(81,142,144)") self.interval_l = QLabel("Интервал") # self.interval_l.setStyleSheet("font: corbel; font-size: 12px; color: rgb(0, 0, 255)") self.interval_e = QLineEdit() self.timer_id = 0 self.table = QTableView() # Create model # self.sqm = QSqlQueryModel(parent=self.table) self.standart_item_model = QStandardItemModel() self.init_ui() def on_start(self): password = self.pass_entry.text() if password == "e": self.print_and_label("Вы не ввели пароль!") else: self.timer_id = self.startTimer(int(self.interval_e.text())) self.start_button1.setEnabled(False) self.stop_button1.setEnabled(True) def on_stop(self): print("Таймер остановлен.", self.timer_id) if self.timer_id: self.killTimer(self.timer_id) self.timer_id = 0 self.start_button1.setEnabled(True) self.stop_button1.setEnabled(False) def print_and_label(self, text): print(text) self.error_label.setText(text) def run(self): rows = connect_to_base_and_execute( self.table_query.format(self.ru_entry.text().strip(), self.cur_entry.text().strip(), int(self.balance_entry.text().strip())), self.error_label, self.user_entry.text(), keyring.get_password(getpass.getuser(), self.user_entry.text()), self.ok_button, "''") self.standart_item_model.clear() self.table.clearSpans() item_list = [] if rows: #print("rows", rows) for values in rows: item_list = [] for value in values: if type(value) == int: item = QStandardItem(str(value)) else: item = QStandardItem(value) item_list.append(item) self.standart_item_model.appendRow(item_list) self.standart_item_model.setHorizontalHeaderLabels( ["Счет", "РУ", "Валюта", "Остаток"]) self.table.setModel(self.standart_item_model) self.table.setColumnWidth(0, 150) self.table.setColumnWidth(1, 60) self.table.setColumnWidth(2, 80) self.table.setColumnWidth(3, 150) if self.standart_item_model.rowCount() > 0: frequency = 2500 duration = 2000 winsound.Beep(frequency, duration) def timerEvent(self, event): # self.error_label.setText("Сработал таймер" + str(event.timerId())) print("Сработал таймер", str(event.timerId())) self.run() def init_ui(self): file_name = 'ini_balance' with open(file_name) as f: lines = f.readlines() try: self.interval_e.setText(lines[0]) except: self.error_label.setText( ' Возможно в первой строке файла ini_balance нет времени таймера!' ) try: self.bars = lines[1] except: self.error_label.setText( ' Возможно во второй строке файла ini_balance нет запроса!' ) try: self.table_query = lines[2] except: self.error_label.setText( ' Возможно в третьей строке файла ini_balance нет запроса!' ) label = QLabel(self) label.setAlignment(Qt.AlignRight) label.resize(30, 30) image = QPixmap("b.jfif", format="JPG").scaled(label.width(), label.height()) #image = QPixmap("mon.png", format="PNG") label.setPixmap(image) self.group = QGroupBox("Таймер остатка") self.group.setStyleSheet("font: corbel; font-size: 14px;") v_group = QVBoxLayout() # Контейнер для группы v_group.addWidget(self.start_button1) v_group.addWidget(self.stop_button1) v_group.addWidget(self.interval_l) v_group.addWidget(self.interval_e) self.group.setLayout(v_group) form = QFormLayout() form.addRow("", label) form.addRow("По&льзователь", self.user_entry) form.addRow("&Пароль", self.pass_entry) form.addRow("&МФО области", self.ru_entry) form.addRow("&Валюта", self.cur_entry) form.addRow("&Необходимый остаток", self.balance_entry) form.addRow("", self.ok_button) form.addRow("", self.group) form.addRow("&Результат", self.table) form.addRow("&Ошибки", self.error_label) self.setLayout(form) # k10 - work with password # is_right in - hash, return - T/F; set_p in - pass return - hash hash_pass = hashlib.md5(self.pass_entry.text().encode('utf-8')) # print("hash", hash_pass) # keyring.set_password(getpass.getuser(), self.user_entry.text(), self.pass_entry.text()) self.pass_entry.editingFinished.connect( lambda: k10.keyring_pass(getpass.getuser(), self.user_entry.text( ), self.pass_entry, hash_pass, self.ru_entry)) self.ok_button.clicked.connect(lambda: self.run()) self.start_button1.clicked.connect(self.on_start) self.stop_button1.clicked.connect(self.on_stop) self.setGeometry(300, 100, 650, 550) self.setWindowTitle('Ждем деньги') self.show()
class IssuesTab(QWidget): def __init__(self, parent): QWidget.__init__(self) self.Parent = parent self.IssueTitle = 'ISSUES' self.UI() @property def Title(self): return self.IssueTitle def UI(self): self.widgets() self.layouts() self.funcDisplayIssues() def widgets(self): # Issues widgets ########################################################### # Top layout (search issues) widgets self.searchIssuesText = QLabel("Search: ") self.searchIssuesEntry = QLineEdit() self.searchIssuesEntry.setPlaceholderText("Search issues..") self.searchIssuesBtn = QPushButton("Search") self.searchIssuesBtn.setObjectName("btn_searchIssues") self.searchIssuesBtn.clicked.connect(self.funcSearchIssues) self.refreshIssuesBtn = QPushButton("Refresh") self.refreshIssuesBtn.clicked.connect(self.funcDisplayIssues) # Middle layout (list issues) widgets with radio buttons self.allIssuesRadioBtn = QRadioButton("All issues") self.ongoingIssuesRadioBtn = QRadioButton("Pending issues") self.lateIssuesRadioBtn = QRadioButton("Late issues") self.closedIssuesRadioBtn = QRadioButton("Closed issues") self.listIssuesBtn = QPushButton("List") self.listIssuesBtn.setObjectName("btn_listIssues") self.listIssuesBtn.clicked.connect(self.funcListIssues) # Bottom layout widget # Table showing issues self.issuesTable = QTableWidget() self.issuesTable.verticalHeader().hide() self.issuesTable.setSortingEnabled(True) self.issuesTable.setShowGrid(False) self.issuesTable.verticalHeader().setDefaultSectionSize(90) self.issuesTable.setColumnCount(13) self.issuesTable.setHorizontalHeaderItem(0, QTableWidgetItem("")) self.issuesTable.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.issuesTable.setHorizontalHeaderItem(1, QTableWidgetItem("Status")) self.issuesTable.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) self.issuesTable.setHorizontalHeaderItem(2, QTableWidgetItem("ID")) self.issuesTable.setHorizontalHeaderItem(3, QTableWidgetItem("Date")) self.issuesTable.setHorizontalHeaderItem(4, QTableWidgetItem("Priority")) self.issuesTable.setHorizontalHeaderItem(5, QTableWidgetItem("Observer")) self.issuesTable.horizontalHeader().setSectionResizeMode(5, QHeaderView.Stretch) self.issuesTable.setHorizontalHeaderItem(6, QTableWidgetItem("Inspection name")) self.issuesTable.horizontalHeader().setSectionResizeMode(6, QHeaderView.Stretch) self.issuesTable.setHorizontalHeaderItem(7, QTableWidgetItem("Theme")) self.issuesTable.horizontalHeader().setSectionResizeMode(7, QHeaderView.Stretch) self.issuesTable.setHorizontalHeaderItem(8, QTableWidgetItem("Facility")) self.issuesTable.setHorizontalHeaderItem(9, QTableWidgetItem("Insp. Dept")) self.issuesTable.setHorizontalHeaderItem(10, QTableWidgetItem("Deadline")) self.issuesTable.setHorizontalHeaderItem(11, QTableWidgetItem("Status")) self.issuesTable.setHorizontalHeaderItem(12, QTableWidgetItem("Created on")) # Double clicking a row opens a window with issue details self.issuesTable.doubleClicked.connect(self.funcSelectedIssue) # Buttons for actions on selected issues self.addIssue = QPushButton("Add") self.addIssue.setObjectName("btn_addIssue") self.addIssue.clicked.connect(self.funcAddIssue) self.viewIssue = QPushButton("View/Edit") self.viewIssue.setObjectName("btn_viewIssue") self.viewIssue.clicked.connect(self.funcSelectedIssue) self.closeIssueBtn = QPushButton("Close") self.closeIssueBtn.setObjectName("btn_closeIssue") self.closeIssueBtn.clicked.connect(self.funcCloseIssue) self.deleteIssue = QPushButton("Delete") self.deleteIssue.setObjectName("btn_deleteIssue") self.deleteIssue.clicked.connect(self.funcDeleteIssue) self.exportIssuesCSVBtn = QPushButton("Export CSV") self.exportIssuesCSVBtn.setEnabled(False) self.exportIssuesCSVBtn.setObjectName("btn_exportIssuesCSV") self.exportIssuesCSVBtn.clicked.connect(self.funcIssuesToCSV) self.exportIssuesXLSXBtn = QPushButton("Export XLSX") self.exportIssuesXLSXBtn.setEnabled(False) self.exportIssuesXLSXBtn.setObjectName("btn_exportIssuesXLSX") self.exportIssuesXLSXBtn.clicked.connect(self.funcIssuestoXLSX) self.exportIssuesPDFBtn = QPushButton("Export PDF") self.exportIssuesPDFBtn.setEnabled(False) self.exportIssuesPDFBtn.setObjectName("btn_exportIssuesPDF") self.exportIssuesPDFBtn.clicked.connect(self.funcIssuesToPdf) def layouts(self): # Issues layouts ########################################################### self.issuesMainLayout = QVBoxLayout() self.issuesMainTopLayout = QHBoxLayout() self.issuesTopLeftLayout = QHBoxLayout() self.issuesTopRightLayout = QHBoxLayout() # self.issuesMainMiddleLayout = QHBoxLayout() self.issuesMainBottomLayout = QHBoxLayout() self.issuesBottomRightLayout = QVBoxLayout() self.issuesBottomLeftLayout = QHBoxLayout() # Groupboxes allow customization using CSS-like syntax # self.issuesTopGroupBox = QGroupBox() # self.issuesTopGroupBoxRightFiller = QGroupBox() # self.issuesTopGroupBoxRightFiller.setStyleSheet(styles.groupBoxFillerStyle()) # # self.issuesMiddleGroupBox = QGroupBox() # self.issuesMiddleGroupBoxRightFiller = QGroupBox() # self.issuesMiddleGroupBoxRightFiller.setStyleSheet(styles.groupBoxFillerStyle()) self.issuesTopLeftGroupBox = QGroupBox() self.issuesTopRightGroupBox = QGroupBox() self.issuesTopGroupBox = QGroupBox() self.issuesBottomGroupBox = QGroupBox() self.issuesBottomLeftGroupBox = QGroupBox() self.issuesBottomRightGroupBox = QGroupBox() self.issuesBottomRightGroupBox.setStyleSheet('QGroupBox {margin-top: 0px;}') self.issuesBottomRightGroupBoxFiller = QGroupBox() self.issuesBottomRightGroupBoxFiller.setStyleSheet(styles.groupBoxFillerStyle()) # Add widgets # Top layout (search box) widgets self.issuesTopLeftLayout.addWidget(self.searchIssuesText, 10) self.issuesTopLeftLayout.addWidget(self.searchIssuesEntry, 30) self.issuesTopLeftLayout.addWidget(self.searchIssuesBtn, 10) self.issuesTopLeftLayout.addItem(QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.issuesTopLeftLayout.addWidget(self.refreshIssuesBtn, 10) self.issuesTopLeftGroupBox.setLayout(self.issuesTopLeftLayout) # layout (list box) widgets self.issuesTopRightLayout.addWidget(self.allIssuesRadioBtn) self.issuesTopRightLayout.addWidget(self.ongoingIssuesRadioBtn) self.issuesTopRightLayout.addWidget(self.lateIssuesRadioBtn) self.issuesTopRightLayout.addWidget(self.closedIssuesRadioBtn) self.issuesTopRightLayout.addWidget(self.listIssuesBtn) self.issuesTopRightGroupBox.setLayout(self.issuesTopRightLayout) self.issuesMainTopLayout.addWidget(self.issuesTopLeftGroupBox, 60) self.issuesMainTopLayout.addWidget(self.issuesTopRightGroupBox, 40) # Bottom layout (table with facilities) widgets # Bottom left layout with table self.issuesBottomLeftLayout.addWidget(self.issuesTable) self.issuesBottomLeftGroupBox.setLayout(self.issuesBottomLeftLayout) # Bottom right layout with buttons self.issuesBottomRightLayout.addWidget(self.addIssue, 5) self.issuesBottomRightLayout.addWidget(self.viewIssue, 5) self.issuesBottomRightLayout.addWidget(self.closeIssueBtn, 5) self.issuesBottomRightLayout.addWidget(self.deleteIssue, 5) self.issuesBottomRightLayout.addWidget(self.issuesBottomRightGroupBoxFiller, 65) self.issuesBottomRightLayout.addWidget(self.exportIssuesCSVBtn, 5) self.issuesBottomRightLayout.addWidget(self.exportIssuesXLSXBtn, 5) self.issuesBottomRightLayout.addWidget(self.exportIssuesPDFBtn, 5) self.issuesBottomRightGroupBox.setLayout(self.issuesBottomRightLayout) self.issuesMainBottomLayout.addWidget(self.issuesTable, 90) self.issuesMainBottomLayout.addWidget(self.issuesBottomRightGroupBox, 10) self.issuesMainLayout.addLayout(self.issuesMainTopLayout, 10) self.issuesMainLayout.addLayout(self.issuesMainBottomLayout, 90) self.setLayout(self.issuesMainLayout) # Populating the table @Slot() def funcDisplayIssues(self): for i in reversed(range(self.issuesTable.rowCount())): self.issuesTable.removeRow(i) issues = db.cur.execute("SELECT " "issue_id, " "issue_date, " "issue_priority, " "issue_observer," "issue_inspection, " "issue_theme, " "issue_facility, " "issue_insp_dept," "issue_deadline, " "status, " "created_on " "FROM issues") for row_data in issues: row_number = self.issuesTable.rowCount() self.issuesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) checkbox.stateChanged.connect(self.funcActivateBtnsWithCheckbox) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.issuesTable.setCellWidget(row_number, 0, qwidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add status photos_thumbnails to the table thumbStatusWidget = QWidget() # Assign proper status thumbnails based on deadline if row_data[9] == "Closed": pic = QPixmap('assets/icons/issue_icons/issue_closed_icon.png') elif row_data[8] > str(datetime.datetime.now()): pic = QPixmap('assets/icons/issue_icons/issue_pending_icon.png') elif row_data[8] < str(datetime.datetime.now()): pic = QPixmap('assets/icons/issue_icons/issue_late_icon.png') thumbStatusLabel = QLabel() thumbStatusLabel.setPixmap(pic) thumbStatusLayout = QHBoxLayout(thumbStatusWidget) thumbStatusLayout.addWidget(thumbStatusLabel) self.issuesTable.setCellWidget(row_number, 1, thumbStatusWidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) thumbPriorityWidget = QWidget() # Assign priority thumbnails if row_data[2] == "Low": pic = QPixmap('assets/icons/issue_priority_icons/low_priority.png') elif row_data[2] == "Medium": pic = QPixmap('assets/icons/issue_priority_icons/medium_priority.png') elif row_data[2] == "High": pic = QPixmap('assets/icons/issue_priority_icons/high_priority.png') thumbPriorityLabel = QLabel() thumbPriorityLabel.setAlignment(Qt.AlignCenter) thumbPriorityLabel.setPixmap(pic) thumbPriorityLayout = QHBoxLayout(thumbPriorityWidget) thumbPriorityLayout.addWidget(thumbPriorityLabel) self.issuesTable.setCellWidget(row_number, 4, thumbPriorityWidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data))) elif column_number == 4: # Do not print priority in the table self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("")) else: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) self.issuesTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.issuesTable.setSelectionBehavior(QTableView.SelectRows) @Slot() def funcActivateBtnsWithCheckbox(self): indices = self.funcIssuesCheckBox() if self.sender().isChecked() or indices: self.exportIssuesCSVBtn.setEnabled(True) self.exportIssuesXLSXBtn.setEnabled(True) self.exportIssuesPDFBtn.setEnabled(True) else: self.exportIssuesCSVBtn.setEnabled(False) self.exportIssuesXLSXBtn.setEnabled(False) self.exportIssuesPDFBtn.setEnabled(False) @Slot() def funcAddIssue(self): self.newIssue = AddIssue(self) self.newIssue.setObjectName("add_issue_popup") self.newIssue.setStyleSheet(styles.addPopups()) @Slot() def funcIssuesCheckBox(self): checked_list = [] for i in range(self.issuesTable.rowCount()): if self.issuesTable.cellWidget(i, 0).findChild(type(QCheckBox())).isChecked(): item = self.issuesTable.item(i, 2).text() checked_list.append(item.lstrip("ISS#")) return checked_list @Slot() def funcSelectedIssue(self): self.displayIssue = DisplayIssue(self) @Slot() def funcSearchIssues(self): value = self.searchIssuesEntry.text() if value == "": QMessageBox.information(self, "Warning", "Search string cannot be empty") self.funcDisplayIssues() else: # Erase search entry self.searchIssuesEntry.setText("") try: query = "SELECT * FROM issues WHERE " \ "issue_id LIKE ? " \ "OR issue_date LIKE ?" \ "OR issue_priority LIKE ?" \ "OR issue_observer LIKE ?" \ "OR issue_team LIKE ?" \ "OR issue_inspection LIKE ?" \ "OR issue_theme LIKE ?" \ "OR issue_facility LIKE ?" \ "OR issue_fac_supervisor LIKE ?" \ "OR issue_spec_loc LIKE ?" \ "OR issue_insp_dept LIKE ?" \ "OR issue_insp_contr LIKE ?" \ "OR issue_insp_subcontr LIKE ?" \ "OR issue_deadline LIKE ?" results = db.cur.execute(query, ('%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%',)).fetchall() if results == []: QMessageBox.information(self, "Info", "Nothing was found") self.funcDisplayIssues() else: for i in reversed(range(self.issuesTable.rowCount())): self.issuesTable.removeRow(i) for row_data in results: row_number = self.issuesTable.rowCount() self.issuesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.issuesTable.setCellWidget(row_number, 0, qwidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data))) else: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") @Slot() def funcListIssues(self): try: if self.allIssuesRadioBtn.isChecked(): self.funcDisplayIssues() elif self.ongoingIssuesRadioBtn.isChecked(): query = "SELECT " \ "issue_id, " \ "issue_date, " \ "issue_priority, " \ "issue_observer," \ "issue_inspection, " \ "issue_theme, " \ "issue_facility, " \ "issue_insp_dept," \ "issue_deadline, " \ "status, " \ "created_on " \ "FROM issues WHERE status='Open' " \ "AND issue_deadline > DATETIME('now')" issues = db.cur.execute(query).fetchall() for i in reversed(range(self.issuesTable.rowCount())): self.issuesTable.removeRow(i) for row_data in issues: row_number = self.issuesTable.rowCount() self.issuesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.issuesTable.setCellWidget(row_number, 0, qwidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data))) else: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) elif self.lateIssuesRadioBtn.isChecked(): query = "SELECT issue_id, " \ "issue_date, " \ "issue_priority, " \ "issue_observer," \ "issue_inspection, " \ "issue_theme, " \ "issue_facility, " \ "issue_insp_dept," \ "issue_deadline, " \ "status, " \ "created_on " \ "FROM issues " \ "WHERE status='Open' AND issue_deadline < DATETIME('now')" issues = db.cur.execute(query).fetchall() for i in reversed(range(self.issuesTable.rowCount())): self.issuesTable.removeRow(i) for row_data in issues: row_number = self.issuesTable.rowCount() self.issuesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.issuesTable.setCellWidget(row_number, 0, qwidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data))) else: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) elif self.closedIssuesRadioBtn.isChecked(): query = "SELECT " \ "issue_id, " \ "issue_date, " \ "issue_priority, " \ "issue_observer," \ "issue_inspection, " \ "issue_theme, " \ "issue_facility, " \ "issue_insp_dept," \ "issue_deadline, " \ "status, " \ "created_on " \ "FROM issues WHERE status='Closed'" issues = db.cur.execute(query).fetchall() for i in reversed(range(self.issuesTable.rowCount())): self.issuesTable.removeRow(i) for row_data in issues: row_number = self.issuesTable.rowCount() self.issuesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.issuesTable.setCellWidget(row_number, 0, qwidget) self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data))) else: self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") @Slot() def funcCloseIssue(self): indices = self.funcIssuesCheckBox() # Close issues with selected checkboxes if indices: try: for index in range(len(indices)): statusQuery = "SELECT status FROM issues WHERE issue_id=?" currentStatus = db.cur.execute(statusQuery, (indices[index],)).fetchone() if currentStatus[0] == "Open": query = "UPDATE issues SET status='Closed' WHERE issue_id=?" db.cur.execute(query, (indices[index],)) db.conn.commit() else: QMessageBox.information(self, "Info", "Issue(s) is already closed") QMessageBox.information(self, "Info", "Operation completed successfully") self.funcDisplayIssues() except: QMessageBox.information(self, "Info", "Something went wrong") else: row = self.issuesTable.currentRow() issueId = self.issuesTable.item(row, 2).text() issueId = issueId.lstrip("ISS#") try: statusQuery = "SELECT status FROM issues WHERE issue_id=?" currentStatus = db.cur.execute(statusQuery, (issueId,)).fetchone() if currentStatus[0] == "Open": query = "UPDATE issues SET status='Closed' WHERE issue_id=?" db.cur.execute(query, (issueId,)) db.conn.commit() QMessageBox.information(self, "Info", "Issue closed successfully") self.funcDisplayIssues() else: QMessageBox.information(self, "Info", "Issue is already closed") except: QMessageBox.information(self, "Info", "Something went wrong") @Slot() def funcDeleteIssue(self): indices = self.funcIssuesCheckBox() mbox = QMessageBox.question(self, "Warning", "Are you sure you want to delete selected issue(s)?", QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if (mbox == QMessageBox.Yes): if indices: try: for index in range(len(indices)): query = "DELETE FROM issues WHERE issue_id = ?" db.cur.execute(query, (indices[index],)) db.conn.commit() QMessageBox.information(self, "Info", "Issues were deleted") self.funcDisplayIssues() except: QMessageBox.information(self, "Info", "No changes made") else: row = self.issuesTable.currentRow() issueId = self.issuesTable.item(row, 2).text() issueId = issueId.lstrip("ISS#") try: query = "DELETE FROM issues WHERE issue_id = ?" db.cur.execute(query, (issueId,)) db.conn.commit() QMessageBox.information(self, "Info", "Issue was deleted") self.funcDisplayIssues() except: QMessageBox.information(self, "Info", "No changes made") self.displayIssue.close() @Slot() def funcIssuesToCSV(self): indices = self.funcIssuesCheckBox() if indices: CSV(self, "issues", indices) else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export") @Slot() def funcIssuestoXLSX(self): indices = self.funcIssuesCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp to when it was created to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/IssuesXLSX" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx", "Excel files (*.xlsx)") if fileName: db.cur.execute("SELECT * FROM issues") workbook = xlsxwriter.Workbook(fileName) worksheet = workbook.add_worksheet("Issues") worksheet.set_column('A:C', 12) worksheet.set_row(0, 30) merge_format = workbook.add_format({ 'bold': 1, 'align': 'center', 'valign': 'vcenter'}) worksheet.merge_range('A1:B1', '', merge_format) worksheet.insert_image('A1', './assets/logo/logo-full-main.png', {'x_scale': 0.4, 'y_scale': 0.4, 'x_offset': 15, 'y_offset': 10}) # Create header row stop = 17 col = 0 for i, value in enumerate(db.cur.description[:stop]): worksheet.write(1, col, value[0]) col += 1 # Write data to xlsx file row_number = 2 for index in range(len(indices)): query = "SELECT * FROM issues WHERE issue_id=?" issue_record = db.cur.execute(query, (indices[index],)).fetchone() for i, value in enumerate(issue_record[:stop]): if issue_record[18]: worksheet.set_row(row_number, 185) worksheet.set_column(17, 17, 35) worksheet.insert_image( row_number, 17, issue_record[18], {'x_scale': 0.3, 'y_scale': 0.3}) worksheet.write(row_number, i, value) row_number += 1 workbook.close() QMessageBox.information(self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export") @Slot() def funcIssuesToPdf(self): indices = self.funcIssuesCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp it was created on to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/IssuesPDF" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf", "PDF files (*.pdf)") if fileName: pdf = PDF() pdf.add_page() pdf.set_font('Arial', 'B', 13) for index in range(len(indices)): query = "SELECT * FROM issues WHERE issue_id=?" issue_record = db.cur.execute(query, (indices[index],)).fetchone() # This string allows for text formatting in the pdf, easy to implement and test stringIssue = "\nIssue id: " + str(issue_record[0]) + \ "\nIssue date: " + str(issue_record[1]) + \ "\nPriority: " + str(issue_record[2]) + \ "\nObserver: " + str(issue_record[3]) + \ "\nRevision team: " + str(issue_record[4]) + \ "\nInspection name: " + str(issue_record[5]) + \ "\nHSE theme: " + str(issue_record[6]) + \ "\nFacility: " + str(issue_record[7]) + \ "\nFacility supervisor: " + str(issue_record[8]) + \ "\nSpecific location: " + str(issue_record[9]) + \ "\nInspected department: " + str(issue_record[10]) + \ "\nInspected contractor: " + str(issue_record[11]) + \ "\nInspected subcontractor: " + str(issue_record[12]) + \ "\nDeadline: " + str(issue_record[13]) + \ "\nStatus: " + str(issue_record[14]) + \ "\nCreated on: " + str(issue_record[15]) + \ "\nClosed on: " + str(issue_record[16]) effectivePageWidth = pdf.w - 2 * pdf.l_margin ybefore = pdf.get_y() pdf.multi_cell(effectivePageWidth / 2, 10, stringIssue) if issue_record[18]: pdf.set_xy(effectivePageWidth / 2 + pdf.l_margin, ybefore) pdf.image(issue_record[18], effectivePageWidth / 2 + 20, 40, w=70) pdf.ln(0.5) # Page break is achieved by adding a new page # after all items except for the last one if index != (len(indices) - 1): pdf.add_page() pdf.output(fileName, 'F') QMessageBox.information(self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export")
class FacilityTab(QWidget): def __init__(self, parent): QWidget.__init__(self) self.Parent = parent self.FcltyTitle = 'FACILITIES' self.UI() @property def Title(self): return self.FcltyTitle def UI(self): self.widgets() self.layouts() self.funcDisplayFacilities() def widgets(self): # Facilities widgets ########################################################### # Top layout (search facilities) widgets self.searchFacilitiesText = QLabel("Search: ") self.searchFacilitesEntry = QLineEdit() self.searchFacilitesEntry.setPlaceholderText("Search facilities..") self.searchFacilitiesBtn = QPushButton("Search") self.searchFacilitiesBtn.clicked.connect(self.funcSearchFacilities) self.refreshFacilitiesBtn = QPushButton("Refresh") self.refreshFacilitiesBtn.clicked.connect(self.funcDisplayFacilities) # Middle layout (list people) widgets with radio buttons self.allFacilitiesRadioBtn = QRadioButton("All facilities") self.withOngoingIssuesFacilitiesRadioBtn = QRadioButton( "With pending issues") self.withLateIssuesRadioBtn = QRadioButton("With late issues") self.listFacilitiesBtn = QPushButton("List") # Bottom layout widget, a table showing people self.facilitiesTable = QTableWidget() self.facilitiesTable.verticalHeader().hide() self.facilitiesTable.setSortingEnabled(True) self.facilitiesTable.setShowGrid(False) self.facilitiesTable.verticalHeader().setDefaultSectionSize(40) self.facilitiesTable.setColumnCount(11) # self.peopleTable.setColumnHidden(0, True) self.facilitiesTable.setHorizontalHeaderItem(0, QTableWidgetItem("")) self.facilitiesTable.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.facilitiesTable.setHorizontalHeaderItem(1, QTableWidgetItem("ID")) self.facilitiesTable.setHorizontalHeaderItem(2, QTableWidgetItem("Name")) self.facilitiesTable.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.facilitiesTable.setHorizontalHeaderItem( 3, QTableWidgetItem("Location")) self.facilitiesTable.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.facilitiesTable.setHorizontalHeaderItem(4, QTableWidgetItem("Phone")) self.facilitiesTable.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.facilitiesTable.setHorizontalHeaderItem(5, QTableWidgetItem("Email")) self.facilitiesTable.horizontalHeader().setSectionResizeMode( 4, QHeaderView.Stretch) self.facilitiesTable.setHorizontalHeaderItem( 6, QTableWidgetItem("Supervisor")) self.facilitiesTable.setHorizontalHeaderItem( 7, QTableWidgetItem("Ongoing issues")) self.facilitiesTable.setHorizontalHeaderItem( 8, QTableWidgetItem("Late issues")) self.facilitiesTable.setHorizontalHeaderItem( 9, QTableWidgetItem("Total issues")) self.facilitiesTable.setHorizontalHeaderItem( 10, QTableWidgetItem("Total inspections")) # Double clicking a row opens a window with person details self.facilitiesTable.doubleClicked.connect(self.funcSelectedFacility) # Buttons for actions on selected facilities self.addFacility = QPushButton("Add") self.addFacility.clicked.connect(self.funcAddFacility) self.viewFacility = QPushButton("View/Edit") self.viewFacility.clicked.connect(self.funcSelectedFacility) self.deleteFacility = QPushButton("Delete") self.deleteFacility.clicked.connect(self.funcDeleteFacility) self.exportFacilitiesCSVBtn = QPushButton("Export CSV") self.exportFacilitiesCSVBtn.setEnabled(False) self.exportFacilitiesCSVBtn.clicked.connect(self.funcFacilitiesToCSV) self.exportFacilitiesXSLXBtn = QPushButton("Export XLSX") self.exportFacilitiesXSLXBtn.setEnabled(False) self.exportFacilitiesXSLXBtn.clicked.connect(self.funcFacilitiesToXLSX) self.exportFacilitiesPDFBtn = QPushButton("Export PDF") self.exportFacilitiesPDFBtn.setEnabled(False) self.exportFacilitiesPDFBtn.clicked.connect(self.funcFacilitiesToPdf) def layouts(self): # Facilities layouts ########################################################### self.facilitiesMainLayout = QVBoxLayout() self.facilitiesMainTopLayout = QHBoxLayout() self.facilitiesTopLeftLayout = QHBoxLayout() self.facilitiesTopRightLayout = QHBoxLayout() self.facilitiesMainBottomLayout = QHBoxLayout() self.facilitiesBottomRightLayout = QVBoxLayout() self.facilitiesBottomLeftLayout = QHBoxLayout() # Groupboxes allows customization using CSS-like syntax self.facilitiesTopLeftGroupBox = QGroupBox() self.facilitiesTopRightGroupBox = QGroupBox() self.facilitiesTopGroupBox = QGroupBox() self.facilitiesBottomGroupBox = QGroupBox() self.facilitiesBottomLeftGroupBox = QGroupBox() self.facilitiesBottomRightGroupBox = QGroupBox() self.facilitiesBottomRightGroupBox.setStyleSheet( 'QGroupBox {margin-top: 0px;}') self.facilitiesBottomRightGroupBoxFiller = QGroupBox() self.facilitiesBottomRightGroupBoxFiller.setStyleSheet( styles.groupBoxFillerStyle()) # Top layout (search box) widgets self.facilitiesTopLeftLayout.addWidget(self.searchFacilitiesText, 10) self.facilitiesTopLeftLayout.addWidget(self.searchFacilitesEntry, 30) self.facilitiesTopLeftLayout.addWidget(self.searchFacilitiesBtn, 10) self.facilitiesTopLeftLayout.addItem( QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.facilitiesTopLeftLayout.addWidget(self.refreshFacilitiesBtn, 10) self.facilitiesTopLeftGroupBox.setLayout(self.facilitiesTopLeftLayout) # layout (list box) widgets self.facilitiesTopRightLayout.addWidget(self.allFacilitiesRadioBtn) self.facilitiesTopRightLayout.addWidget( self.withOngoingIssuesFacilitiesRadioBtn) self.facilitiesTopRightLayout.addWidget(self.withLateIssuesRadioBtn) self.facilitiesTopRightLayout.addWidget(self.listFacilitiesBtn) self.facilitiesTopRightGroupBox.setLayout( self.facilitiesTopRightLayout) self.facilitiesMainTopLayout.addWidget(self.facilitiesTopLeftGroupBox, 60) self.facilitiesMainTopLayout.addWidget(self.facilitiesTopRightGroupBox, 40) # Bottom layout (table with facilities) widgets # Bottom left layout with table self.facilitiesBottomLeftLayout.addWidget(self.facilitiesTable) self.facilitiesBottomLeftGroupBox.setLayout( self.facilitiesBottomLeftLayout) # Bottom right layout with buttons self.facilitiesBottomRightLayout.addWidget(self.addFacility, 5) self.facilitiesBottomRightLayout.addWidget(self.viewFacility, 5) self.facilitiesBottomRightLayout.addWidget(self.deleteFacility, 5) self.facilitiesBottomRightLayout.addWidget( self.facilitiesBottomRightGroupBoxFiller, 70) self.facilitiesBottomRightLayout.addWidget(self.exportFacilitiesCSVBtn, 5) self.facilitiesBottomRightLayout.addWidget( self.exportFacilitiesXSLXBtn, 5) self.facilitiesBottomRightLayout.addWidget(self.exportFacilitiesPDFBtn, 5) self.facilitiesBottomRightGroupBox.setLayout( self.facilitiesBottomRightLayout) self.facilitiesMainBottomLayout.addWidget(self.facilitiesTable, 90) self.facilitiesMainBottomLayout.addWidget( self.facilitiesBottomRightGroupBox, 10) self.facilitiesMainLayout.addLayout(self.facilitiesMainTopLayout, 10) self.facilitiesMainLayout.addLayout(self.facilitiesMainBottomLayout, 90) self.setLayout(self.facilitiesMainLayout) @Slot() def funcAddFacility(self): self.newFacility = AddFacility(self) self.newFacility.setObjectName("add_facility_popup") self.newFacility.setStyleSheet(styles.addPopups()) @Slot() def funcDisplayFacilities(self): for i in reversed(range(self.facilitiesTable.rowCount())): self.facilitiesTable.removeRow(i) cur = db.cur facilities = cur.execute("SELECT * FROM facilities") for row_data in facilities: row_number = self.facilitiesTable.rowCount() self.facilitiesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) checkbox.stateChanged.connect(self.funcActivateBtnsWithCheckbox) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.facilitiesTable.setCellWidget(row_number, 0, qwidget) self.facilitiesTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.facilitiesTable.setItem( row_number, column_number, QTableWidgetItem("FCL#" + str(data))) else: self.facilitiesTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) self.facilitiesTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.facilitiesTable.setSelectionBehavior(QTableView.SelectRows) @Slot() def funcActivateBtnsWithCheckbox(self): indices = self.funcFacilitiesCheckBox() if self.sender().isChecked() or indices: self.exportFacilitiesCSVBtn.setEnabled(True) self.exportFacilitiesXSLXBtn.setEnabled(True) self.exportFacilitiesPDFBtn.setEnabled(True) else: self.exportFacilitiesCSVBtn.setEnabled(False) self.exportFacilitiesXSLXBtn.setEnabled(False) self.exportFacilitiesPDFBtn.setEnabled(False) @Slot() def funcFacilitiesCheckBox(self): checked_list = [] for i in range(self.facilitiesTable.rowCount()): if self.facilitiesTable.cellWidget(i, 0).findChild( type(QCheckBox())).isChecked(): item = self.facilitiesTable.item(i, 1).text() checked_list.append(item.lstrip("FCL#")) return checked_list @Slot() def funcSelectedFacility(self): self.displayFacility = DisplayFacility(self) self.displayFacility.show() @Slot() def funcDeleteFacility(self): indices = self.funcFacilitiesCheckBox() mbox = QMessageBox.question( self, "Warning", "Are you sure you want to delete this facility?", QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if (mbox == QMessageBox.Yes): if indices: try: for index in range(len(indices)): query = "DELETE FROM facilities WHERE facility_id = ?" db.cur.execute(query, (indices[index], )) db.conn.commit() QMessageBox.information(self, "Info", "Facilites were deleted") self.funcDisplayFacilities() except: QMessageBox.information(self, "Info", "No changes made") else: row = self.facilitiesTable.currentRow() facilityId = self.facilitiesTable.item(row, 0).text() facilityId = facilityId.lstrip("FCL#") try: query = "DELETE FROM facilities WHERE facility_id = ?" db.cur.execute(query, (facilityId, )) db.conn.commit() QMessageBox.information(self, "Info", "Facility was deleted") self.funcDisplayFacilities() except: QMessageBox.information(self, "Info", "No changes made") self.displayFacility.close() @Slot() def funcSearchFacilities(self): value = self.searchFacilitesEntry.text() if value == "": QMessageBox.information(self, "Warning", "Search string cannot be empty") self.displayFacilities() else: # Erase search entry self.searchFacilitesEntry.setText("") try: query = "SELECT * FROM facilities WHERE " \ "facility_id LIKE ? " \ "OR facility_name LIKE ?" \ "OR facility_location LIKE ?" \ "OR facility_phone LIKE ?" \ "OR facility_email LIKE ?" \ "OR facility_supervisor LIKE ?" results = db.cur.execute( query, ('%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%')).fetchall() if results == []: QMessageBox.information(self, "Info", "Nothing was found") self.funcDisplayFacilities() else: for i in reversed(range(self.facilitiesTable.rowCount())): self.facilitiesTable.removeRow(i) for row_data in results: row_number = self.facilitiesTable.rowCount() self.facilitiesTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.facilitiesTable.setCellWidget( row_number, 0, qwidget) self.facilitiesTable.setItem( row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=1): if column_number == 1: self.facilitiesTable.setItem( row_number, column_number, QTableWidgetItem("FCL#" + str(data))) else: self.facilitiesTable.setItem( row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") @Slot() def funcFacilitiesToCSV(self): indices = self.funcFacilitiesCheckBox() if indices: CSV(self, "facilities", indices) else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" ) @Slot() def funcFacilitiesToXLSX(self): indices = self.funcFacilitiesCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp to when it was created to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/FacilitiesXLSX" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx", "Excel files (*.xlsx)") if fileName: db.cur.execute("SELECT * FROM facilities") workbook = xlsxwriter.Workbook(fileName) worksheet = workbook.add_worksheet("Facilities") worksheet.set_column('A:C', 12) worksheet.set_row(0, 30) merge_format = workbook.add_format({ 'bold': 1, 'align': 'center', 'valign': 'vcenter' }) worksheet.merge_range('A1:B1', '', merge_format) worksheet.insert_image( 'A1', './assets/logo/logo-full-main.png', { 'x_scale': 0.4, 'y_scale': 0.4, 'x_offset': 15, 'y_offset': 10 }) # Create header row col = 0 for value in db.cur.description: worksheet.write(1, col, value[0]) col += 1 # Write date to xlsx file row_number = 2 for index in range(len(indices)): query = "SELECT * FROM facilities WHERE facility_id=?" facility_record = db.cur.execute( query, (indices[index], )).fetchone() for i, value in enumerate(facility_record): worksheet.write(row_number, i, value) row_number += 1 workbook.close() QMessageBox.information( self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" ) @Slot() def funcFacilitiesToPdf(self): indices = self.funcFacilitiesCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp to when it was created to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/FacilitiesPDF" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf", "PDF files (*.pdf)") if fileName: pdf = PDF() pdf.add_page() pdf.set_font('Arial', 'B', 13) for index in range(len(indices)): query = "SELECT * FROM facilities WHERE facility_id=?" facility_record = db.cur.execute( query, (indices[index], )).fetchone() # This string allows for text formatting in the pdf, easy to implement and test stringFacility = "\nFacility id: " + str(facility_record[0]) + \ "\nFacility name: " + str(facility_record[1]) + \ "\nLocation: " + str(facility_record[2]) + \ "\nPhone: " + str(facility_record[3]) + \ "\nEmail: " + str(facility_record[4]) + \ "\nSupervisor: " + str(facility_record[5]) pdf.multi_cell(200, 10, stringFacility) pdf.output(fileName, 'F') QMessageBox.information( self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" )
class Scanner(): signals = signal.signalClass() preview = None ## @param preview contains the preview image capture = None ## @param capture contains the captured image DisplayTarget = None DisplayWell = None positioner_msg = str batchrun_msg = str ## @brief Scanner::__init__() initialises the variables and instances def __init__(self, parent=None): ## @param PixImage is the label on the MainWindow where the videostream is displayed self.PixImage = QLabel() return ## @brief MainWindow::createVideoGroupBox(self) creates the groupbox and the widgets in it which are used for displaying vido widgets. ## @return self.videoGroupBox. This the groupbox containing the snapshot visualisation widgets. def createVideoWindow(self): self.videoGridLayout = QGridLayout() self.videoGroupBox = QGroupBox() self.videoGroupBox.setStyleSheet("color: #000000;") ## label of QGroupbox content self.gb_label = QLabel("Video stream") self.gb_label.setStyleSheet( 'QLabel {color: #ffffff; font-weight: bold}') self.gb_label.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.videoGridLayout.addWidget(self.gb_label, 0, 0, 1, 1, Qt.AlignHCenter) ## PixImage is a QLabel widget used to display the snapshots self.videoGridLayout.addWidget(self.PixImage, 1, 0) self.videoGroupBox.setLayout(self.videoGridLayout) return self.videoGroupBox ## @brief Scanner()::msg(self, message) emits the message signal. This emit will be catched by the logging slot function in main.py. ## @param message is the string message to be emitted. def msg(self, message): if message is not None: self.signals.mes.emit(self.__class__.__name__ + ": " + str(message)) return ## @brief Scanner::reader(self) takes snapshots @Slot() def reader(self): if not (self.capture is None): if not os.path.exists("snapshots"): self.msg("Generating snapshots directory") os.mkdir("snapshots") filename = 'snapshots/Reader_Snapshot' + str( current_milli_time()) + '.png' self.msg("Generated snapshot: " + str(filename)) cv2.imwrite(filename, self.capture) return ## @brief Scanner::snapshotRequestedPositioner(self, message) sets the positioner message and connects the preview signal to Scanner::snapshotPositioner ## @param message is the positioner message @Slot(str) def snapshotRequestedPositioner(self, message): ## Set the info emitted by the calibrator self.positioner_msg = str(message) ## Connect the capture ready signal to trigger the creation of a new frame. self.signals.previewUpdated.connect(self.snapshotPositioner) ## @brief Scanner::snapshotPositioner(self) signals the positioner ready signal if an capture image is stored. @Slot() def snapshotPositioner(self): if not (self.capture is None): ## Disconnect the capture ready signal to only create snapshots when they are requested. self.signals.previewUpdated.disconnect(self.snapshotPositioner) self.signals.signal_rdy_positioner.emit(self.preview) ## @brief Scanner::snapshotRequestedBatchRun(self, message) sets the image part of the batch filename and connects the capture (high resolution capture image ready) signal to Scanner::snapshotBatchRun ## @param message is the snapshot unique name which will be part of the imagefilename @Slot(str) def snapshotRequestedBatchRun(self, message): ## Set the info emitted by the calibrator. self.batchrun_msg = str(message) ## Connect the capture ready signal to trigger the creation of a new frame. self.signals.captureUpdated.connect(self.snapshotBatchRun) ## @brief Scanner::snapshotBatchRun(self) writes the capture image to the desired directory (creates directory if not existing). @Slot() def snapshotBatchRun(self): if not (self.capture is None): self.signals.captureUpdated.disconnect(self.snapshotBatchRun) file_path = str( mwi.settings_batch.value("Run/path")) + '/' + self.batchrun_msg if not os.path.exists(file_path): os.makedirs(file_path) filename = file_path + '/Snapshot_' + str( current_milli_time()) + '.png' self.msg(str(filename)) print(filename) cv2.imwrite(filename, self.capture) self.signals.signal_rdy_batchrun.emit() ## @brief Scanner::prvUpdate(self, image=None) updates the preview image on the QLabel widget of the MainWindow ## @param image is the new image to show @Slot(np.ndarray) def prvUpdate(self, image=None): if not (image is None): self.preview = image if len(image.shape) < 3: image = cv2.cvtColor( image, cv2.COLOR_GRAY2RGB) ## convert to color image if self.DisplayTarget is not None: cv2.circle(image, (self.DisplayTarget[0], self.DisplayTarget[1]), self.DisplayTarget[2], (0, 255, 0), 1) if self.DisplayWell is not None: cv2.circle(image, (self.DisplayWell[0], self.DisplayWell[1]), self.DisplayWell[2], (255, 0, 0), 1) height, width = image.shape[:2] ## get dimensions ## @note Creating QImage without ctypes causes memory leaks. This is a PySide bug ch = ctypes.c_char.from_buffer(image.data, 0) rcount = ctypes.c_long.from_address(id(ch)).value qImage = QImage( ch, width, height, width * 3, QImage.Format_RGB888) ## Convert from OpenCV to PixMap ctypes.c_long.from_address(id(ch)).value = rcount ## Update the preview self.PixImage.setPixmap(QPixmap(qImage)) self.PixImage.show() self.signals.previewUpdated.emit() ## @brief Scanner::capUpdate(self, image=None) updates the image when a new one is available and emits a captureUpdated signal. ## @param image is the new captured image. @Slot(np.ndarray) def capUpdate(self, image=None): if not (image is None): self.capture = image self.signals.captureUpdated.emit() ## @brief Scanner::set_displaytarget(self, target_information) updates the current by opencv detected light source ## @param target_information is the information of the detected object @Slot(tuple) def set_displaytarget(self, target_information): self.DisplayTarget = target_information return ## @brief Scanner::set_displaywell(self, target_information) updates the current by opencv detected well ## @param target_information is the information of the detected object @Slot(tuple) def set_displaywell(self, target_information): self.DisplayWell = target_information return
import sys from PySide2.QtWidgets import QApplication, QMainWindow, QGroupBox, QRadioButton aplicacao = QApplication(sys.argv) janela = QMainWindow() # setGeometry(esquerda, topo, largura, altura) janela.setGeometry(100, 50, 300, 200) janela.setWindowTitle("Primeira Janela") # cria uma instancia de um grupo de seleção dentro da janela group_box = QGroupBox("Selecione uma opção", janela) group_box.move(50, 50) group_box.resize(200, 100) group_box.setStyleSheet('QGroupBox \ {background-color: yellow}') # cria os radio buttons dentro do grupo de seleção radio_btn_1 = QRadioButton("Opção 1", group_box) radio_btn_1.move(10, 20) radio_btn_2 = QRadioButton("Opção 2", group_box) radio_btn_2.move(10, 40) radio_btn_3 = QRadioButton("Opção 3", group_box) radio_btn_3.move(10, 60) radio_btn_3.setChecked(True) janela.show() aplicacao.exec_() sys.exit()
class MyDockWidget(cutter.CutterDockWidget): def __init__(self, parent, action): super(MyDockWidget, self).__init__(parent, action) self.setObjectName("Capa explorer") self.setWindowTitle("Capa explorer") self._config = CutterBindings.Configuration.instance() self.model_data = CapaExplorerDataModel() self.range_model_proxy = CapaExplorerRangeProxyModel() self.range_model_proxy.setSourceModel(self.model_data) self.search_model_proxy = CapaExplorerSearchProxyModel() self.search_model_proxy.setSourceModel(self.range_model_proxy) self.create_view_tabs() self.create_tree_tab_ui() self.create_view_attack() self.connect_signals() self.setWidget(self.tabs) self.show() def create_view_tabs(self): # Create tabs container self.tabs = QTabWidget() # Create the tabs self.tab_attack = QWidget(self.tabs) self.tab_tree_w_model = QWidget(self.tabs) self.tabs.addTab(self.tab_tree_w_model, "Tree View") self.tabs.addTab(self.tab_attack, "MITRE") # Add load button self.btn_load_capa_results = QPushButton() self.btn_load_capa_results.setText("Load capa JSON") self.btn_load_capa_results.setStyleSheet( "margin-bottom: 2px;margin-right:2px") self.btn_load_capa_results.clicked.connect(self.load_file) self.tabs.setCornerWidget(self.btn_load_capa_results) def create_tree_tab_ui(self): self.capa_tree_view_layout = QVBoxLayout() self.capa_tree_view_layout.setAlignment(Qt.AlignTop) self.chk_fcn_scope = QCheckBox("Limit to Current function") #TODO: reset state on load file self.chk_fcn_scope.setChecked(False) self.chk_fcn_scope.stateChanged.connect( self.slot_checkbox_limit_by_changed) self.input_search = QLineEdit() self.input_search.setStyleSheet("margin:0px; padding:0px;") self.input_search.setPlaceholderText("search...") self.input_search.textChanged.connect( self.slot_limit_results_to_search) self.filter_controls_container = QGroupBox() self.filter_controls_container.setObjectName("scope") self.filter_controls_container.setFlat(True) self.filter_controls_container.setStyleSheet( "#scope{border:0px; padding:0px; margin:0px;subcontrol-origin: padding; subcontrol-position: left top;}" ) self.filter_controls_layout = QHBoxLayout( self.filter_controls_container) self.filter_controls_layout.setContentsMargins(0, 0, 0, 0) self.filter_controls_layout.addWidget(self.input_search) self.filter_controls_layout.addWidget(self.chk_fcn_scope) self.view_tree = CapaExplorerQtreeView(self.search_model_proxy) self.view_tree.setModel(self.search_model_proxy) # Make it look a little nicer when no results are loaded self.view_tree.header().setStretchLastSection(True) self.capa_tree_view_layout.addWidget(self.filter_controls_container) self.capa_tree_view_layout.addWidget(self.view_tree) self.tab_tree_w_model.setLayout(self.capa_tree_view_layout) def create_view_attack(self): table_headers = [ "ATT&CK Tactic", "ATT&CK Technique ", ] table = QTableWidget() table.setColumnCount(len(table_headers)) table.verticalHeader().setVisible(False) table.setSortingEnabled(False) table.setEditTriggers(QAbstractItemView.NoEditTriggers) table.setFocusPolicy(Qt.NoFocus) table.setSelectionMode(QAbstractItemView.NoSelection) table.setHorizontalHeaderLabels(table_headers) table.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) table.horizontalHeader().setStretchLastSection(True) table.setShowGrid(False) table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) #table.setStyleSheet("QTableWidget::item { padding: 25px; }") attack_view_layout = QVBoxLayout() attack_view_layout.setAlignment(Qt.AlignTop) self.attack_table = table attack_view_layout.addWidget(self.attack_table) self.tab_attack.setLayout(attack_view_layout) return table def connect_signals(self): QObject.connect(cutter.core(), SIGNAL("functionRenamed(RVA, QString)"), self.model_data.refresh_function_names) QObject.connect(cutter.core(), SIGNAL("functionsChanged()"), self.model_data.refresh_function_names) QObject.connect(cutter.core(), SIGNAL("seekChanged(RVA)"), self.signal_shim_slot_checkbox_limit_by_changed) def render_new_table_header_item(self, text): """create new table header item with our style @param text: header text to display """ item = QTableWidgetItem(text) item.setForeground(self._config.getColor("graph.true")) font = QFont() font.setBold(True) item.setFont(font) return item def fill_attack_table(self, rules): tactics = collections.defaultdict(set) for key, rule in rules.items(): if not rule["meta"].get("att&ck"): continue for attack in rule["meta"]["att&ck"]: tactic, _, rest = attack.partition("::") if "::" in rest: technique, _, rest = rest.partition("::") subtechnique, _, id = rest.rpartition(" ") tactics[tactic].add((technique, subtechnique, id)) else: technique, _, id = rest.rpartition(" ") tactics[tactic].add((technique, id)) column_one = [] column_two = [] for (tactic, techniques) in sorted(tactics.items()): column_one.append(tactic.upper()) # add extra space when more than one technique column_one.extend(["" for i in range(len(techniques) - 1)]) for spec in sorted(techniques): if len(spec) == 2: technique, id = spec column_two.append("%s %s" % (technique, id)) elif len(spec) == 3: technique, subtechnique, id = spec column_two.append("%s::%s %s" % (technique, subtechnique, id)) else: raise RuntimeError("unexpected ATT&CK spec format") self.attack_table.setRowCount(max(len(column_one), len(column_two))) for (row, value) in enumerate(column_one): self.attack_table.setItem(row, 0, self.render_new_table_header_item(value)) for (row, value) in enumerate(column_two): self.attack_table.setItem(row, 1, QTableWidgetItem(value)) def slot_limit_results_to_search(self, text): """limit tree view results to search matches reset view after filter to maintain level 1 expansion """ self.search_model_proxy.set_query(text) self.view_tree.reset_ui(should_sort=False) def signal_shim_slot_checkbox_limit_by_changed(self): if self.chk_fcn_scope.isChecked(): self.slot_checkbox_limit_by_changed(Qt.Checked) def slot_checkbox_limit_by_changed(self, state): """slot activated if checkbox clicked if checked, configure function filter if screen location is located in function, otherwise clear filter @param state: checked state """ invoke_reset = True if state == Qt.Checked: minbound, maxbound = util.get_function_boundries_at_current_location( ) if self.range_model_proxy.min_ea == minbound and self.range_model_proxy.max_ea == maxbound: # Seek only changed within current function, avoid resetting tree invoke_reset = False self.limit_results_to_function((minbound, maxbound)) else: self.range_model_proxy.reset_address_range_filter() if invoke_reset: self.view_tree.reset_ui() def limit_results_to_function(self, f): """add filter to limit results to current function adds new address range filter to include function bounds, allowing basic blocks matched within a function to be included in the results @param f: (tuple (maxbound, minbound)) """ if f: self.range_model_proxy.add_address_range_filter(f[0], f[1]) else: # if function not exists don't display any results (assume address never -1) self.range_model_proxy.add_address_range_filter(-1, -1) def log(self, msg): """log to cutter console @param msg: message to log """ cutter.message(f"[CAPAExplorer]: {msg}") def load_file(self): # Disable load button during loading self.btn_load_capa_results.setEnabled(False) filename = QFileDialog.getOpenFileName() path = filename[0] if len(path): try: data = util.load_capa_json(path) self.fill_attack_table(data['rules']) self.model_data.clear() self.model_data.render_capa_doc(data) # Restore ability to scroll on last column self.view_tree.header().setStretchLastSection(False) self.view_tree.slot_resize_columns_to_content() except Exception as e: util.log('Could not load json file.') else: util.log('No file selected.') self.btn_load_capa_results.setEnabled(True)
def box_gen(self, x, y, resource=''): group_box = QGroupBox(self.window) group_box.move(x, y) group_box.resize(self.box_width, self.box_height) if resource == '': return [] group_box.setTitle('') group_box.setStyleSheet('QGroupBox { background-color: \ rgb(255, 255, 255); border: 3px solid rgb(122, 255, 100); } \ QGroupBox::title{font: 75 ' + str(100 * self.screen_ratio) + 'pt "宋体"; color: rgb(255, 0, 0)}') label_again = QLabel(group_box) label_again.setStyleSheet('QLabel {font: 75 ' + str(self.font_size) + 'pt "宋体"; color: rgb(255, 0, 0)}') label_again.setText(resource) label_again.move(int(self.grid_width * 0.7), 5 * self.screen_ratio) label_again.resize(int(self.grid_width * 3.3), self.init_bias - 5) product_label00 = QLabel(group_box) product_label00.setText('产量') product_label00.move(3, self.init_bias) product_label00.resize(self.grid_width, self.grid_height) product_label00.setStyleSheet('QLabel {font: 75 ' + str(self.font_size) + 'pt "宋体"}') product00 = QLineEdit(group_box) product00.setText('0') product00.move(self.grid_width, self.init_bias) product00.resize(self.grid_width, self.grid_height) product00.setEnabled(False) product00.setStyleSheet('QLineEdit {font: ' + str(self.line_edit_font_size) + 'pt "宋体"}') product_label10 = QLabel(group_box) product_label10.setText('额外') product_label10.move(3, self.grid_height + self.init_bias) product_label10.resize(self.grid_width, self.grid_height) product_label10.setStyleSheet('QLabel {font: 75 ' + str(self.font_size) + 'pt "宋体"}') product10 = QLineEdit(group_box) product10.setText('0') product10.move(self.grid_width, self.grid_height + self.init_bias) product10.resize(self.grid_width, self.grid_height) product10.setStyleSheet('QLineEdit {font: ' + str(self.line_edit_font_size) + 'pt "宋体"}') product_label01 = QLabel(group_box) product_label01.setText('机器') product_label01.move(self.grid_width * 2 + self.interval, self.init_bias) product_label01.resize(self.grid_width, self.grid_height) product_label01.setStyleSheet('QLabel {font: 75 ' + str(self.font_size) + 'pt "宋体"}') product01 = QLineEdit(group_box) product01.setText('0.0') product01.move(self.grid_width * 3 + self.interval, self.init_bias) product01.resize(self.grid_width, self.grid_height) product01.setStyleSheet('QLineEdit {font: ' + str(self.line_edit_font_size) + 'pt "宋体"}') product01.setEnabled(False) product_label11 = QLabel(group_box) product_label11.setText('已有') product_label11.move(self.grid_width * 2 + self.interval, self.grid_height + self.init_bias) product_label11.resize(self.grid_width, self.grid_height) product_label11.setStyleSheet('QLabel {font: 75 ' + str(self.font_size) + 'pt "宋体"}') product11 = QLineEdit(group_box) product11.setText('0') product11.move(self.grid_width * 3 + self.interval, self.grid_height + self.init_bias) product11.resize(self.grid_width, self.grid_height) product11.setStyleSheet('QLineEdit {font: ' + str(self.line_edit_font_size) + 'pt "宋体"}') if resource in self.supporter: product11.setEnabled(True) else: product11.setEnabled(False) return [product00, product01, product10, product11]
class Main(QWidget): def __init__(self): super().__init__() self.user_entry = QLineEdit("user5301") # self.user_entry.setStyleSheet("font: corbel; font-size: 12px;") self.pass_entry = QLineEdit("e", self) self.odbc = "" self.bars = "" self.table_query = "" self.pass_entry.setEchoMode(QLineEdit.PasswordEchoOnEdit) self.ru_entry = QLineEdit("328845", self) # self.ru_entry.setStyleSheet("font: corbel; font-size: 12px;") self.cur_entry = QLineEdit("840") # self.cur_entry.setStyleSheet("font: corbel; font-size: 12px;") self.balance_entry = QLineEdit("213000001") # self.balance_entry.setStyleSheet("font: corbel; font-size: 12px;") self.ok_button = QPushButton("Запустить") self.ok_button.setStyleSheet( "font: corbel; font-size: 12px; color: rgb(0, 0, 255)") # self.ok_button.setStyleSheet("color: rgb(160, 70, 70)") self.error_label = QLabel("Ошибки будут тут") self.error_label.setStyleSheet("color: rgb(255, 0, 0)") self.start_button1 = QPushButton("Старт") self.stop_button1 = QPushButton("Стоп") self.start_button1.setEnabled(True) self.stop_button1.setEnabled(False) self.start_button1.setStyleSheet("background-color: rgb(81,142,144)") self.interval_l = QLabel("Интервал") # self.interval_l.setStyleSheet("font: corbel; font-size: 12px; color: rgb(0, 0, 255)") self.interval_e = QLineEdit() self.timer_id = 0 self.table = QTableView() # Create model self.sqm = QSqlQueryModel(parent=self.table) self.init_ui() def on_start(self): password = self.pass_entry.text() if password == "e": self.print_and_label("Вы не ввели пароль!") else: self.timer_id = self.startTimer(int(self.interval_e.text())) self.start_button1.setEnabled(False) self.stop_button1.setEnabled(True) def on_stop(self): print("Таймер остановлен.", self.timer_id) if self.timer_id: self.killTimer(self.timer_id) self.timer_id = 0 self.start_button1.setEnabled(True) self.stop_button1.setEnabled(False) def print_and_label(self, text): print(text) self.error_label.setText(text) def run(self): ## print(getpass.getuser(), self.user_entry.text()) e = WorkWithOCI( "XE", self.user_entry.text(), keyring.get_password(getpass.getuser(), self.user_entry.text())) #print("Name of database:", e.name) # print("Host :", e.host) conn = e.open_db() if conn: self.error_label.setText("Ошибок уже/пока нет") query = QSqlQuery() query2 = QSqlQuery() # Доступность if query.exec_(self.bars): #print("Q1 done!") query.finish() # Create model self.sqm = QSqlQueryModel(parent=self.table) # Сам запрос self.sqm.setQuery( self.table_query.format(self.ru_entry.text().strip(), self.cur_entry.text().strip(), self.balance_entry.text().strip())) if query2.exec_( self.table_query.format( self.ru_entry.text().strip(), self.cur_entry.text().strip(), int(self.balance_entry.text().strip()))): #print("Q2 done!") self.sqm.setQuery(query2) else: self.print_and_label("Ошибка 2-го запроса") print( "2-й запрос (", self.table_query.format( self.ru_entry.text().strip(), self.cur_entry.text().strip(), int(self.balance_entry.text().strip())), ") :", query.lastError().text()) # Задаем заголовки для столбцов модели self.sqm.setHeaderData(0, Qt.Horizontal, "Счет") self.sqm.setHeaderData(1, Qt.Horizontal, "РУ") self.sqm.setHeaderData(2, Qt.Horizontal, "Валюта") self.sqm.setHeaderData(3, Qt.Horizontal, "Остаток") # self.print_and_label(sqm.lastError().text()) # Задаем для таблицы только что созданную модель self.table.setModel(self.sqm) # Not)Скрываем первый столбец, в котором выводится идентификатор # self.table.hideColumn(0) self.table.setColumnWidth(0, 150) self.table.setColumnWidth(1, 60) self.table.setColumnWidth(2, 80) self.table.setColumnWidth(3, 150) # print("sqm.rowCount()", self.sqm.rowCount()) if self.sqm.rowCount() > 0: frequency = 2500 duration = 2000 winsound.Beep(frequency, duration) conn.close() #conn.removeDatabase('qt_sql_default_connection') else: self.print_and_label("Ошибка первого запроса (", self.bars, ") :", query.lastError().text()) else: self.print_and_label("Ошибка открытия базы данных") def timerEvent(self, event): # self.error_label.setText("Сработал таймер" + str(event.timerId())) print("Сработал таймер", str(event.timerId())) self.run() def init_ui(self): file_name = 'ini_balance' with open(file_name) as f: lines = f.readlines() try: self.interval_e.setText(lines[0]) except: self.error_label.setText( ' Возможно в первой строке файла ini_balance нет времени таймера!' ) try: self.bars = lines[1] except: self.error_label.setText( ' Возможно во второй строке файла ini_balance нет запроса!' ) try: self.table_query = lines[2] except: self.error_label.setText( ' Возможно в третьей строке файла ini_balance нет запроса!' ) label = QLabel(self) label.setAlignment(Qt.AlignRight) label.resize(30, 30) image = QPixmap("b.jfif", format="JPG").scaled(label.width(), label.height()) #image = QPixmap("mon.png", format="PNG") label.setPixmap(image) self.group = QGroupBox("Таймер остатка") self.group.setStyleSheet("font: corbel; font-size: 14px;") v_group = QVBoxLayout() # Контейнер для группы v_group.addWidget(self.start_button1) v_group.addWidget(self.stop_button1) v_group.addWidget(self.interval_l) v_group.addWidget(self.interval_e) self.group.setLayout(v_group) form = QFormLayout() form.addRow("", label) form.addRow("По&льзователь", self.user_entry) form.addRow("&Пароль", self.pass_entry) form.addRow("&МФО области", self.ru_entry) form.addRow("&Валюта", self.cur_entry) form.addRow("&Необходимый остаток", self.balance_entry) form.addRow("", self.ok_button) form.addRow("", self.group) form.addRow("&Результат", self.table) form.addRow("&Ошибки", self.error_label) self.setLayout(form) # k10 - work with password # is_right in - hash, return - T/F; set_p in - pass return - hash hash_pass = hashlib.md5(self.pass_entry.text().encode('utf-8')) # print("hash", hash_pass) # keyring.set_password(getpass.getuser(), self.user_entry.text(), self.pass_entry.text()) self.pass_entry.editingFinished.connect( lambda: k10.keyring_pass(getpass.getuser(), self.user_entry.text( ), self.pass_entry, hash_pass, self.ru_entry)) self.ok_button.clicked.connect(lambda: self.run()) self.start_button1.clicked.connect(self.on_start) self.stop_button1.clicked.connect(self.on_stop) self.setGeometry(300, 100, 650, 550) self.setWindowTitle('Ждем деньги') self.show()
class Window(QWidget): def __init__(self): super().__init__() # ----------style------------- self.font_type = "Arial" self.font_size = 10 self.font_color = "#676767" self.font_size2 = 12 self.font_color_black = "#f0f0f0" #--------------------------------- self.text8 = QTextEdit() self.text8.setReadOnly(True) self.check_text = False self.gbox6 = QGroupBox() try: f = open("plotter.txt", "x+") except: f = open("plotter.txt", "r") self.s = f.readline() f.close if self.s == "": f = open("plotter.txt", "w") f.write("dark") f.close() self.s = "dark" self.information_dialog() else: self.gbox6.setStyleSheet( "border:None;background-color:rgba(255,255,255,0)") self.text8.setStyleSheet( "border:None;background-color:rgba(255,255,255,0)") self.gbox6.setTitle("") self.text8.setText("") np.seterr(invalid='raise') self.setWindowTitle("XGrapher") self.setGeometry(500, 400, 900, 600) self.setMinimumSize(900, 600) pg.setConfigOption('background', (255, 255, 255, 0)) self.pw = pg.PlotWidget() self.pw.setXRange(0, 1) self.pw.setYRange(0, 1) self.pw.hideButtons() #--------------------------- self.list_errors = [] # -------------------------- self.a = False self.b = False self.c = False # ------------------------- self.d = False self.e = False self.f = False self.g = False self.after = False # ------------------------- self.check1 = False self.check2 = False self.check3 = False self.check_dot = False self.check_neg = False self.check_xrange = False self.check_yrange = False # ------------Labels----------------------------------------- self.label1 = QLabel() self.label1.setText("F(x):") self.label2 = QLabel() self.label2.setText("Min(x):") self.label3 = QLabel() self.label3.setText("Max(x):") self.label4 = QLabel() self.label5 = QLabel() self.label5.setText("< x <") self.label6 = QLabel() self.label6.setText("< y <") # --------------------------texteditors------------------ self.text1 = QLineEdit(self) self.text1.textChanged.connect(self.text1_response) self.text1.returnPressed.connect(self.focus_text1) self.text2 = QLineEdit(self) self.text2.textChanged.connect(self.text2_response) self.text2.returnPressed.connect(self.focus_text2) self.text3 = QLineEdit(self) self.text3.textChanged.connect(self.text3_response) self.text3.returnPressed.connect(self.focus_text3) self.text4 = QLineEdit() self.text4.textChanged.connect(self.text4_response) self.text4.returnPressed.connect(self.focus_text4) self.text5 = QLineEdit() self.text5.textChanged.connect(self.text5_response) self.text5.returnPressed.connect(self.focus_text5) self.text6 = QLineEdit() self.text6.textChanged.connect(self.text6_response) self.text6.returnPressed.connect(self.focus_text6) self.text7 = QLineEdit() self.text7.textChanged.connect(self.text7_response) self.text7.returnPressed.connect(self.focus_text7) # -------------------------------------------------------- self.button_2 = QPushButton() self.button_2.clicked.connect(self.auto_mode) self.button_save = QPushButton("Export Graph") self.button_help = QPushButton() self.button_help.clicked.connect(self.information_dialog) # ----------------------RadioButtons---------------------- self.rbutton1 = QRadioButton("Light") self.rbutton1.toggled.connect(self.light_mode) self.rbutton2 = QRadioButton("Dark") self.rbutton2.toggled.connect(self.dark_mode) # -------------------------------------------------------- self.setIcon() self.center() self.input_box() self.plot_box() self.vbox = QHBoxLayout() self.vbox.addWidget(self.gbox5) self.vbox.addSpacing(5) self.vbox.addWidget(self.plot) # self.setStyleSheet("background-color:rgb(32,32,32);") # self.setStyleSheet("background-color:rgb(240,240,240);") self.setLayout(self.vbox) if self.s == "dark": self.rbutton2.setChecked(True) else: self.rbutton1.setChecked(True) if self.s == "dark": self.dark_mode() else: self.light_mode() self.show() # --------------------------------------evalute------------------------------------------------------------------- self.replacements = { 'sin': 'np.sin', 'cos': 'np.cos', 'tan': 'np.tan', 'arccos': 'np.arccos', 'arcsin': 'np.arcsin', 'arctan': 'np.arctan', 'exp': 'np.exp', 'sqrt': 'np.sqrt', 'cbrt': 'np.cbrt', 'ln': 'np.log', "cosh": "np.cosh", "sinh": "np.cosh", "tanh": "np.cosh" } self.allowed_words = [ "x", "sin", "cos", "tan", "arccos", "arcsin", "arctan", "cosh", "sinh", "tanh", "exp", "sqrt", "cbrt", "log10", "ln" ] # ---------------------------------------------------------------------------------------------------------------- self.after = True def setIcon(self): appIcon = QIcon("close.ico") self.setWindowIcon(appIcon) def center(self): qRect = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qRect.moveCenter(centerPoint) self.move(qRect.topLeft()) def input_box(self): self.input = QGroupBox("Function") self.gbox = QGroupBox("Range") vbox_parent = QVBoxLayout() self.hbox_parent = QVBoxLayout() hbox1 = QHBoxLayout() hbox2 = QHBoxLayout() hbox3 = QHBoxLayout() hbox1.addWidget(self.label1) hbox1.addSpacing(17) hbox1.addWidget(self.text1) hbox2.addWidget(self.label2) hbox2.addSpacing(4) hbox2.addWidget(self.text2) hbox3.addWidget(self.label3) hbox3.addSpacing(0) hbox3.addWidget(self.text3) hbox_button = QHBoxLayout() hbox_button.addStretch(1) self.button = QPushButton("Reset") self.button.setFixedSize(70, 25) self.button.clicked.connect(self.reset) hbox_button.addWidget(self.button) vbox_parent.addLayout(hbox1) vbox_parent.addLayout(hbox2) vbox_parent.addLayout(hbox3) vbox_parent.addLayout(hbox_button) self.input.setLayout(vbox_parent) hbox4 = QHBoxLayout() hbox4.addWidget(self.text4) hbox4.addWidget(self.label5) hbox4.addWidget(self.text5) hbox5 = QHBoxLayout() hbox5.addWidget(self.text6) hbox5.addWidget(self.label6) hbox5.addWidget(self.text7) vbox3 = QVBoxLayout() vbox3.addWidget(self.button_2) vbox2 = QVBoxLayout() vbox2.addLayout(hbox4) vbox2.addLayout(hbox5) hbox6 = QHBoxLayout() hbox6.addLayout(vbox2) hbox6.addLayout(vbox3) self.gbox.setLayout(hbox6) #self.button_save.setFixedSize(200, 25) self.button_save.setFixedHeight(25) self.button_save.setFixedWidth(220) self.button_save.clicked.connect(self.export) hbox7 = QHBoxLayout() hbox7.addWidget(self.button_save) hbox7.addWidget(self.button_help) self.gbox3 = QGroupBox() self.gbox3.setFlat(True) self.gbox3.setStyleSheet("border: None") #self.gbox3.setLayout(hbox7) vbox3 = QVBoxLayout() vbox3.addWidget(self.gbox) self.gbox4 = QGroupBox("Status") hbox8 = QHBoxLayout() hbox8.addWidget(self.label4) self.gbox4.setLayout(hbox8) self.gbox_mode = QGroupBox("Style") vbox4 = QHBoxLayout() vbox4.addWidget(self.rbutton1) vbox4.addWidget(self.rbutton2) self.gbox_mode.setLayout(vbox4) hbox9 = QHBoxLayout() hbox9.addWidget(self.text8) self.gbox6.setLayout(hbox9) self.hbox_parent.addWidget(self.input) self.hbox_parent.addLayout(vbox3) self.hbox_parent.addLayout(hbox7) self.hbox_parent.addWidget(self.gbox6) self.hbox_parent.addWidget(self.gbox_mode) self.hbox_parent.addWidget(self.gbox4) self.gbox5 = QGroupBox() self.gbox5.setLayout(self.hbox_parent) def plot_box(self): self.plot = QGroupBox() layout = QVBoxLayout() self.pw.showGrid(True, True, 0.5) layout.addWidget(self.pw) self.plot.setLayout(layout) def text_restricted(self, str): if str != "": word = str[len(str) - 1] if re.match('[0-9-.]', word) is None: k = str.translate({ord(word): None}) str = k if word == "-" and len(str) > 1: k = str[1:].translate({ord(word): None}) str = str.replace(str[1:], k) if word == ".": i = 0 for v in str: if v == ".": i += 1 if i > 1: str = str[0:len(str) - 1] + "" if word == ".": self.check_dot = True else: str = "" return str def text1_response(self): if self.check1 == False: self.a = True self.plotx() else: self.check1 = False def text2_response(self): self.text2.setText(self.text_restricted(self.text2.text())) if self.check2 == False: self.b = True self.plotx() else: self.check2 = False def text3_response(self): self.text3.setText(self.text_restricted(self.text3.text())) if self.check3 == False: self.c = True self.plotx() else: self.check3 = False def text4_response(self): self.text4.setText(self.text_restricted(self.text4.text())) self.xrange() def text5_response(self): self.text5.setText(self.text_restricted(self.text5.text())) self.xrange() def text6_response(self): self.text6.setText(self.text_restricted(self.text6.text())) self.yrange() def text7_response(self): self.text7.setText(self.text_restricted(self.text7.text())) self.yrange() def xrange(self): if self.text4.text() == "" and self.text5.text() == "": self.error("No X Min Range") self.error("No X Max Range") self.error("Invalid X Range") self.f = False self.check_xrange = False if self.text1.text() == "" or self.text2.text( ) == "" or self.text3.text() == "": self.pw.setXRange(0, 1) else: self.pw.enableAutoRange(axis='x') elif self.text4.text() != "" and self.text5.text() != "": self.check_xrange = True if float(self.text4.text()) >= float(self.text5.text()): self.error_add("Invalid X Range") self.f = True else: self.pw.setXRange(float(self.text4.text()), float(self.text5.text())) self.error("No X Min Range") self.error("No X Max Range") self.error("Invalid X Range") self.f = False self.plotx() if self.text6.text() == "" or self.text7.text() == "": self.pw.enableAutoRange(axis='y') self.pw.setAutoVisible(y=True) else: if self.text4.text() == "" and self.check_xrange == True: self.error_add("No X Min Range") self.f = True self.pw.setXRange(0, 1) if self.text5.text() == "" and self.check_xrange == True: self.error_add("No X Max Range") self.f = True self.pw.setXRange(0, 1) if self.text6.text() != "" and self.text7.text() != "": self.pw.enableAutoRange(axis='x') self.pw.setAutoVisible(x=True) else: if self.d == True or self.e == True: self.pw.setYRange(0, 1) self.pw.setXRange(0, 1) else: self.pw.enableAutoRange() def yrange(self): if self.text6.text() == "" and self.text7.text() == "": self.error("No Y Min Range") self.error("No Y Max Range") self.error("Invalid Y Range") self.g = False self.check_yrange = False if self.text1.text() == "" or self.text2.text( ) == "" or self.text3.text() == "": self.pw.setYRange(0, 1) else: self.pw.enableAutoRange(axis='y') elif self.text6.text() != "" and self.text7.text() != "": self.check_yrange = True if float(self.text6.text()) >= float(self.text7.text()): self.error_add("Invalid Y Range") self.g = True else: self.pw.setYRange(float(self.text6.text()), float(self.text7.text())) self.error("No Y Min Range") self.error("No Y Max Range") self.error("Invalid Y Range") self.g = False self.plotx() if self.text4.text() == "" or self.text5.text() == "": self.pw.enableAutoRange(axis='x') self.pw.setAutoVisible(x=True) else: if self.text6.text() == "" and self.check_yrange == True: self.error_add("No Y Min Range") self.g = True self.pw.setYRange(0, 1) if self.text7.text() == "" and self.check_yrange == True: self.error_add("No Y Max Range") self.g = True self.pw.setYRange(0, 1) if self.text4.text() != "" and self.text5.text() != "": self.pw.enableAutoRange(axis='y') self.pw.setAutoVisible(y=True) else: if self.d == True or self.e == True: self.pw.setYRange(0, 1) self.pw.setXRange(0, 1) else: self.pw.enableAutoRange() def string2func(self, str): if str != "" and self.a == True and self.b == True and self.c == True: self.error("No Function to draw") self.d = False for word in re.findall('[a-zA-Z_]+', str): if word not in self.allowed_words: self.error_add("F(x) is not a Function of x") self.d = True else: self.d = False self.error('F(x) is not a Function of x') if word in self.replacements: str = str.replace(word, self.replacements[word]) if "^" in str: str = str.replace("^", "**") elif str == "" and self.b == True and self.c == True: self.error_add("No Function to draw") self.d = True self.pw.clear() def func(x): if str != "" and self.text2.text() != "" and self.text3.text( ) != "" and self.d == False: if self.d == False: try: if np.inf in eval(str): raise ZeroDivisionError if -np.inf in eval(str): raise ValueError except ZeroDivisionError: self.error_add("Cannot divide by Zero") self.d = True except FloatingPointError: self.error_addd("Undefined") self.d = True except ValueError: self.error_add("Math Error") self.d = True except: self.error_add("Syntax Error") self.d = True else: self.error("Cannot divide by Zero") self.error("Undefined") self.error("Math Error") self.error("Syntax Error") self.d = False return eval(str) return func def plotx(self): if self.text2.text() == "" and self.text3.text( ) == "" and self.text1.text( ) == "" and self.a == True and self.b == True and self.c == True: self.reset() func = self.string2func(self.text1.text()) if self.a == True and self.b == True and self.c == True and self.text2.text( ) != "" and self.text3.text() != "" and self.text1.text( ) != "" and self.d == False: if (self.text4.text() == "" and self.text5.text() == "") and ( self.text6.text() == "" and self.text7.text() == ""): self.pw.enableAutoRange() self.pw.clear() if (self.text2.text() == "-" or self.text3.text() == "-" or self.text3.text() == "." or self.text2.text() == "."): self.list_errors.append("Invalid Range") self.e = True else: min_num = float(self.text2.text()) max_num = float(self.text3.text()) if min_num >= max_num: self.error_add("Invalid Range") self.e = True else: range = np.linspace(min_num, max_num, 2000) if "x" not in self.text1.text( ) and self.text1.text() != "": try: if self.s == "light": self.pw.plot(range, np.ones(len(range)) * eval(self.text1.text()), pen=pg.mkPen(color=(140, 140, 140), width=2)) else: self.pw.plot(range, np.ones(len(range)) * eval(self.text1.text()), pen=pg.mkPen(color="w", width=2)) except ZeroDivisionError: self.error_add("Cannot divide by Zero") self.d = True except FloatingPointError: self.error_add("Undefined") self.d = True except ValueError: self.error_add("Math Error") self.d = True except: self.error_add("Syntax Error") self.d = True else: self.error("Cannot divide by Zero") self.error("Undefined") self.error("Math Error") self.error("Syntax Error") self.d = False else: y = func(range) if self.s == "light": self.pw.plot(range, y, pen=pg.mkPen(color=(140, 140, 140), width=2)) self.error("Invalid Range") self.error("No Min Value") self.error("No Max Value") else: self.pw.plot(range, y, pen=pg.mkPen(color="w", width=2)) self.error("Invalid Range") self.error("No Min Value") self.error("No Max Value") self.e = False else: if (self.text3.text() == "" and self.c == True): self.pw.clear() self.e = True self.error_add("No Max Value") elif (self.text3.text() != "" and self.c == True): self.error("No Max Value") if (self.text2.text() == "" and self.b == True): self.pw.clear() self.e = True self.error_add("No Min Value") elif (self.text2.text() != "" and self.b == True): self.error("No Min Value") def error(self, type): if type in self.list_errors: self.list_errors.remove(type) if len(self.list_errors) == 0: self.label4.setText("") else: self.label4.setText(self.list_errors[len(self.list_errors) - 1]) def error_add(self, error): if error in self.list_errors: pass else: self.list_errors.append(error) self.label4.setText(self.list_errors[len(self.list_errors) - 1]) def reset(self): self.pw.clear() if self.text4.text() == "" and self.text5.text( ) == "" and self.text6.text() == "" and self.text7.text() == "": self.pw.setXRange(0, 1) self.pw.setYRange(0, 1) self.check1 = True self.check2 = True self.check3 = True self.text1.setText("") self.text2.setText("") self.text3.setText("") self.a = False self.b = False self.c = False self.text1.setFocus() self.d = False self.e = False self.error("Invalid Range") self.error("No Min Value") self.error("No Max Value") self.error("Cannot divide by Zero") self.error("Undefined") self.error("Math Error") self.error("Syntax Error") self.error('F(x) is not a Function of x') self.error("No Function to draw") def focus_text1(self): self.text2.setFocus() def focus_text2(self): self.text3.setFocus() def focus_text3(self): self.text1.setFocus() def focus_text4(self): self.text5.setFocus() def focus_text5(self): self.text6.setFocus() def focus_text6(self): self.text7.setFocus() def focus_text7(self): self.text4.setFocus() def save(self): pass def information_dialog(self): if self.check_text == False: if self.s == "dark": self.gbox6.setTitle("Help") self.gbox6.setStyleSheet( "QGroupBox {border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.text8.setStyleSheet( "border:None;background-color:#383838;border:None;color: " + self.font_color_black) self.text8.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.text8.setText("--> The following operators must be used when writting the function:\n( - + / ^ ( ) ).\n\n--> The program supports the following functions and must be written as:" "\nsin(x),cos(x),tan(x),arccos(x),\narcsin(x),arctan(x),cosh(x),sinh(x),\ntanh(x),exp(x),sqrt(X),cbrt(x),\n" "log10(x),ln(x) and polynomial and rational functions." "\n\n--> The 'A' button in the Range box sets the x-axis and y-axis ranges to the appropriate values according to the values of the function.\n\n" \ "--> To close the Help box just click the help button beside the Export Graph.") else: self.gbox6.setTitle("Help") self.gbox6.setStyleSheet( "QGroupBox {border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.text8.setStyleSheet( "border:None;background-color:#f5f6f7;color: " + self.font_color) self.text8.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.text8.setText("--> The following operators must be used when writting the function:\n( - + / ^ ( ) ).\n\n--> The program supports the following functions and must be written as:" "\nsin(x),cos(x),tan(x),arccos(x),\narcsin(x),arctan(x),cosh(x),sinh(x),\ntanh(x),exp(x),sqrt(X),cbrt(x),\n" "log10(x),ln(x) and polynomial and rational functions." "\n\n--> The 'A' button in the Range box sets the x-axis and y-axis ranges to the appropriate values according to the values of the function.\n\n" \ "--> To close the Help box just click the help button beside the Export Graph.") self.check_text = True else: self.gbox6.setStyleSheet( "border:None;background-color:rgba(255,255,255,0)") self.text8.setStyleSheet( "border:None;background-color:rgba(255,255,255,0)") self.text8.setText("") self.gbox6.setTitle("") self.check_text = False def auto_mode(self): self.text4.setText("") self.text5.setText("") self.text6.setText("") self.text7.setText("") self.f = False self.g = False self.check_yrange == False self.check_xrange == False self.xrange() self.yrange() def dark_mode(self): self.input.setMaximumWidth(250) self.input.setFixedSize(250, 150) self.gbox.setMaximumWidth(250) self.gbox.setFixedSize(250, 90) self.gbox3.setMaximumWidth(250) self.gbox3.setFixedSize(250, 90) self.gbox4.setMaximumWidth(250) self.gbox4.setFixedSize(250, 45) self.gbox_mode.setMaximumWidth(250) self.gbox_mode.setFixedSize(250, 50) self.gbox5.setMaximumWidth(270) self.input.setObjectName("input") self.input.setStyleSheet( "QGroupBox#input{border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox#input::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox.setStyleSheet( "QGroupBox {border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox4.setStyleSheet( "QGroupBox {border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox_mode.setStyleSheet( "QGroupBox {border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.plot.setStyleSheet("color: " + self.font_color) self.setStyleSheet("background-color:#202020") self.label1.setStyleSheet( "background-color:#383838;border:None;color: " + self.font_color_black) self.label2.setStyleSheet( "background-color:#383838;border:None;color:" + self.font_color_black) self.label3.setStyleSheet( "background-color:#383838;border:None;color:" + self.font_color_black) self.label4.setStyleSheet( "background-color:#383838;border:None;color:" + self.font_color_black) self.label5.setStyleSheet( "background-color:#383838;border:None;color:" + self.font_color_black) self.label6.setStyleSheet( "background-color:#383838;border:None;color:" + self.font_color_black) self.rbutton1.setStyleSheet("background-color:#383838;color:" + self.font_color_black) self.rbutton2.setStyleSheet("background-color:#383838;color:" + self.font_color_black) self.rbutton1.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.rbutton2.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.label1.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label2.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label3.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label4.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label5.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label6.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text1.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text2.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text3.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text4.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text5.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text6.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.text7.setStyleSheet( "border:1px solid #5b5b5b;background-color:#383838;color:" + self.font_color_black) self.button_save.setStyleSheet( " QPushButton{border: 1px solid #f0f0f0;Text-align:center;background:#333333; color:#f0f0f0}" "QPushButton::hover{border: 1px solid #f0f0f0;Text-align:center;background:#2c2c2c}" "QPushButton::Pressed{border: 1px solid #f0f0f0;Text-align:center;background:#3d3c3c}" ) self.button.setStyleSheet( " QPushButton{border: 1px solid #f0f0f0;Text-align:center;background:#333333; color:#f0f0f0}" "QPushButton::hover{border: 1px solid #f0f0f0;Text-align:center;background:#2c2c2c}" "QPushButton::Pressed{border: 1px solid #f0f0f0;Text-align:center;background:#3d3c3c}" ) self.text1.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text2.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text3.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text4.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text5.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text6.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text7.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.gbox5.setObjectName("GroupBox") self.gbox5.setStyleSheet( "QGroupBox#GroupBox{border: None;background-color:#383838}") f = open("plotter.txt", "w") f.write("dark") f.close() self.s = "dark" self.pw.setBackground(background=None) if self.after == True: self.plotx() pixmap1 = QPixmap("auto-button_dark.png") button_icon1 = QIcon(pixmap1) self.button_2.setStyleSheet("border:none;background-color:#383838") self.button_2.setIcon(button_icon1) pixmap2 = QPixmap("help_dark.png") button_icon2 = QIcon(pixmap2) self.button_help.setIcon(button_icon2) self.button_help.setStyleSheet("border:none;background-color:#383838") if self.check_text == True: self.gbox6.setStyleSheet( "QGroupBox {border: 2px solid #3d3d3d;background-color:#383838;color: " + self.font_color_black + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.text8.setStyleSheet( "border:None;background-color:#383838;border:None;color: " + self.font_color_black) self.text8.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) def light_mode(self): self.input.setMaximumWidth(250) self.input.setFixedSize(250, 150) self.gbox.setMaximumWidth(250) self.gbox.setFixedSize(250, 90) self.gbox3.setMaximumWidth(250) self.gbox3.setFixedSize(250, 90) self.gbox4.setMaximumWidth(250) self.gbox4.setFixedSize(250, 45) self.gbox_mode.setMaximumWidth(250) self.gbox_mode.setFixedSize(250, 50) self.gbox5.setMaximumWidth(270) self.input.setObjectName("input") self.input.setStyleSheet( "QGroupBox#input{border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox#input::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox.setStyleSheet( "QGroupBox {border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox4.setStyleSheet( "QGroupBox {border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.gbox_mode.setStyleSheet( "QGroupBox {border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.plot.setStyleSheet("color: " + self.font_color) self.setStyleSheet("background-color:white;") self.label1.setStyleSheet("background-color:#f5f6f7;color: " + self.font_color) self.label2.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.label3.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.label4.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.label5.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.label6.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.rbutton1.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.rbutton2.setStyleSheet("background-color:#f5f6f7;color:" + self.font_color) self.rbutton1.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.rbutton2.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) self.label1.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label2.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label3.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label4.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label5.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.label6.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text1.setStyleSheet("background-color:white") self.text2.setStyleSheet("background-color:white") self.text3.setStyleSheet("background-color:white") self.text4.setStyleSheet("background-color:white") self.text5.setStyleSheet("background-color:white") self.text6.setStyleSheet("background-color:white") self.text7.setStyleSheet("background-color:white") self.button_save.setStyleSheet( " QPushButton{border: 1px solid #adadad;Text-align:center;background:#e1e1e1; color:black}" "QPushButton::hover{border: 1px solid #adadad;Text-align:center;background:#d8d7d7}" "QPushButton::Pressed{border: 1px solid #adadad;Text-align:center;background:#f5f6f7}" ) self.button.setStyleSheet( " QPushButton{border: 1px solid #adadad;Text-align:center;background:#e1e1e1; color:black}" "QPushButton::hover{border: 1px solid #adadad;Text-align:center;background:#d8d7d7}" "QPushButton::Pressed{border: 1px solid #adadad;Text-align:center;background:#f5f6f7}" ) self.text1.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text2.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text3.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text4.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text5.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text6.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.text7.setFont(QFont(self.font_type, self.font_size, QFont.Normal)) self.gbox5.setObjectName("GroupBox") self.gbox5.setStyleSheet( "QGroupBox#GroupBox{border: None;background-color:#f5f6f7}") f = open("plotter.txt", "w") f.write("light") f.close() self.s = "light" self.pw.setBackground(background=None) if self.after == True: self.plotx() pixmap2 = QPixmap("auto-button.png") button_icon2 = QIcon(pixmap2) self.button_2.setStyleSheet("border:none;background-color:#f5f6f7") self.button_2.setIcon(button_icon2) pixmap2 = QPixmap("help_light.png") button_icon2 = QIcon(pixmap2) self.button_help.setIcon(button_icon2) self.button_help.setStyleSheet("border:none;background-color:#f5f6f7") if self.check_text == True: self.gbox6.setStyleSheet( "QGroupBox {border: 2px solid #e6e6e6;background-color:#f5f6f7;color: " + self.font_color + ";margin-top: 6px;}" + "QGroupBox::title {subcontrol-origin:margin;left:8px;padding: 0px 0px 0px 0px;}" ) self.text8.setStyleSheet( "border:None;background-color:#f5f6f7;color: " + self.font_color) self.text8.setFont( QFont(self.font_type, self.font_size, QFont.Normal)) def export(self): self.exportdialog = exportDialog.ExportDialog(self.pw.plotItem.scene()) name = QFileDialog.getSaveFileName( self, 'Save File', "", "PNG (*.PNG;*.PNG);;CSV (*.CSV);;SVG(*.SVG)", "", QFileDialog.Options()) if name[0] != "": if "PNG" in name[1]: if self.s == "dark": self.pw.setBackground(background=(0, 0, 0)) else: self.pw.setBackground(background=(255, 255, 255)) exporter = pg.exporters.ImageExporter(self.pw.plotItem) exporter.export(name[0]) self.pw.setBackground(background=None) elif "CSV" in name[1]: exporter = pg.exporters.CSVExporter(self.pw.plotItem) exporter.export(name[0]) elif "SVG" in name[1]: if self.s == "dark": self.pw.setBackground(background=(0, 0, 0)) else: self.pw.setBackground(background=(255, 255, 255)) exporter = pg.exporters.SVGExporter(self.pw.plotItem) exporter.export(name[0]) self.pw.setBackground(background=None)
class ToolBox(QVBoxLayout): sig = QtCore.Signal(object) listThread = None groupBoxThreadInfo = None threadvbox = None mode = None def __init__(self, mode, parentQWidget = None): QVBoxLayout.__init__(self) self.sig.connect(self.addThreadList) self.mode = mode self.sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.groupBoxSearch = QGroupBox() self.groupBoxSearch.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 4px; };") vboxSearch = QVBoxLayout() self.searchTitle = QLabel("Search Messages") vboxSearch.addWidget(self.searchTitle) self.searchHLayout = QHBoxLayout() self.editTextSearch = QTextEdit('') self.editTextSearch.setFixedSize(200,30) self.buttonSearch = QPushButton('Search') self.buttonSearch.setFixedSize(100,30) self.buttonSearch.clicked.connect(self.searchMsg) vboxSearch.addWidget(self.editTextSearch) self.searchHLayout.addWidget(self.buttonSearch) self.searchCursor = QLabel() self.searchHLayout.addWidget(self.searchCursor) vboxSearch.addLayout(self.searchHLayout) self.browseHLayout = QHBoxLayout() self.buttonLookUp = QPushButton('\u21e7') #Arrow up self.buttonLookUp.setFixedWidth(100) self.buttonLookUp.clicked.connect(self.moveToPrev) self.buttonLookDown = QPushButton('\u21e9') #Arrow down self.buttonLookDown.setFixedWidth(100) self.buttonLookDown.clicked.connect(self.moveToNext) self.browseHLayout.addWidget(self.buttonLookUp) self.browseHLayout.addWidget(self.buttonLookDown) vboxSearch.addLayout(self.browseHLayout) self.groupBoxSearch.setLayout(vboxSearch) self.addWidget(self.groupBoxSearch) self.groupBoxSearch.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.buttonHiddenLifelines = QPushButton('Show hidden life-lines') self.buttonHiddenLifelines.setFixedWidth(200) self.buttonHiddenLifelines.clicked.connect(self.showHiddenLifelines) self.addWidget(self.buttonHiddenLifelines) self.buttonHiddenMessages = QPushButton('Show hidden Messages') self.buttonHiddenMessages.setFixedWidth(200) self.buttonHiddenMessages.clicked.connect(self.showHiddenMessages) self.addWidget(self.buttonHiddenMessages) if const.mode_interactive == mode: self.buttonCapture = QPushButton('Capture') self.buttonCapture.setFixedWidth(200) self.buttonCapture.clicked.connect(self.notifyCapture) self.addWidget(self.buttonCapture) self.msgRcv = [] self.msgInfo = QLabel("Message Info.") self.groupBoxMessageInfo = QGroupBox() self.groupBoxMessageInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;") vbox = QVBoxLayout() vbox.addWidget(self.msgInfo) self.tableTime = QTableWidget(3,2) self.tableTime.setHorizontalHeaderLabels(['-','time']) self.tableTime.setColumnWidth(0,80) self.tableTime.setColumnWidth(1,150) vwidth = self.tableTime.verticalHeader().length() hwidth = self.tableTime.horizontalHeader().height() fwidth = self.tableTime.frameWidth() * 2 self.tableTime.setFixedHeight(vwidth + hwidth + fwidth) self.tableTime.horizontalHeader().setStretchLastSection(True) self.tableTime.setItem(0,0,QTableWidgetItem('begin')) self.tableTime.setItem(0,1,QTableWidgetItem(' - ')) self.tableTime.setItem(1,0,QTableWidgetItem('end')) self.tableTime.setItem(1,1,QTableWidgetItem(' - ')) self.tableTime.setItem(2,0,QTableWidgetItem('duration')) self.tableTime.setItem(2,1,QTableWidgetItem(' - ')) vbox.addWidget(self.tableTime) self.titleArg = QLabel('Argument List') vbox.addWidget(self.titleArg) max_arg_num = 10 self.tableArgs = QTableWidget(max_arg_num,2) self.tableArgs.setHorizontalHeaderLabels(['type','value']) for idx in range(0,max_arg_num): self.tableArgs.setItem(idx,0,QTableWidgetItem()) self.tableArgs.setItem(idx,1,QTableWidgetItem()) self.tableArgs.horizontalHeader().setStretchLastSection(True) vbox.addWidget(self.tableArgs) self.titleArg = QLabel('Return Value List') vbox.addWidget(self.titleArg) max_ret_num = 4 self.tableRet = QTableWidget(max_ret_num,2) self.tableRet.setHorizontalHeaderLabels(['type','value']) for idx in range(0,max_ret_num): self.tableRet.setItem(idx,0,QTableWidgetItem()) self.tableRet.setItem(idx,1,QTableWidgetItem()) self.tableRet.horizontalHeader().setStretchLastSection(True) vwidth = self.tableRet.verticalHeader().length() hwidth = self.tableRet.horizontalHeader().height() fwidth = self.tableRet.frameWidth() * 2 self.tableRet.setFixedHeight(vwidth + hwidth + fwidth) vbox.addWidget(self.tableRet) self.buttonSrcView = QPushButton('view code') self.buttonSrcView.setFixedWidth(200) self.buttonSrcView.clicked.connect(self.openSourceViewer) self.buttonHide = QPushButton('Hide') self.buttonHide.setFixedWidth(200) self.buttonHide.clicked.connect(self.notifyHide) self.buttonHideAllMsg = QPushButton('Hide All') self.buttonHideAllMsg.setFixedWidth(200) self.buttonHideAllMsg.clicked.connect(self.hideAllMsgNamedAsSelected) self.groupBoxMessageInfo.setLayout(vbox) self.checkHideCircular = QCheckBox('Hide Circular Messages') self.checkHideCircular.setCheckState(QtCore.Qt.Unchecked) self.checkHideCircular.stateChanged.connect(self.changeHideCircularMessage) self.addWidget(self.checkHideCircular) self.addWidget(self.groupBoxMessageInfo) self.groupBoxMessageInfo.setSizePolicy(self.sizePolicy) def reset(self): for idx in reversed(range(0,self.listThread.count())): self.listThread.takeItem(idx) def setMsgInfoMessage(self,msg): self.strMessage = msg def changeHideCircularMessage(self,state): if state == QtCore.Qt.Unchecked: self.diagramView.hideCircularChanged(False) elif state == QtCore.Qt.Checked: self.diagramView.hideCircularChanged(True) def setMsgInfoModule(self,module): self.strModule = module def updateSearchStatus(self,curr,number): self.searchCursor.setText("%d/%d" % (curr,number)) def connectSourceViewer(self,viewer): self.srcViewer = viewer def openSourceViewer(self): self.srcViewer.openViewer(self.strModule,self.strMessage) def setMessageInfoTime(self,begin,end,duration): self.tableTime.item(0,1).setText(begin) self.tableTime.item(1,1).setText(end) self.tableTime.item(2,1).setText(duration + ' msec') def setMessageInfoArg(self,listParam,listArg): # Clear the contents in the table max_arg_num = 10 for idx in range(0,max_arg_num): self.tableArgs.item(idx,0).setText('') self.tableArgs.item(idx,1).setText('') if listArg: for idx, text in enumerate(listArg): self.tableArgs.item(idx,1).setText(text) for idx, text in enumerate(listParam): self.tableArgs.item(idx,0).setText(text) else: for idx in range(0,self.tableArgs.rowCount()): self.tableArgs.item(idx,1).setText('') self.tableArgs.item(idx,0).setText('') def setMessageInfoRet(self,listRet): if listRet: for idx, text in enumerate(listRet): self.tableRet.item(idx,1).setText(text) else: for idx in range(0,self.tableRet.rowCount()): self.tableRet.item(idx,1).setText('') self.tableRet.item(idx,0).setText('') def notifyInteractiveStateChanged(self,state): if const.mode_interactive != self.mode: return if const.STATE_INTERACTIVE_CAPTURING == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Stop Capture') if const.STATE_INTERACTIVE_PROCESSING == state: self.buttonCapture.setEnabled(False) if const.STATE_INTERACTIVE_IDLE == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') if const.STATE_INTERACTIVE_RESET == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') elif const.STATE_INTERACTIVE_ACTIVE == state: self.buttonCapture.setEnabled(True) self.buttonCapture.setText('Capture') def setMessageInfo(self,info): self.msgInfo.setText(info) def setAvailable(self,threads): self.sig.emit(threads) def toggleThreadDisplay(self,item): print(self.listThread.currentRow()) #if item.isSelected(): # print(item.text() + " is selected") #else: # print(item.text() + " is not selected") self.diagramView.showThread(self.listThread.currentRow(),item.isSelected()) def hideAllMsgNamedAsSelected(self): self.diagramView.hideAllMessageSelected() def addThreadList(self,threads): if not self.groupBoxThreadInfo: self.groupBoxThreadInfo = QGroupBox() self.threadInfo = QLabel("Thread Info.") self.groupBoxThreadInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;") if not self.threadvbox: self.threadvbox = QVBoxLayout() if not self.listThread: self.listThread = QListWidget() self.listThread.setFixedWidth(200) self.listThread.setSelectionMode(QAbstractItemView.MultiSelection) QtCore.QObject.connect(self.listThread, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.toggleThreadDisplay) self.threadvbox.addWidget(self.threadInfo) self.threadvbox.addWidget(self.listThread) self.groupBoxThreadInfo.setLayout(self.threadvbox) self.addWidget(self.groupBoxThreadInfo) self.groupBoxThreadInfo.setSizePolicy(self.sizePolicy) for id in threads: item = QListWidgetItem(id) self.listThread.addItem(item) def connectController(self,controller): self.controller = controller self.connect(controller,QtCore.SIGNAL('setAvailable()'),self.setAvailable) def connectDiagramView(self,view): self.diagramView = view def disconnectMsgRcv(self,receiver): print("Implement this method !!! disconnectMsgRcv") def connectMsgRcv(self,receiver): self.msgRcv.append(receiver) def notifyHide(self): for rcv in self.msgRcv: rcv.activateHide(True) def showHiddenLifelines(self): response, selected_items = HiddenDialog.HiddenDialog.getSelectedItems(self.diagramView.getHiddenLifeLines()) if response: self.diagramView.showLifelines(selected_items) def showHiddenMessages(self): response, selected_items = HiddenMessageDialog.HiddenMessageDialog.getSelectedItems(self.diagramView.getHiddenMessages(),self.diagramView.getHiddenLifeLines()) if response: if selected_items[3] in self.diagramView.getHiddenLifeLines(): confirmation = ShowLifeLineDialog.ShowLifeLineDialog.confirmToShowLifeLine(selected_items[3]) if confirmation: self.diagramView.showLifelines([selected_items[3]]) self.diagramView.showMessages(selected_items) else: self.diagramView.showMessages(selected_items) def notifyCapture(self): for rcv in self.msgRcv: rcv.activateCapture(True) def moveToPrev(self): for rcv in self.msgRcv: rcv.moveToPrev() def moveToNext(self): for rcv in self.msgRcv: rcv.moveToNext() def searchMsg(self): str = self.editTextSearch.toPlainText() for rcv in self.msgRcv: rcv.searchMessage(str)
def gui_init(self): control_group_layout = QVBoxLayout() control_group_widget = QWidget() control_group_widget.setLayout(control_group_layout) self.layout.addWidget(control_group_widget) rows = int(len(self._stepMotorAxies) / 2) columns = rows + int(len(self._stepMotorAxies) % 2) '''Добавляем шаговики''' steps_group = QGroupBox("{}".format(self.app.tr("Steppers"))) steps_group.setContentsMargins(0, 0, 0, 0) steps_group.setStyleSheet("QGroupBox::title {" "text-align: left;" "font: bold 14px;" "})") steps_group_layout = QGridLayout() steps_group.setLayout(steps_group_layout) row = 0 column = 0 for i, step_axis in enumerate(self._stepMotorAxies): row = int(i / (rows)) column = i - columns * row step_block = stepAxisWidget(step_axis, 1000, self.app, self) if self.__motorActions: step_block.changed.connect(self.__motorActions) steps_group_layout.addWidget(step_block, row, column, Qt.AlignCenter) # spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) # steps_group_layout.addItem(spacer) control_group_layout.addWidget(steps_group) servo_group = QGroupBox("{}".format(self.app.tr("Servos"))) servo_group.setContentsMargins(0, 0, 0, 0) servo_group.setStyleSheet("QGroupBox::title {" "text-align: left;" "font: bold 14px;" "})") servo_group_layout = QGridLayout() servo_group.setLayout(servo_group_layout) row = 0 column = 0 for i, servo_axis in enumerate(self._servoMotorAxies): row = int(i / (rows)) column = i - columns * row servo_block = servoAxisWidget(servo_axis, 1000, self.app, 180, self) if self.__motorActions: servo_block.changed.connect(self.__motorActions) servo_group_layout.addWidget(servo_block, row, column, Qt.AlignCenter) control_group_layout.addWidget(servo_group) led_group = QGroupBox("{}".format(self.app.tr("LED"))) led_group.setStyleSheet("QGroupBox::title {" "text-align: left;" "font: bold 14px;" "})") led_group_layout = QHBoxLayout() led_group.setLayout(led_group_layout) for pin, labels in self._controlPins.items(): switch = LedSwitch( self, target=pin) if len(labels) == 0 else LedSwitch( self, target=pin, leftText=labels[0], rightText=labels[1]) if self.__pinAcions: switch.switched.connect(self.__pinAcions) led_group_layout.addWidget(switch) control_group_layout.addWidget(led_group) spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) control_group_layout.addItem(spacer) spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.layout.addItem(spacer)
class PeopleTab(QWidget): def __init__(self, parent): QWidget.__init__(self) self.Parent = parent self.PeoplTitle = 'PEOPLE' self.UI() @property def Title(self): return self.PeoplTitle def UI(self): self.widgets() self.layouts() self.funcDisplayPeople() def widgets(self): # People widgets ########################################################### # Top layout (search people) widgets self.searchPeopleText = QLabel("Search: ") self.searchPeopleEntry = QLineEdit() self.searchPeopleEntry.setPlaceholderText("Search people..") self.searchPeopleBtn = QPushButton("Search") self.searchPeopleBtn.clicked.connect(self.searchPeople) self.refreshPeopleBtn = QPushButton("Refresh") self.refreshPeopleBtn.clicked.connect(self.funcDisplayPeople) # Middle layout (list people) widgets with radio buttons self.allPeopleRadioBtn = QRadioButton("All people") self.employeesPeopleRadioBtn = QRadioButton("Employees") self.contractorsPeopleRadioBtn = QRadioButton("Contractors") self.subcontractorsPeopleRadioBtn = QRadioButton("Subcontractors") self.listPeopleBtn = QPushButton("List") self.listPeopleBtn.clicked.connect(self.funcListPeople) # Bottom layout widget, a table showing people self.peopleTable = QTableWidget() self.peopleTable.verticalHeader().hide() self.peopleTable.setSortingEnabled(True) self.peopleTable.setShowGrid(False) self.peopleTable.verticalHeader().setDefaultSectionSize(90) self.peopleTable.setColumnCount(10) # self.peopleTable.setColumnHidden(0, True) self.peopleTable.setHorizontalHeaderItem(0, QTableWidgetItem("")) self.peopleTable.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.peopleTable.setHorizontalHeaderItem(1, QTableWidgetItem("Photo")) self.peopleTable.horizontalHeader().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.peopleTable.setHorizontalHeaderItem(2, QTableWidgetItem("ID")) self.peopleTable.setHorizontalHeaderItem( 3, QTableWidgetItem("First name")) self.peopleTable.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.peopleTable.setHorizontalHeaderItem(4, QTableWidgetItem("Last name")) self.peopleTable.horizontalHeader().setSectionResizeMode( 4, QHeaderView.Stretch) self.peopleTable.setHorizontalHeaderItem(5, QTableWidgetItem("Title")) self.peopleTable.setHorizontalHeaderItem(6, QTableWidgetItem("Phone")) self.peopleTable.horizontalHeader().setSectionResizeMode( 6, QHeaderView.Stretch) self.peopleTable.setHorizontalHeaderItem(7, QTableWidgetItem("Email")) self.peopleTable.horizontalHeader().setSectionResizeMode( 7, QHeaderView.Stretch) self.peopleTable.setHorizontalHeaderItem(8, QTableWidgetItem("Location")) self.peopleTable.setHorizontalHeaderItem( 9, QTableWidgetItem("Employment type")) self.peopleTable.horizontalHeader().setSectionResizeMode( 9, QHeaderView.ResizeToContents) # Double clicking a row opens a window with person details self.peopleTable.doubleClicked.connect(self.selectedPerson) # Buttons for actions on selected people self.addPerson = QPushButton("Add") self.addPerson.clicked.connect(self.funcAddPerson) self.viewPerson = QPushButton("View/Edit") self.viewPerson.clicked.connect(self.selectedPerson) self.deletePerson = QPushButton("Delete") self.deletePerson.clicked.connect(self.funcDeletePerson) self.exportPeopleCSVBtn = QPushButton("Export CSV") self.exportPeopleCSVBtn.setEnabled(False) self.exportPeopleCSVBtn.clicked.connect(self.funcPeopleToCSV) self.exportPeopleXLSXBtn = QPushButton("Export XLSX") self.exportPeopleXLSXBtn.setEnabled(False) self.exportPeopleXLSXBtn.clicked.connect(self.funcPeopleToXLSX) self.exportPeoplePDFBtn = QPushButton("Export PDF") self.exportPeoplePDFBtn.setEnabled(False) self.exportPeoplePDFBtn.clicked.connect(self.funcPeopleToPdf) def layouts(self): # People layouts ########################################################### self.peopleMainLayout = QVBoxLayout() self.peopleMainTopLayout = QHBoxLayout() self.peopleTopLeftLayout = QHBoxLayout() self.peopleTopRightLayout = QHBoxLayout() # self.peopleMainMiddleLayout = QHBoxLayout() self.peopleMainBottomLayout = QHBoxLayout() self.peopleBottomRightLayout = QVBoxLayout() self.peopleBottomLeftLayout = QHBoxLayout() # Groupboxes allows customization using CSS-like syntax # self.peopleTopGroupBox = QGroupBox() # self.peopleTopGroupBoxRightFiller = QGroupBox() # self.peopleMiddleGroupBox = QGroupBox() # self.peopleMiddleGroupBoxRightFiller = QGroupBox() self.peopleTopLeftGroupBox = QGroupBox() self.peopleTopRightGroupBox = QGroupBox() self.peopleTopGroupBox = QGroupBox() self.peopleBottomGroupBox = QGroupBox() self.peopleBottomLeftGroupBox = QGroupBox() self.peopleBottomRightGroupBox = QGroupBox() self.peopleBottomRightGroupBox.setStyleSheet( 'QGroupBox {margin-top: 0px;}') self.peopleBottomRightGroupBoxFiller = QGroupBox() self.peopleBottomRightGroupBoxFiller.setStyleSheet( styles.groupBoxFillerStyle()) # Top layout (search box) widgets self.peopleTopLeftLayout.addWidget(self.searchPeopleText, 10) self.peopleTopLeftLayout.addWidget(self.searchPeopleEntry, 30) self.peopleTopLeftLayout.addWidget(self.searchPeopleBtn, 10) self.peopleTopLeftLayout.addItem( QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.peopleTopLeftLayout.addWidget(self.refreshPeopleBtn, 10) self.peopleTopLeftGroupBox.setLayout(self.peopleTopLeftLayout) # Middle layout (list box) widgets self.peopleTopRightLayout.addWidget(self.allPeopleRadioBtn) self.peopleTopRightLayout.addWidget(self.employeesPeopleRadioBtn) self.peopleTopRightLayout.addWidget(self.contractorsPeopleRadioBtn) self.peopleTopRightLayout.addWidget(self.subcontractorsPeopleRadioBtn) self.peopleTopRightLayout.addWidget(self.listPeopleBtn) self.peopleTopRightGroupBox.setLayout(self.peopleTopRightLayout) self.peopleMainTopLayout.addWidget(self.peopleTopLeftGroupBox, 60) self.peopleMainTopLayout.addWidget(self.peopleTopRightGroupBox, 40) # Bottom layout (table with issues) widgets # Bottom left layout with table self.peopleBottomLeftLayout.addWidget(self.peopleTable) self.peopleBottomLeftGroupBox.setLayout(self.peopleBottomLeftLayout) # Bottom right layout with buttons self.peopleBottomRightLayout.addWidget(self.addPerson, 5) self.peopleBottomRightLayout.addWidget(self.viewPerson, 5) self.peopleBottomRightLayout.addWidget(self.deletePerson, 5) self.peopleBottomRightLayout.addWidget( self.peopleBottomRightGroupBoxFiller, 70) self.peopleBottomRightLayout.addWidget(self.exportPeopleCSVBtn, 5) self.peopleBottomRightLayout.addWidget(self.exportPeopleXLSXBtn, 5) self.peopleBottomRightLayout.addWidget(self.exportPeoplePDFBtn, 5) self.peopleBottomRightGroupBox.setLayout(self.peopleBottomRightLayout) self.peopleMainBottomLayout.addWidget(self.peopleTable, 90) self.peopleMainBottomLayout.addWidget(self.peopleBottomRightGroupBox, 10) # self.peopleMainLayout.addWidget(self.peopleTopGroupBox, 10) # self.peopleMainLayout.addWidget(self.peopleMiddleGroupBox, 10) # self.peopleMainLayout.addLayout(self.peopleMainBottomLayout, 80) self.peopleMainLayout.addLayout(self.peopleMainTopLayout, 10) self.peopleMainLayout.addLayout(self.peopleMainBottomLayout, 90) self.setLayout(self.peopleMainLayout) @Slot() def funcDisplayPeople(self): for i in reversed(range(self.peopleTable.rowCount())): self.peopleTable.removeRow(i) cur = db.cur people = cur.execute("SELECT * FROM people") for row_data in people: row_number = self.peopleTable.rowCount() self.peopleTable.insertRow(row_number) # Add checkboxes to the table widget = QWidget() checkBox = QCheckBox() checkBox.setCheckState(Qt.Unchecked) checkBox.stateChanged.connect(self.funcActivateBtnsWithCheckbox) hBoxLayout = QHBoxLayout(widget) hBoxLayout.addWidget(checkBox) hBoxLayout.setAlignment(Qt.AlignCenter) self.peopleTable.setCellWidget(row_number, 0, widget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add photo photos_thumbnails to the table thumbWidget = QWidget() pic = QPixmap(str(row_data[10])) thumbLabel = QLabel() thumbLabel.setPixmap(pic) thumbLayout = QHBoxLayout(thumbWidget) thumbLayout.addWidget(thumbLabel) self.peopleTable.setCellWidget(row_number, 1, thumbWidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Fill the rest of the data for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem("PRN#" + str(data))) else: self.peopleTable.setItem(row_number, column_number, QTableWidgetItem(str(data))) self.peopleTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.peopleTable.setSelectionBehavior(QTableView.SelectRows) @Slot() def funcActivateBtnsWithCheckbox(self): indices = self.funcPeopleCheckBox() if self.sender().isChecked() or indices: self.exportPeopleCSVBtn.setEnabled(True) self.exportPeopleXLSXBtn.setEnabled(True) self.exportPeoplePDFBtn.setEnabled(True) else: self.exportPeopleCSVBtn.setEnabled(False) self.exportPeopleXLSXBtn.setEnabled(False) self.exportPeoplePDFBtn.setEnabled(False) @Slot() def funcAddPerson(self): self.newPerson = AddPerson(self) self.newPerson.setObjectName("add_person_popup") self.newPerson.setStyleSheet(styles.addPopups()) @Slot() def funcPeopleCheckBox(self): checked_list = [] for i in range(self.peopleTable.rowCount()): if self.peopleTable.cellWidget(i, 0).findChild(type( QCheckBox())).isChecked(): item = self.peopleTable.item(i, 2).text() checked_list.append(item.lstrip("PRN#")) return checked_list @Slot() def selectedPerson(self): self.displayPerson = DisplayPerson(self) self.displayPerson.show() @Slot() def funcDeletePerson(self): indices = self.funcPeopleCheckBox() mbox = QMessageBox.question( self, "Warning", "Are you sure you want to delete this person?", QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if (mbox == QMessageBox.Yes): if indices: try: for index in range(len(indices)): query = "DELETE FROM people WHERE person_id = ?" db.cur.execute(query, (indices[index], )) db.conn.commit() QMessageBox.information(self, "Info", "Selected people were deleted") self.funcDisplayPeople() except: QMessageBox.information(self, "Info", "No changes made") else: row = self.peopleTable.currentRow() personId = self.peopleTable.item(row, 0).text() personId = personId.lstrip("PRN#") try: query = "DELETE FROM people WHERE person_id = ?" db.cur.execute(query, (personId, )) db.conn.commit() QMessageBox.information(self, "Info", "Person was deleted") self.funcDisplayPeople() except: QMessageBox.information(self, "Info", "No changes made") self.displayPerson.close() @Slot() def funcListPeople(self): if self.allPeopleRadioBtn.isChecked(): self.funcDisplayPeople() elif self.employeesPeopleRadioBtn.isChecked(): try: query = "SELECT * FROM people WHERE person_empl_type = 'Employee'" people = db.cur.execute(query).fetchall() for i in reversed(range(self.peopleTable.rowCount())): self.peopleTable.removeRow(i) for row_data in people: row_number = self.peopleTable.rowCount() self.peopleTable.insertRow(row_number) # Add checkboxes to the table widget = QWidget() checkBox = QCheckBox() checkBox.setCheckState(Qt.Unchecked) hBoxLayout = QHBoxLayout(widget) hBoxLayout.addWidget(checkBox) hBoxLayout.setAlignment(Qt.AlignCenter) self.peopleTable.setCellWidget(row_number, 0, widget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add photo photos_thumbnails to the table thumbWidget = QWidget() pic = QPixmap( "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png" ) thumbLabel = QLabel() thumbLabel.setPixmap(pic) thumbLayout = QHBoxLayout(thumbWidget) thumbLayout.addWidget(thumbLabel) self.peopleTable.setCellWidget(row_number, 1, thumbWidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Fill the rest of the data for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem("PRN#" + str(data))) else: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") elif self.contractorsPeopleRadioBtn.isChecked(): try: query = "SELECT * FROM people WHERE person_empl_type = 'Contractor'" people = db.cur.execute(query).fetchall() for i in reversed(range(self.peopleTable.rowCount())): self.peopleTable.removeRow(i) for row_data in people: row_number = self.peopleTable.rowCount() self.peopleTable.insertRow(row_number) # Add checkboxes to the table widget = QWidget() checkBox = QCheckBox() checkBox.setCheckState(Qt.Unchecked) hBoxLayout = QHBoxLayout(widget) hBoxLayout.addWidget(checkBox) hBoxLayout.setAlignment(Qt.AlignCenter) self.peopleTable.setCellWidget(row_number, 0, widget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add photo photos_thumbnails to the table thumbWidget = QWidget() pic = QPixmap( "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png" ) thumbLabel = QLabel() thumbLabel.setPixmap(pic) thumbLayout = QHBoxLayout(thumbWidget) thumbLayout.addWidget(thumbLabel) self.peopleTable.setCellWidget(row_number, 1, thumbWidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Fill the rest of the data for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem("PRN#" + str(data))) else: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") elif self.subcontractorsPeopleRadioBtn.isChecked(): try: query = "SELECT * FROM people WHERE person_empl_type = 'Subcontractor'" people = db.cur.execute(query).fetchall() for i in reversed(range(self.peopleTable.rowCount())): self.peopleTable.removeRow(i) for row_data in people: row_number = self.peopleTable.rowCount() self.peopleTable.insertRow(row_number) # Add checkboxes to the table widget = QWidget() checkBox = QCheckBox() checkBox.setCheckState(Qt.Unchecked) hBoxLayout = QHBoxLayout(widget) hBoxLayout.addWidget(checkBox) hBoxLayout.setAlignment(Qt.AlignCenter) self.peopleTable.setCellWidget(row_number, 0, widget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add photo photos_thumbnails to the table thumbWidget = QWidget() pic = QPixmap( "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png" ) thumbLabel = QLabel() thumbLabel.setPixmap(pic) thumbLayout = QHBoxLayout(thumbWidget) thumbLayout.addWidget(thumbLabel) self.peopleTable.setCellWidget(row_number, 1, thumbWidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Fill the rest of the data for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem("PRN#" + str(data))) else: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") @Slot() def searchPeople(self): value = self.searchPeopleEntry.text() if value == "": QMessageBox.information(self, "Warning", "Search string cannot be empty") self.funcDisplayPeople() else: # Erase search entry self.searchPeopleEntry.setText("") try: query = "SELECT * FROM people WHERE " \ "person_id LIKE ? " \ "OR person_first_name LIKE ?" \ "OR person_last_name LIKE ?" \ "OR person_title LIKE ?" \ "OR person_phone LIKE ?" \ "OR person_email LIKE ?" \ "OR person_location LIKE ?" \ "OR person_empl_type LIKE ?" results = db.cur.execute(query, ( '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', '%' + value + '%', )).fetchall() if results == []: QMessageBox.information(self, "Info", "Nothing was found") self.displayPeople() else: for i in reversed(range(self.peopleTable.rowCount())): self.peopleTable.removeRow(i) for row_data in results: row_number = self.peopleTable.rowCount() self.peopleTable.insertRow(row_number) # Add checkboxes to the table qwidget = QWidget() checkbox = QCheckBox() checkbox.setCheckState(Qt.Unchecked) qhboxlayout = QHBoxLayout(qwidget) qhboxlayout.addWidget(checkbox) qhboxlayout.setAlignment(Qt.AlignCenter) self.peopleTable.setCellWidget(row_number, 0, qwidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) # Add photo photos_thumbnails to the table thumbWidget = QWidget() pic = QPixmap( "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png" ) thumbLabel = QLabel() thumbLabel.setPixmap(pic) thumbLayout = QHBoxLayout(thumbWidget) thumbLayout.addWidget(thumbLabel) self.peopleTable.setCellWidget(row_number, 1, thumbWidget) self.peopleTable.setItem(row_number, 0, QTableWidgetItem(row_number)) for column_number, data in enumerate(row_data, start=2): if column_number == 2: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem("PRN#" + str(data))) else: self.peopleTable.setItem( row_number, column_number, QTableWidgetItem(str(data))) except: QMessageBox.information(self, "Info", "Cannot access database") @Slot() def funcPeopleToCSV(self): indices = self.funcPeopleCheckBox() if indices: CSV(self, "people", indices) else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" ) @Slot() def funcPeopleToXLSX(self): indices = self.funcPeopleCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp to when it was created to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/PeopleXLSX" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx", "Excel files (*.xlsx)") if fileName: db.cur.execute("SELECT * FROM people") workbook = xlsxwriter.Workbook(fileName) worksheet = workbook.add_worksheet("People") worksheet.set_column('A:C', 12) worksheet.set_row(0, 30) merge_format = workbook.add_format({ 'bold': 1, 'align': 'center', 'valign': 'vcenter' }) worksheet.merge_range('A1:B1', '', merge_format) worksheet.insert_image( 'A1', './assets/logo/logo-full-main.png', { 'x_scale': 0.4, 'y_scale': 0.4, 'x_offset': 15, 'y_offset': 10 }) # Create header row stop = 8 col = 0 for i, value in enumerate(db.cur.description[:stop]): worksheet.write(1, col, value[0]) col += 1 # Write date to xlsx file row_number = 2 for index in range(len(indices)): query = "SELECT * FROM people WHERE person_id=?" person_record = db.cur.execute( query, (indices[index], )).fetchone() for i, value in enumerate(person_record[:stop]): if person_record[9]: worksheet.set_row(row_number, 185) worksheet.set_column(8, 8, 35) worksheet.insert_image(row_number, 8, person_record[9], { 'x_scale': 0.3, 'y_scale': 0.3 }) worksheet.write(row_number, i, value) row_number += 1 workbook.close() QMessageBox.information( self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" ) @Slot() def funcPeopleToPdf(self): indices = self.funcPeopleCheckBox() if indices: try: date = datetime.datetime.now() # Get file location and add timestamp to when it was created to the filename fileName, _ = QFileDialog.getSaveFileName( self, "Save as...", "~/PeoplePDF" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf", "PDF files (*.pdf)") if fileName: pdf = PDF() pdf.add_page() pdf.set_font('Arial', 'B', 13) for index in range(len(indices)): query = "SELECT * FROM people WHERE person_id=?" person_record = db.cur.execute( query, (indices[index], )).fetchone() # This string allows for text formatting in the pdf, easy to implement and test stringPerson = "\nPerson id: " + str(person_record[0]) + \ "\nFirst name: " + str(person_record[1]) + \ "\nLast name: " + str(person_record[2]) + \ "\nTitle: " + str(person_record[3]) + \ "\nPhone: " + str(person_record[4]) + \ "\nEmail: " + str(person_record[5]) + \ "\nLocation: " + str(person_record[6]) + \ "\nEmployment type: " + str(person_record[7]) effectivePageWidth = pdf.w - 2 * pdf.l_margin ybefore = pdf.get_y() pdf.multi_cell(effectivePageWidth / 2, 10, stringPerson) if person_record[9]: pdf.set_xy(effectivePageWidth / 2 + pdf.l_margin, ybefore) pdf.image(person_record[9], effectivePageWidth / 2 + 20, 40, w=70) pdf.ln(0.5) if index != (len(indices) - 1): pdf.add_page() # pdf.multi_cell(200, 10, stringPerson) pdf.output(fileName, 'F') QMessageBox.information( self, "Info", "Data exported successfully into {}".format(fileName)) except: QMessageBox.information(self, "Info", "Export failed") else: QMessageBox.information( self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export" )
class MyWidget(QWidget): def __init__(self): QWidget.__init__(self) self.setStyleSheet("background-color:white; font-size:24px;") # Icon self.top_icon = QPixmap("ivs.jpg") self.top_icon_label = QLabel() self.top_icon_label.setAlignment(Qt.AlignCenter) self.top_icon_label.setPixmap( self.top_icon.scaled(256, 256, Qt.KeepAspectRatio)) # Title title_font = QFont("Helvatica", 24, QFont.Bold) self.title = QLabel("Intelligent Video Summarization") self.title.setFont(title_font) # Desired Objects self.desired_objects_checkbox = [ QCheckBox("car", self), QCheckBox("motor-bike", self), QCheckBox("rickshaw", self), QCheckBox("cycle", self), QCheckBox("person", self) ] self.desired_objects_label = QLabel("Select the desired objects") self.desired_objects = QGroupBox() self.desired_objects.setTitle("Select Desired Objects") # Add Options (Checkboxes) in Desired Objects self.desired_objects_layout = QVBoxLayout() self.desired_objects.setStyleSheet("font-weight:bold;") for checkbox in self.desired_objects_checkbox: self.desired_objects_layout.addWidget(checkbox) self.desired_objects.setLayout(self.desired_objects_layout) self.button = QPushButton("Select Video") self.button.setStyleSheet("background-color:blue; color:white;") self.start_button = QPushButton("Start") self.start_button.setStyleSheet("background-color:red; color:white;") # Detector self.detectors_list = [ QRadioButton("yolo", self), QRadioButton("frcc", self), QRadioButton("pseudo", self) ] self.detectors = QGroupBox() self.detectors.setTitle("Select Detection Algorithm") self.detectors_layout = QVBoxLayout() self.detectors.setStyleSheet("font-weight:bold;") for radio_button in self.detectors_list: self.detectors_layout.addWidget(radio_button) self.detectors.setLayout(self.detectors_layout) # Main Layout self.layout = QFormLayout() self.layout.addRow(self.top_icon_label) self.layout.addRow(self.title) self.layout.addRow(self.button) self.layout.addRow(self.desired_objects) self.layout.addRow(self.detectors) self.layout.addRow(self.start_button) self.setLayout(self.layout) # Connecting the signal self.button.clicked.connect(self.add_video_path) self.start_button.clicked.connect(self.start_summarizing) @Slot() def add_video_path(self): self.video_file_path = QFileDialog.getOpenFileName( self, "Select Video", str(Path.home()), "Video File (*.mp4, *.m4v)") # Update the text of button only if the selected video path is not empty if self.video_file_path[0]: self.button.setText(self.video_file_path[0]) @Slot() def start_summarizing(self): _desired_objects = [] _detection_algorithm = "" # get desired objects for child in self.desired_objects.children(): if hasattr(child, "isChecked") and child.isChecked(): _desired_objects.append(child) print(child.text()) # get detection algorithm for child in self.detectors.children(): if hasattr(child, "isChecked") and child.isChecked(): _detection_algorithm = child.text() print(dir(self.video_file_path[0])) subprocess.run([ "python3", "main.py", "--video", self.video_file_path[0], "--detector", _detection_algorithm ])