コード例 #1
0
    def createWidget(self):
        # Add vertical layout to dock contents
        verticalLayout = QtWidgets.QVBoxLayout(self)
        verticalLayout.setContentsMargins(10, 10, 10, 10)
        verticalLayout.setAlignment(Qt.AlignTop)

        # Add vertical layout to main widget (self)
        self.setLayout(verticalLayout)

        # Add the next and previous buttons:
        horizontalGroupBox = QGroupBox()
        horizontalGroupBox.setContentsMargins(0, 0, 0, 0)
        horizontalLayout = QHBoxLayout()
        horizontalGroupBox.setLayout(horizontalLayout)
        horizontalGroupBox.setFlat(True)
        verticalLayout.addWidget(horizontalGroupBox)

        next_button = QPushButton("Next step")
        prev_button = QPushButton("Previous step")
        prev_button.setEnabled(False)
        prev_button.clicked.connect(lambda: self.updateStep('prev'))
        next_button.clicked.connect(lambda: self.updateStep('next'))
        horizontalLayout.addWidget(prev_button)
        horizontalLayout.addWidget(next_button)
        self.next_button = next_button
        self.prev_button = prev_button

        self.current_step = -1

        self.uiElements = {
            'verticalLayout': verticalLayout,
            'buttonGroupBox': horizontalGroupBox,
        }
        self.widgets = {}
コード例 #2
0
def create_group_box(parent, text):
    font = QFont()
    font.setBold(True)
    group_box = QGroupBox(text, parent)
    group_box.setFont(font)
    group_box.setAlignment(Qt.AlignHCenter)
    group_box.setFlat(False)
    return group_box
コード例 #3
0
    def __init__(self, all_course_info, choose_info, parent=None):
        super(OptionalCourse, self).__init__(parent)

        self.course_info = []

        # Create optional course GroupBox
        optional_course = QGroupBox("选修")
        optional_course.setFlat(False)

        # Optional course checkbox
        self.checkBox = []
        for i in all_course_info:
            if i[0] == '-':
                checkbox = QCheckBox(i[1:])
                checkbox.stateChanged.connect(self.checkbox_func)
                self.checkBox.append(checkbox)

        # Add label and combobox to GridLayout
        i = 0
        j = 0
        self.optional_layout = QGridLayout()
        for obj in range(len(self.checkBox)):
            self.optional_layout.addWidget(self.checkBox[obj], j, i)
            if i == 4:
                j = j + 1
                i = 0
            else:
                i = i + 2

        optional_course.setLayout(self.optional_layout)
        button = QPushButton("确定", self)
        button.clicked.connect(self.return_info)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(optional_course)
        mainLayout.addWidget(button)

        for i in choose_info:
            for j in self.checkBox:
                if i == j.text():
                    j.setChecked(True)

        self.setLayout(mainLayout)
        self.setWindowTitle("选修课")
コード例 #4
0
    def __init__(self,
                 candidate_course,
                 all_candidate_course,
                 candidate_course_semester,
                 pre2post,
                 parent=None):
        super(ChangeCourse, self).__init__(parent)

        self.course_info = dict()
        self.pre2post = pre2post
        self.candidate_course_semester = candidate_course_semester

        # Create required course GroupBox
        required_course = QGroupBox("必修")
        required_course.setFlat(False)

        # Course Label
        self.checkBox = []
        for i in candidate_course:
            if i[0] != '-':
                self.course_info[i] = ''
                label = QLabel(i)
                self.checkBox.append(label)

        # Course combobox
        self.cb = []
        for i in range(0, len(candidate_course)):
            if candidate_course[i][0] != '-':
                cb = QComboBox(self)
                for k in range(
                        candidate_course_semester[all_candidate_course[i]], 8):
                    self.course_info[
                        all_candidate_course[i]] = candidate_course_semester[
                            all_candidate_course[i]]
                    cb.addItem(str(k))
                cb.currentIndexChanged.connect(self.get_info)
                self.cb.append(cb)

        # Add label and combobox to GridLayout
        i = 0
        j = 0
        self.required_layout = QGridLayout()
        for obj in range(len(self.checkBox)):
            self.required_layout.addWidget(self.checkBox[obj], j, i)
            self.required_layout.addWidget(self.cb[obj], j, i + 1)
            if i == 4:
                j = j + 1
                i = 0
            else:
                i = i + 2

        required_course.setLayout(self.required_layout)

        # Create optional course GroupBox
        optional_course = QGroupBox("选修")
        optional_course.setFlat(False)

        # Optional course checkbox
        self.checkBox_optional = []
        for i in candidate_course:
            if i[0] == '-':
                checkbox = QLabel(i[1:])
                # checkbox.stateChanged.connect(self.checkbox_func)
                self.checkBox_optional.append(checkbox)

        # Optional course combobox
        self.cb = []
        for i in range(0, len(self.checkBox_optional)):
            cb = QComboBox(self)
            # cb.addItem('')
            for k in range(
                    candidate_course_semester[
                        self.checkBox_optional[i].text()], 8):
                self.course_info[self.checkBox_optional[i].text(
                )] = candidate_course_semester[
                    self.checkBox_optional[i].text()]
                cb.addItem(str(k))
            cb.currentIndexChanged.connect(self.get_info)
            self.cb.append(cb)

        # Add label and combobox to GridLayout
        i = 0
        j = 0
        self.optional_layout = QGridLayout()
        for obj in range(len(self.checkBox_optional)):
            self.optional_layout.addWidget(self.checkBox_optional[obj], j, i)
            self.optional_layout.addWidget(self.cb[obj], j, i + 1)
            if i == 4:
                j = j + 1
                i = 0
            else:
                i = i + 2

        optional_course.setLayout(self.optional_layout)
        button = QPushButton("确定", self)
        button.clicked.connect(self.return_info)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(required_course)
        mainLayout.addWidget(optional_course)
        mainLayout.addWidget(button)

        self.setLayout(mainLayout)
        self.setWindowTitle("高级排课选项")
コード例 #5
0
ファイル: cutterplugin.py プロジェクト: ctlayon/capa-explorer
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)
コード例 #6
0
class Preferences(QDialog):
    def __init__(self, prefs, icon=None):
        super().__init__()
        self.prefs = prefs
        self.hotkey_format_regex = r'^\<ctrl\>\+\<alt\>(\+\<shift\>)?\+[a-zA-Z0-9]$'
        if icon:
            self.setWindowIcon(icon)

        # checkbox: Include Minimized
        include_minimized = QCheckBox()
        include_minimized.setFixedWidth(35)
        include_minimized.setChecked(self.prefs["include_minimized"]["value"])
        include_minimized.stateChanged.connect(
            lambda: self.include_minimized(include_minimized.isChecked()))
        include_minimized_descr = QLabel(
            self.prefs["include_minimized"]["description"])
        include_minimized_descr.setWordWrap(True)

        include_minimized_layout = QHBoxLayout()
        include_minimized_layout.addWidget(include_minimized)
        include_minimized_layout.addWidget(include_minimized_descr)

        include_minimized_groupbox = QGroupBox("Include Minimized")
        include_minimized_groupbox.setLayout(include_minimized_layout)

        # checkbox: snap to grid
        snap_to_grid = QCheckBox()
        snap_to_grid.setFixedWidth(35)
        snap_to_grid.setChecked(self.prefs["snap_to_grid"]["value"])
        snap_to_grid.stateChanged.connect(
            lambda: self.snap_to_grid(snap_to_grid.isChecked()))
        snap_to_grid_descr = QLabel(self.prefs["snap_to_grid"]["description"])
        snap_to_grid_descr.setWordWrap(True)

        snap_to_grid_layout = QHBoxLayout()
        snap_to_grid_layout.addWidget(snap_to_grid)
        snap_to_grid_layout.addWidget(snap_to_grid_descr)

        snap_to_grid_groupbox = QGroupBox("Snap To Grid")
        snap_to_grid_groupbox.setLayout(snap_to_grid_layout)

        # checkbox: fit into screen
        fit_into_screen = QCheckBox()
        fit_into_screen.setFixedWidth(35)
        fit_into_screen.setChecked(self.prefs["fit_into_screen"]["value"])
        fit_into_screen.stateChanged.connect(
            lambda: self.fit_into_screen(fit_into_screen.isChecked()))
        fit_into_screen_descr = QLabel(
            self.prefs["fit_into_screen"]["description"])
        fit_into_screen_descr.setWordWrap(True)

        fit_into_screen_layout = QHBoxLayout()
        fit_into_screen_layout.addWidget(fit_into_screen)
        fit_into_screen_layout.addWidget(fit_into_screen_descr)

        fit_into_screen_groupbox = QGroupBox("Fit Into Screen")
        fit_into_screen_groupbox.setLayout(fit_into_screen_layout)

        # doublespinBox: match cutoff
        match_cutoff = QDoubleSpinBox()
        match_cutoff.setFixedWidth(35)
        match_cutoff.setValue(self.prefs["match_cutoff"]["value"])
        match_cutoff.setRange(0.1, 1.0)
        match_cutoff.setSingleStep(0.1)
        match_cutoff.setDecimals(1)
        match_cutoff.valueChanged.connect(
            lambda: self.match_cutoff(match_cutoff.value()))
        match_cutoff_descr = QLabel(self.prefs["match_cutoff"]["description"])
        match_cutoff_descr.setWordWrap(True)

        match_cutoff_layout = QHBoxLayout()
        match_cutoff_layout.addWidget(match_cutoff)
        match_cutoff_layout.addWidget(match_cutoff_descr)

        match_cutoff_groupbox = QGroupBox("Match Cutoff")
        match_cutoff_groupbox.setLayout(match_cutoff_layout)

        # checkbox: enable hotkeys
        enable_hotkeys = QCheckBox()
        enable_hotkeys.setFixedWidth(35)
        enable_hotkeys.setChecked(self.prefs["enable_hotkeys"]["value"])
        enable_hotkeys.stateChanged.connect(
            lambda: self.enable_hotkeys(enable_hotkeys.isChecked()))
        enable_hotkeys_descr = QLabel(
            self.prefs["enable_hotkeys"]["description"])
        enable_hotkeys_descr.setWordWrap(True)

        enable_hotkeys_layout = QHBoxLayout()
        enable_hotkeys_layout.addWidget(enable_hotkeys)
        enable_hotkeys_layout.addWidget(enable_hotkeys_descr)

        # lineedit: hotkeys shortcuts
        hotkey_freeze_new_name = QLabel("Freeze New:")
        hotkey_freeze_new_name.setFixedWidth(75)
        self.hotkey_freeze_new_status = QLabel()
        self.hotkey_freeze_new = QLineEdit(
            self.prefs["hotkeys"]["value"]["freeze_new"])
        self.hotkey_freeze_new.setFixedWidth(140)
        self.hotkey_freeze_new.editingFinished.connect(
            lambda: self.hotkey_freeze_new_update(self.hotkey_freeze_new.text(
            )))
        self.hotkey_freeze_new.cursorPositionChanged.connect(
            self.hotkey_freeze_new_status.clear)

        hotkey_freeze_new_layout = QHBoxLayout()
        hotkey_freeze_new_layout.addWidget(hotkey_freeze_new_name)
        hotkey_freeze_new_layout.addWidget(self.hotkey_freeze_new)
        hotkey_freeze_new_layout.addWidget(self.hotkey_freeze_new_status)

        hotkey_freeze_all_name = QLabel("Freeze All:")
        hotkey_freeze_all_name.setFixedWidth(75)
        self.hotkey_freeze_all_status = QLabel()
        self.hotkey_freeze_all = QLineEdit(
            self.prefs["hotkeys"]["value"]["freeze_all"])
        self.hotkey_freeze_all.setFixedWidth(140)
        self.hotkey_freeze_all.editingFinished.connect(
            lambda: self.hotkey_freeze_all_update(self.hotkey_freeze_all.text(
            )))
        self.hotkey_freeze_all.cursorPositionChanged.connect(
            self.hotkey_freeze_all_status.clear)

        hotkey_freeze_all_layout = QHBoxLayout()
        hotkey_freeze_all_layout.addWidget(hotkey_freeze_all_name)
        hotkey_freeze_all_layout.addWidget(self.hotkey_freeze_all)
        hotkey_freeze_all_layout.addWidget(self.hotkey_freeze_all_status)

        hotkey_restore_name = QLabel("Restore:")
        hotkey_restore_name.setFixedWidth(75)
        self.hotkey_restore_status = QLabel()
        self.hotkey_restore = QLineEdit(
            self.prefs["hotkeys"]["value"]["restore"])
        self.hotkey_restore.setFixedWidth(140)
        self.hotkey_restore.editingFinished.connect(
            lambda: self.hotkey_restore_update(self.hotkey_restore.text()))
        self.hotkey_restore.cursorPositionChanged.connect(
            self.hotkey_restore_status.clear)

        hotkey_restore_layout = QHBoxLayout()
        hotkey_restore_layout.addWidget(hotkey_restore_name)
        hotkey_restore_layout.addWidget(self.hotkey_restore)
        hotkey_restore_layout.addWidget(self.hotkey_restore_status)

        self.hotkeys_statusbar = QLabel()
        self.hotkeys_statusbar.setWordWrap(True)
        self.hotkeys_statusbar.setText(hotkeys_statusbar_map[
            self.prefs['enable_hotkeys']['value']]['text'])
        self.hotkeys_statusbar.setStyleSheet(hotkeys_statusbar_map[
            self.prefs['enable_hotkeys']['value']]['style'])

        close_button = QPushButton("Close")
        close_button.setMaximumWidth(75)
        close_button.clicked.connect(self.close)

        hotkeys_statusbar_layout = QHBoxLayout()
        hotkeys_statusbar_layout.addWidget(self.hotkeys_statusbar)
        hotkeys_statusbar_layout.addWidget(close_button)

        hotkeys_layout = QVBoxLayout()
        hotkeys_layout.addLayout(hotkey_freeze_new_layout)
        hotkeys_layout.addLayout(hotkey_freeze_all_layout)
        hotkeys_layout.addLayout(hotkey_restore_layout)

        self.hotkeys_groupbox = QGroupBox()
        self.hotkeys_groupbox.setFlat(True)
        self.hotkeys_groupbox.setDisabled(
            not self.prefs["enable_hotkeys"]["value"])
        self.hotkeys_groupbox.setLayout(hotkeys_layout)

        enable_hotkeys_outer_layout = QVBoxLayout()
        enable_hotkeys_outer_layout.addLayout(enable_hotkeys_layout)
        enable_hotkeys_outer_layout.addWidget(self.hotkeys_groupbox)

        enable_hotkeys_groupbox = QGroupBox("Enable Hotkeys")
        enable_hotkeys_groupbox.setLayout(enable_hotkeys_outer_layout)

        # Create main layout and add widgets
        main_layout = QVBoxLayout()
        main_layout.addWidget(include_minimized_groupbox)
        main_layout.addWidget(snap_to_grid_groupbox)
        main_layout.addWidget(fit_into_screen_groupbox)
        main_layout.addWidget(match_cutoff_groupbox)
        main_layout.addWidget(enable_hotkeys_groupbox)
        main_layout.addWidget(self.hotkeys_groupbox)
        #main_layout.addWidget(hotkeys_statusbar_groupbox)
        main_layout.addLayout(hotkeys_statusbar_layout)
        self.setLayout(main_layout)

    def include_minimized(self, isChecked):
        print(f'include_minimized: {isChecked}')
        self.prefs["include_minimized"]["value"] = isChecked

    def snap_to_grid(self, isChecked):
        print(f'snap_to_grid: {isChecked}')
        self.prefs["snap_to_grid"]["value"] = isChecked

    def fit_into_screen(self, isChecked):
        print(f'fit_into_screen: {isChecked}')
        self.prefs["fit_into_screen"]["value"] = isChecked

    def match_cutoff(self, value):
        rounded_value = round(value, 1)
        print(f'match_cutoff: {rounded_value}')
        self.prefs["match_cutoff"]["value"] = rounded_value

    def enable_hotkeys(self, isChecked):
        print(f'enable_hotkeys: {isChecked}')
        self.prefs["enable_hotkeys"]["value"] = isChecked
        self.hotkeys_groupbox.setDisabled(not isChecked)
        self.hotkeys_statusbar.setText(
            hotkeys_statusbar_map[isChecked]['text'])
        self.hotkeys_statusbar.setStyleSheet(
            hotkeys_statusbar_map[isChecked]['style'])

    def hotkey_freeze_new_update(self, text):
        print(f'hotkey_freeze_new: {text}')
        if re.match(self.hotkey_format_regex, text):
            self.prefs["hotkeys"]["value"]["freeze_new"] = text
            self.hotkey_freeze_new_status.setText(f'Updated!')
            self.hotkey_freeze_new_status.setStyleSheet("color: green;")
        else:
            self.hotkey_freeze_new.setText(
                self.prefs["hotkeys"]["value"]["freeze_new"])
            self.hotkey_freeze_new_status.setText(
                'Failed to update: unsupported format')
            self.hotkey_freeze_new_status.setStyleSheet("color: red;")

    def hotkey_freeze_all_update(self, text):
        print(f'hotkey_freeze_all: {text}')
        if re.match(self.hotkey_format_regex, text):
            self.prefs["hotkeys"]["value"]["freeze_all"] = text
            self.hotkey_freeze_all_status.setText(f'Updated!')
            self.hotkey_freeze_all_status.setStyleSheet("color: green;")
        else:
            self.hotkey_freeze_all.setText(
                self.prefs["hotkeys"]["value"]["freeze_all"])
            self.hotkey_freeze_all_status.setText(
                'Failed to update: unsupported format')
            self.hotkey_freeze_all_status.setStyleSheet("color: red;")

    def hotkey_restore_update(self, text):
        print(f'hotkey_restore: {text}')
        if re.match(self.hotkey_format_regex, text):
            self.prefs["hotkeys"]["value"]["restore"] = text
            self.hotkey_restore_status.setText(f'Updated!')
            self.hotkey_restore_status.setStyleSheet("color: green;")
        else:
            self.hotkey_restore.setText(
                self.prefs["hotkeys"]["value"]["restore"])
            self.hotkey_restore_status.setText(
                'Failed to update: unsupported format')
            self.hotkey_restore_status.setStyleSheet("color: red;")
コード例 #7
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_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.')
コード例 #8
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)
コード例 #9
0
    def initialise(self):
        self.settingsFile = os.path.join(self.findNukeHomeDir(),
                                         "deadline_settings.ini")
        print("Loading settings: " + self.settingsFile)

        # Initialize the submission settings.
        self.settings = QSettings(self.settingsFile, QSettings.IniFormat)

        print("Grabbing submitter info...")
        try:
            dcOutput = CallDeadlineCommand([
                "-prettyJSON",
                "-GetSubmissionInfo",
                "Pools",
                "Groups",
                "MaxPriority",
                "TaskLimit",
                "UserHomeDir",
                "RepoDir:submission/Hiero/Main",
                "RepoDir:submission/Integration/Main",
            ],
                                           useDeadlineBg=True)
            output = json.loads(dcOutput, encoding="utf-8")
        except ValueError as e:
            print("Unable to get submitter info from Deadline:\n\n" +
                  e.message)
            raise

        if output["ok"]:
            self.submissionInfo = output["result"]
        else:
            raise ValueError(
                "DeadlineCommand returned a bad result and was unable to grab the submitter info.\n\n"
                + output["result"])

        # Get the Deadline temp directory.
        deadlineHome = self.submissionInfo["UserHomeDir"].strip()
        self.deadlineTemp = os.path.join(deadlineHome, "temp")

        self.integrationDir = self.submissionInfo["RepoDirs"][
            "submission/Integration/Main"].strip()

        # Get maximum priority.
        maximumPriority = self.submissionInfo["MaxPriority"]

        # Collect the pools and groups.
        pools = self.submissionInfo["Pools"]

        secondaryPools = [""]
        secondaryPools.extend(pools)

        groups = self.submissionInfo["Groups"]

        # Set up the other default arrays.
        onJobComplete = ("Nothing", "Archive", "Delete")
        nukeVersions = ("6.0", "6.1", "6.2", "6.3", "6.4", "7.0", "7.1", "7.2",
                        "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "9.0",
                        "9.1", "9.2", "9.3", "9.4", "10.0", "10.1", "10.2",
                        "10.3", "10.4", "11.0", "11.1", "11.2", "11.3")
        buildsToForce = ("None", "32bit", "64bit")

        # Main Window
        mainWindow = hiero.ui.mainWindow()
        dialog = QDialog(mainWindow)
        self.dialog = dialog
        dialog.setWindowTitle("Submit to Deadline (and render with Nuke)")

        # Main Layout
        topLayout = QVBoxLayout()
        dialog.setLayout(topLayout)
        tabWidget = QTabWidget(dialog)

        jobTab = QWidget()
        jobTabLayout = QVBoxLayout()
        jobTab.setLayout(jobTabLayout)

        # Job Info Layout
        jobInfoGroupBox = QGroupBox("Job Description")
        jobTabLayout.addWidget(jobInfoGroupBox)
        jobInfoLayout = QGridLayout()
        jobInfoGroupBox.setLayout(jobInfoLayout)

        # Job Name
        jobInfoLayout.addWidget(QLabel("Job Name"), 0, 0)
        jobNameWidget = QLineEdit(self.settings.value("JobName", ""))
        jobInfoLayout.addWidget(jobNameWidget, 0, 1)

        # Comment
        jobInfoLayout.addWidget(QLabel("Comment"), 1, 0)
        commentWidget = QLineEdit(self.settings.value("Comment", ""))
        jobInfoLayout.addWidget(commentWidget, 1, 1)

        # Department
        jobInfoLayout.addWidget(QLabel("Department"), 2, 0)
        departmentWidget = QLineEdit(self.settings.value("Department", ""))
        jobInfoLayout.addWidget(departmentWidget, 2, 1)

        # Job Options Layout
        jobOptionsGroupBox = QGroupBox("Job Options")
        jobTabLayout.addWidget(jobOptionsGroupBox)
        jobOptionsLayout = QGridLayout()
        jobOptionsGroupBox.setLayout(jobOptionsLayout)

        # Pool
        jobOptionsLayout.addWidget(QLabel("Pool"), 0, 0)
        poolWidget = QComboBox()
        for pool in pools:
            poolWidget.addItem(pool)

        defaultPool = self.settings.value("Pool", "none")
        defaultIndex = poolWidget.findText(defaultPool)
        if defaultIndex != -1:
            poolWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(poolWidget, 0, 1, 1, 3)

        # Secondary Pool
        jobOptionsLayout.addWidget(QLabel("Secondary Pool"), 1, 0)
        secondaryPoolWidget = QComboBox()
        for secondaryPool in secondaryPools:
            secondaryPoolWidget.addItem(secondaryPool)

        defaultSecondaryPool = self.settings.value("SecondaryPool", "")
        defaultIndex = secondaryPoolWidget.findText(defaultSecondaryPool)
        if defaultIndex != -1:
            secondaryPoolWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(secondaryPoolWidget, 1, 1, 1, 3)

        # Group
        jobOptionsLayout.addWidget(QLabel("Group"), 2, 0)
        groupWidget = QComboBox()
        for group in groups:
            groupWidget.addItem(group)

        defaultGroup = self.settings.value("Group", "none")
        defaultIndex = groupWidget.findText(defaultGroup)
        if defaultIndex != -1:
            groupWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(groupWidget, 2, 1, 1, 3)

        # Priority
        initPriority = int(self.settings.value("Priority", "50"))
        if initPriority > maximumPriority:
            initPriority = maximumPriority / 2

        jobOptionsLayout.addWidget(QLabel("Priority"), 3, 0)
        priorityWidget = QSpinBox()
        priorityWidget.setRange(0, maximumPriority)
        priorityWidget.setValue(initPriority)
        jobOptionsLayout.addWidget(priorityWidget, 3, 1)

        # Task Timeout
        jobOptionsLayout.addWidget(QLabel("Task Timeout"), 4, 0)
        taskTimeoutWidget = QSpinBox()
        taskTimeoutWidget.setRange(0, 1000000)
        taskTimeoutWidget.setValue(int(self.settings.value("TaskTimeout",
                                                           "0")))
        jobOptionsLayout.addWidget(taskTimeoutWidget, 4, 1)

        # Auto Task Timeout
        autoTaskTimeoutWidget = QCheckBox("Enable Auto Task Timeout")
        autoTaskTimeoutWidget.setChecked(
            strtobool(self.settings.value("AutoTaskTimeout", "False")))
        jobOptionsLayout.addWidget(autoTaskTimeoutWidget, 4, 2)

        # Concurrent Tasks
        jobOptionsLayout.addWidget(QLabel("Concurrent Tasks"), 5, 0)
        concurrentTasksWidget = QSpinBox()
        concurrentTasksWidget.setRange(1, 16)
        concurrentTasksWidget.setValue(
            int(self.settings.value("ConcurrentTasks", "1")))
        jobOptionsLayout.addWidget(concurrentTasksWidget, 5, 1)

        # Limit Tasks To Slave's Task Limit
        limitConcurrentTasksWidget = QCheckBox(
            "Limit Tasks To Slave's Task Limit")
        limitConcurrentTasksWidget.setChecked(
            strtobool(self.settings.value("LimitConcurrentTasks", "True")))
        jobOptionsLayout.addWidget(limitConcurrentTasksWidget, 5, 2)

        # Machine Limit
        jobOptionsLayout.addWidget(QLabel("Machine Limit"), 6, 0)
        machineLimitWidget = QSpinBox()
        machineLimitWidget.setRange(0, 1000000)
        machineLimitWidget.setValue(
            int(self.settings.value("MachineLimit", "1")))
        jobOptionsLayout.addWidget(machineLimitWidget, 6, 1)

        # Machine List Is A Blacklist
        isBlacklistWidget = QCheckBox("Machine List Is A Blacklist")
        isBlacklistWidget.setChecked(
            strtobool(self.settings.value("IsBlacklist", "False")))
        jobOptionsLayout.addWidget(isBlacklistWidget, 6, 2)

        # Machine List
        jobOptionsLayout.addWidget(QLabel("Machine List"), 7, 0)
        machineListWidget = QLineEdit(self.settings.value("MachineList", ""))
        jobOptionsLayout.addWidget(machineListWidget, 7, 1, 1, 2)

        def browseMachineList():
            output = CallDeadlineCommand(
                ["-selectmachinelist",
                 str(machineListWidget.text())], False)
            output = output.replace("\r", "").replace("\n", "")
            if output != "Action was cancelled by user":
                machineListWidget.setText(output)

        machineListButton = QPushButton("Browse")
        machineListButton.pressed.connect(browseMachineList)
        jobOptionsLayout.addWidget(machineListButton, 7, 3)

        # Limits
        jobOptionsLayout.addWidget(QLabel("Limits"), 8, 0)
        limitsWidget = QLineEdit(self.settings.value("Limits", ""))
        jobOptionsLayout.addWidget(limitsWidget, 8, 1, 1, 2)

        def browseLimitList():
            output = CallDeadlineCommand(
                ["-selectlimitgroups",
                 str(limitsWidget.text())], False)
            output = output.replace("\r", "").replace("\n", "")
            if output != "Action was cancelled by user":
                limitsWidget.setText(output)

        limitsButton = QPushButton("Browse")
        limitsButton.pressed.connect(browseLimitList)
        jobOptionsLayout.addWidget(limitsButton, 8, 3)

        # On Job Complete
        jobOptionsLayout.addWidget(QLabel("On Job Complete"), 9, 0)
        onJobCompleteWidget = QComboBox()
        for option in onJobComplete:
            onJobCompleteWidget.addItem(option)

        defaultOption = self.settings.value("OnJobComplete", "Nothing")
        defaultIndex = onJobCompleteWidget.findText(defaultOption)
        if defaultIndex != -1:
            onJobCompleteWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(onJobCompleteWidget, 9, 1)

        # Submit Job As Suspended
        submitSuspendedWidget = QCheckBox("Submit Job As Suspended")
        submitSuspendedWidget.setChecked(
            strtobool(self.settings.value("SubmitSuspended", "False")))
        jobOptionsLayout.addWidget(submitSuspendedWidget, 9, 2)

        # Nuke Options
        nukeOptionsGroupBox = QGroupBox("Nuke Options")
        jobTabLayout.addWidget(nukeOptionsGroupBox)
        nukeOptionsLayout = QGridLayout()
        nukeOptionsGroupBox.setLayout(nukeOptionsLayout)

        # Version
        nukeOptionsLayout.addWidget(QLabel("Version"), 0, 0)
        versionWidget = QComboBox()
        for version in nukeVersions:
            versionWidget.addItem(version)

        defaultVersion = self.settings.value("Version", "7.0")
        defaultIndex = versionWidget.findText(defaultVersion)
        if defaultIndex != -1:
            versionWidget.setCurrentIndex(defaultIndex)

        nukeOptionsLayout.addWidget(versionWidget, 0, 1)

        # Submit Nuke Script File With Job
        submitScriptWidget = QCheckBox("Submit Nuke Script File With Job")
        submitScriptWidget.setChecked(
            strtobool(self.settings.value("SubmitScript", "False")))
        nukeOptionsLayout.addWidget(submitScriptWidget, 0, 2)

        # Build To Force
        nukeOptionsLayout.addWidget(QLabel("Build To Force"), 1, 0)
        buildWidget = QComboBox()
        for build in buildsToForce:
            buildWidget.addItem(build)

        defaultBuild = self.settings.value("Build", "None")
        defaultIndex = buildWidget.findText(defaultBuild)
        if defaultIndex != -1:
            buildWidget.setCurrentIndex(defaultIndex)

        nukeOptionsLayout.addWidget(buildWidget, 1, 1)

        # Render With NukeX
        useNukeXWidget = QCheckBox("Render With NukeX")
        useNukeXWidget.setChecked(
            strtobool(self.settings.value("UseNukeX", "False")))
        nukeOptionsLayout.addWidget(useNukeXWidget, 1, 2)

        # Max RAM Usage (MB)
        nukeOptionsLayout.addWidget(QLabel("Max RAM Usage (MB)"), 2, 0)
        memoryWidget = QSpinBox()
        memoryWidget.setRange(0, 5000)
        memoryWidget.setValue(int(self.settings.value("Memory", "0")))
        nukeOptionsLayout.addWidget(memoryWidget, 2, 1)

        # Continue On Error
        continueOnErrorWidget = QCheckBox("Continue On Error")
        continueOnErrorWidget.setChecked(
            strtobool(self.settings.value("ContinueOnError", "False")))
        nukeOptionsLayout.addWidget(continueOnErrorWidget, 2, 2)

        # Threads
        nukeOptionsLayout.addWidget(QLabel("Threads"), 3, 0)
        threadsWidget = QSpinBox()
        threadsWidget.setRange(0, 256)
        threadsWidget.setValue(int(self.settings.value("Threads", "0")))
        nukeOptionsLayout.addWidget(threadsWidget, 3, 1)

        # Use Batch Mode
        batchModeWidget = QCheckBox("Use Batch Mode")
        batchModeWidget.setChecked(
            strtobool(self.settings.value("BatchMode", "False")))
        nukeOptionsLayout.addWidget(batchModeWidget, 3, 2)

        # Frames Per Task
        nukeOptionsLayout.addWidget(QLabel("Frames Per Task"), 4, 0)
        framesPerTaskWidget = QSpinBox()
        framesPerTaskWidget.setRange(1, 1000000)
        framesPerTaskWidget.setValue(
            int(self.settings.value("FramesPerTask", "1")))
        nukeOptionsLayout.addWidget(framesPerTaskWidget, 4, 1)
        nukeOptionsLayout.addWidget(
            QLabel("(this only affects non-movie jobs)"), 4, 2)

        tabWidget.addTab(jobTab, "Job Options")

        # Button Box (Extra work required to get the custom ordering we want)
        self.pipelineToolStatusLabel.setAlignment(Qt.AlignRight
                                                  | Qt.AlignVCenter)
        pipelineToolStatus = self.retrievePipelineToolStatus()
        self.updatePipelineToolStatusLabel(pipelineToolStatus)

        integrationButton = QPushButton("Pipeline Tools")
        integrationButton.clicked.connect(self.OpenIntegrationWindow)

        submitButton = QPushButton("Submit")
        submitButton.clicked.connect(dialog.accept)
        submitButton.setDefault(True)

        cancelButton = QPushButton("Cancel")
        cancelButton.clicked.connect(dialog.reject)

        buttonGroupBox = QGroupBox()
        buttonLayout = QGridLayout()
        buttonLayout.setColumnStretch(
            0, 1)  # Makes the pipeline status label expand, not the buttons
        buttonGroupBox.setLayout(buttonLayout)
        buttonGroupBox.setAlignment(Qt.AlignRight)
        buttonGroupBox.setFlat(True)
        buttonLayout.addWidget(self.pipelineToolStatusLabel, 0, 0)
        buttonLayout.addWidget(integrationButton, 0, 1)
        buttonLayout.addWidget(submitButton, 0, 2)
        buttonLayout.addWidget(cancelButton, 0, 3)

        topLayout.addWidget(tabWidget)
        topLayout.addWidget(buttonGroupBox)

        # Show the dialog.
        result = (dialog.exec_() == QDialog.DialogCode.Accepted)
        if result:
            # Need to pass integration dir path to render task
            self.settings.setValue("IntegrationDir", self.integrationDir)

            self.settings.setValue("JobName", jobNameWidget.text())
            self.settings.setValue("Comment", commentWidget.text())
            self.settings.setValue("Department", departmentWidget.text())
            self.settings.setValue("Pool", poolWidget.currentText())
            self.settings.setValue("SecondaryPool",
                                   secondaryPoolWidget.currentText())
            self.settings.setValue("Group", groupWidget.currentText())
            self.settings.setValue("Priority", priorityWidget.value())
            self.settings.setValue("TaskTimeout", taskTimeoutWidget.value())
            self.settings.setValue("AutoTaskTimeout",
                                   str(autoTaskTimeoutWidget.isChecked()))
            self.settings.setValue("ConcurrentTasks",
                                   concurrentTasksWidget.value())
            self.settings.setValue("LimitConcurrentTasks",
                                   str(limitConcurrentTasksWidget.isChecked()))
            self.settings.setValue("MachineLimit", machineLimitWidget.value())
            self.settings.setValue("IsBlacklist",
                                   str(isBlacklistWidget.isChecked()))
            self.settings.setValue("MachineList", machineListWidget.text())
            self.settings.setValue("Limits", limitsWidget.text())
            self.settings.setValue("OnJobComplete",
                                   onJobCompleteWidget.currentText())
            self.settings.setValue("SubmitSuspended",
                                   str(submitSuspendedWidget.isChecked()))
            self.settings.setValue("Version", versionWidget.currentText())
            self.settings.setValue("SubmitScript",
                                   str(submitScriptWidget.isChecked()))
            self.settings.setValue("Build", buildWidget.currentText())
            self.settings.setValue("UseNukeX", str(useNukeXWidget.isChecked()))
            self.settings.setValue("FramesPerTask",
                                   framesPerTaskWidget.value())
            self.settings.setValue("ContinueOnError",
                                   str(continueOnErrorWidget.isChecked()))
            self.settings.setValue("Threads", threadsWidget.value())
            self.settings.setValue("BatchMode",
                                   str(batchModeWidget.isChecked()))
            self.settings.setValue("Memory", memoryWidget.value())

            print("Saving settings: " + self.settingsFile)
            self.settings.sync()
        else:
            print("Submission canceled")
            self.settings = None
            # Not sure if there is a better way to stop the export process. This works, but it leaves all the tasks
            # in the Queued state.
            self.setError("Submission was canceled")