Beispiel #1
0
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
Beispiel #2
0
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])
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
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.')
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #10
0
    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):
        ...
Beispiel #12
0
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"
            )
Beispiel #15
0
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
Beispiel #16
0
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()
Beispiel #17
0
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]
Beispiel #19
0
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()
Beispiel #20
0
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)
Beispiel #21
0
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)
Beispiel #22
0
    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"
            )
Beispiel #24
0
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
        ])