class StartMineSchedDialog(QDialog):
    # 定义选择信号
    start_minesched_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory,
                 title: str):
        super(StartMineSchedDialog, self).__init__()
        self.config = config
        self.logger = logger
        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.start_minesched_button_group = QButtonGroup()
        self.start_minesched_button_group.setExclusive(True)
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.minescheds = []
        self.minesched_id = -1

    # 设置MineSched不同版本列表
    def set_minescheds(self, minescheds: list):
        self.minescheds = minescheds
        for _id, minesched in enumerate(self.minescheds):
            minesched_item = QRadioButton(minesched)
            self.start_minesched_button_group.addButton(minesched_item)
            self.start_minesched_button_group.setId(minesched_item, _id)
            if _id == 0:
                minesched_item.setChecked(True)
                self.minesched_id = 0
            self.layout.addWidget(minesched_item)
        self.start_minesched_button_group.buttonClicked.connect(
            self.start_minesched_change)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.layout.addWidget(self.buttons)

    # 如果单击ok按钮
    def accept(self):
        # 先关闭对话框,然后发送消息
        super(StartMineSchedDialog, self).accept()
        self.config.set_config('minesched', 'minesched_location',
                               self.minescheds[self.minesched_id])
        # 发送surpac启动消息
        self.start_minesched_signal.emit(self.minescheds[self.minesched_id])

    def start_minesched_change(self):
        self.minesched_id = self.start_minesched_button_group.checkedId()
class ChoiceSurpacDialog(QDialog):
    # 定义选择信号
    choices_surpac_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory,
                 title: str, surpacs: list):
        super(ChoiceSurpacDialog, self).__init__()
        self.config = config
        self.logger = logger

        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.surpacs = surpacs
        self.choice_surpac_button_group = QButtonGroup()
        self.choice_surpac_button_group.setExclusive(True)
        layout = QVBoxLayout()
        for surpac_id, choice in enumerate(surpacs):
            surpac_item = QRadioButton(choice)
            self.choice_surpac_button_group.addButton(surpac_item)
            self.choice_surpac_button_group.setId(surpac_item, surpac_id)
            if surpac_id == 0:
                surpac_item.setChecked(True)
                self.surpac_id = 0
            layout.addWidget(surpac_item)
        self.choice_surpac_button_group.buttonClicked.connect(
            self.choice_surpac_change)
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        layout.addWidget(self.buttons)
        self.setLayout(layout)

    def accept(self):
        # 先关闭对话框,然后发送消息
        super(ChoiceSurpacDialog, self).accept()
        if self.config.get('master',
                           'surpac_location') == self.surpacs[self.surpac_id]:
            pass
        else:
            self.choices_surpac_signal.emit(self.surpacs[self.surpac_id])
            self.config.set_config('master', 'surpac_location',
                                   self.surpacs[self.surpac_id])

    def choice_surpac_change(self):
        self.surpac_id = self.choice_surpac_button_group.checkedId()
class ChoiceLanguageDialog(QDialog):
    # 定义选择信号
    choices_language_dialog_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory, title: str, languages: list):
        super(ChoiceLanguageDialog, self).__init__()
        self.config = config
        self.logger = logger
        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.languages = languages
        self.choice_language_button_group = QButtonGroup()
        self.choice_language_button_group.setExclusive(True)
        layout = QVBoxLayout()
        for language_id, language in enumerate(languages):
            # 显示语言提示
            language_item = QRadioButton(language.split(':')[0])
            self.choice_language_button_group.addButton(language_item)
            self.choice_language_button_group.setId(language_item, language_id)
            if language_id == 0:
                language_item.setChecked(True)
                self.language_id = 0
            layout.addWidget(language_item)
        self.choice_language_button_group.buttonClicked.connect(self.language_change)
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        layout.addWidget(self.buttons)
        self.setLayout(layout)

    def accept(self):
        # 先关闭对话框,然后发送消息
        super(ChoiceLanguageDialog, self).accept()
        # 发送语言文件
        language = self.languages[self.language_id].split(':')[1]
        self.choices_language_dialog_signal.emit(language)
        self.config.set_config('master', 'surpac_language_cfg', language)

    def language_change(self):
        self.language_id = self.choice_language_button_group.checkedId()
Exemplo n.º 4
0
class SettingsWindow(QDialog):
    """Settings menu with two tabs for settings models and components"""
    def __init__(self, master, enigma_api):
        """
        Submenu for setting Enigma model and component settings
        :param master: Qt parent object
        :param enigma_api: {EnigmaAPI}
        """
        super().__init__(master)

        # QT WINDOW SETTINGS ===================================================

        main_layout = QVBoxLayout(self)
        self.__settings_frame = QFrame(self)
        self.__settings_layout = QHBoxLayout(self.__settings_frame)
        self.setWindowTitle("Settings")
        self.setLayout(main_layout)
        self.setFixedHeight(620)
        self.__reflector_group = []
        self.__rotor_frames = []

        # SAVE ATTRIBUTES ======================================================

        self.__enigma_api = enigma_api
        self.__rotor_selectors = []
        self.__ring_selectors = []
        self.__ukwd_window = UKWDSettingsWindow(self, enigma_api)

        # ROTORS AND REFLECTOR SETTINGS ========================================

        self.__ukwd_button = QPushButton("UKW-D pairs")
        self.__ukwd_button.clicked.connect(self.open_ukwd_window)

        # TAB WIDGET ===========================================================

        tab_widget = QTabWidget()

        self.__stacked_wikis = _ViewSwitcherWidget(self,
                                                   self.regenerate_for_model)
        tab_widget.addTab(self.__stacked_wikis, "Enigma model")
        tab_widget.addTab(self.__settings_frame, "Component settings")

        # BUTTONS ==============================================================

        button_frame = QFrame(self)
        button_layout = QHBoxLayout(button_frame)
        button_layout.setAlignment(Qt.AlignRight)

        self.__apply_btn = QPushButton("Apply")
        self.__apply_btn.clicked.connect(self.collect)

        storno = QPushButton("Storno")
        storno.clicked.connect(self.close)

        button_layout.addWidget(storno)
        button_layout.addWidget(self.__apply_btn)

        # SHOW WIDGETS =========================================================

        model_i = list(VIEW_DATA.keys()).index(self.__enigma_api.model())
        self.__stacked_wikis.select_model(model_i)
        self.__stacked_wikis.highlight(model_i)
        main_layout.addWidget(tab_widget)
        main_layout.addWidget(button_frame)

    def open_ukwd_window(self):
        """Opens UKWD wiring menu"""
        logging.info("Opened UKW-D wiring menu...")
        self.__ukwd_window.exec_()
        self.refresh_ukwd()

    def refresh_ukwd(self):
        """Refreshes Apply button according to criteria (UKW-D rotor must be
        selected to edit its settings)"""
        if self.__reflector_group.checkedButton().text() == "UKW-D":
            logging.info("UKW-D reflector selected, enabling UKW-D button...")

            if len(self.__ukwd_window.pairs()) != 12:
                self.__apply_btn.setDisabled(True)
                self.__apply_btn.setToolTip(
                    "Connect all 12 pairs in UKW-D wiring!")
            else:
                self.__apply_btn.setDisabled(False)
                self.__apply_btn.setToolTip(None)

            self.__ukwd_button.setDisabled(False)
            self.__ukwd_button.setToolTip(
                "Select the UKW-D rotor to edit settings")
            if len(self.__rotor_frames) == 4:  # IF THIN ROTORS
                logging.info("Disabling thin rotor radiobuttons...")
                self.__rotor_frames[0].setDisabled(True)
        else:
            logging.info(
                "UKW-D reflector deselected, disabling UKW-D button...")
            self.__apply_btn.setDisabled(False)
            self.__apply_btn.setToolTip(None)

            self.__ukwd_button.setDisabled(True)
            self.__ukwd_button.setToolTip(None)
            if len(self.__rotor_frames) == 4:  # IF THIN ROTORS
                logging.info("Enabling thin rotor radiobuttons...")
                self.__rotor_frames[0].setDisabled(False)

    def generate_components(self, reflectors, rotors, rotor_n, charset):
        """Generates currently displayed components based on Enigma model
        :param reflectors: {str} Reflector labels
        :param rotors: {[str, str, str]} Rotor labels
        :param rotor_n: {int} Number of rotors the Enigma model has
        """
        # REFLECTOR SETTINGS ===================================================
        spacing = 15
        style = "font-size: 18px; text-align: center;"

        reflector_frame = QFrame(self.__settings_frame)
        reflector_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)

        reflector_layout = QVBoxLayout(reflector_frame)
        reflector_layout.setSpacing(spacing)
        reflector_layout.addWidget(
            QLabel("REFLECTOR", reflector_frame, styleSheet=style),
            alignment=Qt.AlignHCenter,
        )

        self.__reflector_group = QButtonGroup(reflector_frame)
        reflector_layout.setAlignment(Qt.AlignTop)

        for i, model in enumerate(reflectors):
            radio = QRadioButton(model, reflector_frame)
            radio.setToolTip(
                "Reflector is an Enigma component that \nreflects "
                "letters from the rotors back to the lightboard")
            self.__reflector_group.addButton(radio)
            self.__reflector_group.setId(radio, i)
            reflector_layout.addWidget(radio, alignment=Qt.AlignTop)

        reflector_layout.addStretch()
        reflector_layout.addWidget(self.__ukwd_button)

        self.__reflector_group.button(0).setChecked(True)
        self.__reflector_group.buttonClicked.connect(self.refresh_ukwd)
        self.__settings_layout.addWidget(reflector_frame)

        # ROTOR SETTINGS =======================================================

        self.__rotor_selectors = []
        self.__ring_selectors = []
        self.__rotor_frames = []

        for rotor in range(rotor_n):
            rotor_frame = QFrame(self.__settings_frame)
            rotor_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
            rotor_layout = QVBoxLayout(rotor_frame)
            rotor_layout.setAlignment(Qt.AlignTop)
            rotor_layout.setSpacing(spacing)
            rotor_frame.setLayout(rotor_layout)

            # ROTOR RADIOS =====================================================

            label = QLabel(SELECTOR_LABELS[-rotor_n:][rotor],
                           rotor_frame,
                           styleSheet=style)
            label.setToolTip(SELECTOR_TOOLTIPS[-rotor_n:][rotor])

            rotor_layout.addWidget(label, alignment=Qt.AlignHCenter)

            button_group = QButtonGroup(rotor_frame)

            final_rotors = rotors

            if "Beta" in rotors:
                logging.info(
                    "Enigma M4 rotors detected, adjusting radiobuttons...")
                if rotor == 0:
                    final_rotors = ["Beta", "Gamma"]
                else:
                    final_rotors.remove("Beta")
                    final_rotors.remove("Gamma")

            for i, model in enumerate(final_rotors):
                radios = QRadioButton(model, rotor_frame)
                button_group.addButton(radios)
                button_group.setId(radios, i)
                rotor_layout.addWidget(radios, alignment=Qt.AlignTop)

            button_group.button(0).setChecked(True)

            # RINGSTELLUNG =====================================================

            combobox = QComboBox(rotor_frame)
            for i, label in enumerate(LABELS[:len(charset)]):
                combobox.addItem(label, i)

            h_rule = QFrame(rotor_frame)
            h_rule.setFrameShape(QFrame.HLine)
            h_rule.setFrameShadow(QFrame.Sunken)

            self.__ring_selectors.append(combobox)
            self.__rotor_selectors.append(button_group)

            rotor_layout.addStretch()
            rotor_layout.addWidget(h_rule)
            rotor_layout.addWidget(
                QLabel("RING SETTING", rotor_frame, styleSheet=style),
                alignment=Qt.AlignHCenter,
            )
            rotor_layout.addWidget(combobox)

            self.__settings_layout.addWidget(rotor_frame)
            self.__rotor_frames.append(rotor_frame)

    def clear_components(self):
        """Deletes all components settings widgets"""
        while True:
            child = self.__settings_layout.takeAt(0)
            if not child:
                break
            wgt = child.widget()
            wgt.deleteLater()
            del wgt

    def regenerate_for_model(self, new_model):
        """Regenerates component settings
        :param new_model: {str} Enigma model
        """
        logging.info("Regenerating component settings...")
        self.clear_components()

        reflectors = self.__enigma_api.model_labels(new_model)["reflectors"]
        rotors = self.__enigma_api.model_labels(new_model)["rotors"]
        rotor_n = self.__enigma_api.rotor_n(new_model)
        charset = HISTORICAL[new_model]["charset"]

        self.generate_components(reflectors, rotors[::], rotor_n, charset)

        defaults = self.__enigma_api.default_cfg(new_model, rotor_n)[1]
        for selected, i in zip(defaults, range(rotor_n)):
            self.__rotor_selectors[i].button(selected).setChecked(True)

        self.__ukwd_window.clear_pairs()
        self.__ukwd_window._old_pairs = {}
        if new_model == self.__enigma_api.model():
            self.load_from_api()
            self.__ukwd_window.refresh_pairs()
        self.refresh_ukwd()

    def load_from_api(self):
        """Loads displayed settings from shared EnigmaAPI instance"""
        logging.info("Loading component settings from EnigmaAPI...")

        model = self.__enigma_api.model()
        reflectors = self.__enigma_api.model_labels(model)["reflectors"]
        rotors = self.__enigma_api.model_labels(model)["rotors"]

        if "Beta" in rotors:
            rotors.remove("Beta")
            rotors.remove("Gamma")

        reflector_i = reflectors.index(self.__enigma_api.reflector())
        self.__reflector_group.button(reflector_i).setChecked(True)

        for i, rotor in enumerate(self.__enigma_api.rotors()):
            if (model == "Enigma M4"
                    and self.__enigma_api.reflector() != "UKW-D" and i == 0):
                rotor_i = ["Beta", "Gamma"].index(rotor)
            else:
                rotor_i = rotors.index(rotor)

            self.__rotor_selectors[i].button(rotor_i).setChecked(True)

        for i, ring in enumerate(self.__enigma_api.ring_settings()):
            self.__ring_selectors[i].setCurrentIndex(ring - 1)

    def collect(self):
        """Collects all selected settings for rotors and other components,
        applies them to the EnigmaAPI as new settings"""
        logging.info("Collecting new settings...")

        new_model = self.__stacked_wikis.currently_selected
        new_reflector = self.__reflector_group.checkedButton().text(
        )  # REFLECTOR CHOICES
        reflector_pairs = self.__ukwd_window.pairs()

        if new_reflector == "UKW-D" and new_model == "Enigma M4":
            new_rotors = [
                group.checkedButton().text()
                for group in self.__rotor_selectors[1:]
            ]
        else:
            new_rotors = [
                group.checkedButton().text()
                for group in self.__rotor_selectors
            ]

        ring_settings = [
            ring.currentIndex() + 1 for ring in self.__ring_selectors
        ]

        logging.info("EnigmaAPI state before applying settings:\n%s",
                     str(self.__enigma_api))

        if new_model != self.__enigma_api.model():
            self.__enigma_api.model(new_model)

        if new_reflector != self.__enigma_api.reflector():
            self.__enigma_api.reflector(new_reflector)

        if new_reflector == "UKW-D":
            self.__enigma_api.reflector_pairs(reflector_pairs)

        if new_rotors != self.__enigma_api.rotors():
            self.__enigma_api.rotors(new_rotors)

        if ring_settings != self.__enigma_api.ring_settings():
            self.__enigma_api.ring_settings(ring_settings)

        logging.info("EnigmaAPI state when closing settings:\n%s",
                     str(self.__enigma_api))

        self.close()

    def pairs(self):
        """Returns current UKW-D pairs for collection"""
        return self._pairs
Exemplo n.º 5
0
    def generate_components(self, reflectors, rotors, rotor_n, charset):
        """Generates currently displayed components based on Enigma model
        :param reflectors: {str} Reflector labels
        :param rotors: {[str, str, str]} Rotor labels
        :param rotor_n: {int} Number of rotors the Enigma model has
        """
        # REFLECTOR SETTINGS ===================================================
        spacing = 15
        style = "font-size: 18px; text-align: center;"

        reflector_frame = QFrame(self.__settings_frame)
        reflector_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)

        reflector_layout = QVBoxLayout(reflector_frame)
        reflector_layout.setSpacing(spacing)
        reflector_layout.addWidget(
            QLabel("REFLECTOR", reflector_frame, styleSheet=style),
            alignment=Qt.AlignHCenter,
        )

        self.__reflector_group = QButtonGroup(reflector_frame)
        reflector_layout.setAlignment(Qt.AlignTop)

        for i, model in enumerate(reflectors):
            radio = QRadioButton(model, reflector_frame)
            radio.setToolTip(
                "Reflector is an Enigma component that \nreflects "
                "letters from the rotors back to the lightboard")
            self.__reflector_group.addButton(radio)
            self.__reflector_group.setId(radio, i)
            reflector_layout.addWidget(radio, alignment=Qt.AlignTop)

        reflector_layout.addStretch()
        reflector_layout.addWidget(self.__ukwd_button)

        self.__reflector_group.button(0).setChecked(True)
        self.__reflector_group.buttonClicked.connect(self.refresh_ukwd)
        self.__settings_layout.addWidget(reflector_frame)

        # ROTOR SETTINGS =======================================================

        self.__rotor_selectors = []
        self.__ring_selectors = []
        self.__rotor_frames = []

        for rotor in range(rotor_n):
            rotor_frame = QFrame(self.__settings_frame)
            rotor_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
            rotor_layout = QVBoxLayout(rotor_frame)
            rotor_layout.setAlignment(Qt.AlignTop)
            rotor_layout.setSpacing(spacing)
            rotor_frame.setLayout(rotor_layout)

            # ROTOR RADIOS =====================================================

            label = QLabel(SELECTOR_LABELS[-rotor_n:][rotor],
                           rotor_frame,
                           styleSheet=style)
            label.setToolTip(SELECTOR_TOOLTIPS[-rotor_n:][rotor])

            rotor_layout.addWidget(label, alignment=Qt.AlignHCenter)

            button_group = QButtonGroup(rotor_frame)

            final_rotors = rotors

            if "Beta" in rotors:
                logging.info(
                    "Enigma M4 rotors detected, adjusting radiobuttons...")
                if rotor == 0:
                    final_rotors = ["Beta", "Gamma"]
                else:
                    final_rotors.remove("Beta")
                    final_rotors.remove("Gamma")

            for i, model in enumerate(final_rotors):
                radios = QRadioButton(model, rotor_frame)
                button_group.addButton(radios)
                button_group.setId(radios, i)
                rotor_layout.addWidget(radios, alignment=Qt.AlignTop)

            button_group.button(0).setChecked(True)

            # RINGSTELLUNG =====================================================

            combobox = QComboBox(rotor_frame)
            for i, label in enumerate(LABELS[:len(charset)]):
                combobox.addItem(label, i)

            h_rule = QFrame(rotor_frame)
            h_rule.setFrameShape(QFrame.HLine)
            h_rule.setFrameShadow(QFrame.Sunken)

            self.__ring_selectors.append(combobox)
            self.__rotor_selectors.append(button_group)

            rotor_layout.addStretch()
            rotor_layout.addWidget(h_rule)
            rotor_layout.addWidget(
                QLabel("RING SETTING", rotor_frame, styleSheet=style),
                alignment=Qt.AlignHCenter,
            )
            rotor_layout.addWidget(combobox)

            self.__settings_layout.addWidget(rotor_frame)
            self.__rotor_frames.append(rotor_frame)
Exemplo n.º 6
0
class AppearanceTab(QWidget):
    def __init__(self, parent):
        """Initialize the appearance tab
        """

        super(AppearanceTab, self).__init__(parent)

        self.prefs = parent.prefs

        # Default column width code
        col_width_label = QLabel("Default Column Width:")
        self.col_width_edit = QLineEdit(str(self.prefs['default_column_width']))
        self.col_width_edit.setMinimumWidth(40)
        self.col_width_edit.setMaximumWidth(100)
        validator = QIntValidator(10, 200, self)
        self.col_width_edit.setValidator(validator)

        # Visual style code
        style_label = QLabel("Visual Style of Application:")
        self.style_edit = QComboBox(self)
        self.style_edit.addItems(list(QStyleFactory.keys()))
        self.style_edit.setMaximumWidth(200)
        self.style_edit.setCurrentIndex(self.style_edit.findText(self.prefs['style']))

        # Units display code
        units_header_label = QLabel("Units Display:")
        self.header_units_check = QCheckBox('Show Units in Table Headers', self)
        checked_header = Qt.Checked if self.prefs['show_units_in_headers'] == 1 else Qt.Unchecked
        self.header_units_check.setCheckState(checked_header)
        self.cells_units_check = QCheckBox('Show Units in Table Cells', self)
        checked_cells = Qt.Checked if self.prefs['show_units_in_cells'] == 1 else Qt.Unchecked
        self.cells_units_check.setCheckState(checked_cells)

        # Handling of file options code
        default_handling_text = QLabel("Select how options saved directly within an IDF "
                                             "file are treated. See \"Save Options\" tab "
                                             "for the options in question.")
        default_handling_text.setWordWrap(True)
        default_handling_text.setMaximumWidth(450)
        self.button_force = QRadioButton("Force Session Options:", self)
        force_text = QLabel("Options from the current session will be used for all "
                                  "files, ignoring any options saved in the IDF file.")
        force_text.setWordWrap(True)
        force_text.setMaximumWidth(450)
        force_text.setMinimumHeight(30)
        force_text.setIndent(25)
        self.button_obey = QRadioButton("Obey IDF Options if Present:", self)
        obey_text = QLabel("Obey options saved in the IDF file. If none are "
                                 "present, use the current session's options.")
        obey_text.setWordWrap(True)
        obey_text.setMaximumWidth(450)
        obey_text.setMinimumHeight(30)
        obey_text.setIndent(25)

        # Handling of file options group box
        self.behaviour_group_box = QGroupBox("Handling of File-based Options")
        self.behaviour_group_box.setMinimumHeight(220)
        self.behaviour_group_box.setMinimumWidth(450)
        behaviour_box = QVBoxLayout()
        behaviour_box.addWidget(default_handling_text)
        behaviour_box.addWidget(self.button_force)
        behaviour_box.addWidget(force_text)
        behaviour_box.addSpacing(5)
        behaviour_box.addWidget(self.button_obey)
        behaviour_box.addWidget(obey_text)
        behaviour_box.addStretch(1)
        self.behaviour_group_box.setLayout(behaviour_box)

        self.behaviour_button_group = QButtonGroup(self)
        self.behaviour_button_group.addButton(self.button_force)
        self.behaviour_button_group.addButton(self.button_obey)
        self.behaviour_button_group.setId(self.button_force, 0)
        self.behaviour_button_group.setId(self.button_obey, 1)
        self.behaviour_button_group.button(self.prefs['obey_idf_options']).setChecked(True)

        # Main layout code
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(col_width_label)
        mainLayout.addWidget(self.col_width_edit)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(style_label)
        mainLayout.addWidget(self.style_edit)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(self.behaviour_group_box)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(units_header_label)
        mainLayout.addWidget(self.header_units_check)
        mainLayout.addWidget(self.cells_units_check)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)

        # Update settings
        self.behaviour_button_group.buttonClicked.connect(self.update)
        self.col_width_edit.textChanged.connect(self.update)
        self.style_edit.currentIndexChanged.connect(self.update)
        self.header_units_check.stateChanged.connect(self.update)
        self.cells_units_check.stateChanged.connect(self.update)

    def update(self):
        self.prefs['default_column_width'] = self.col_width_edit.text()
        self.prefs['style'] = self.style_edit.currentText()
        self.prefs['obey_idf_options'] = self.behaviour_button_group.checkedId()
        self.prefs['show_units_in_headers'] = 1 if self.header_units_check.checkState() else 0
        self.prefs['show_units_in_cells'] = 1 if self.cells_units_check.checkState() else 0