class ServerPlugin(Plugin): __icon__ = "fa.qrcode" __pname__ = "server" __views__ = ["slice_viewer"] __tab__ = "server" def __init__(self, parent=None): super().__init__(parent=parent) run_config = { "server_ip": "127.0.0.1", "server_port": "8134", "workspace_name": "test_hunt_d4b", "use_ssh": False, "ssh_host": "ws168.diamond.ac.uk", "ssh_port": "22", } workspace_config = { "dataset_name": "data", "datasets_dir": "/path/to/my/data/dir", "vol_fname": "myfile.h5", "workspace_name": "my_survos_workspace", "downsample_by": "1", } from survos2.server.config import cfg pipeline_config = dict(cfg) self.run_config = run_config self.workspace_config = workspace_config self.pipeline_config = pipeline_config self.server_process = None self.client_process = None self.layout = QVBoxLayout() tabwidget = QTabWidget() tab1 = QWidget() tab2 = QWidget() tabwidget.addTab(tab1, "Setup and Start Survos") self.create_workspace_button = QPushButton("Create workspace") tab1.layout = QVBoxLayout() tab1.setLayout(tab1.layout) chroot_fields = self.get_chroot_fields() tab1.layout.addWidget(chroot_fields) workspace_fields = self.get_workspace_fields() tab1.layout.addWidget(workspace_fields) self.setup_adv_run_fields() self.adv_run_fields.hide() run_fields = self.get_run_fields() tab1.layout.addWidget(run_fields) output_config_button = QPushButton("Save config") self.create_workspace_button.clicked.connect( self.create_workspace_clicked) output_config_button.clicked.connect(self.output_config_clicked) self.layout.addWidget(tabwidget) self.setGeometry(300, 300, 600, 400) self.setWindowTitle("SuRVoS Settings Editor") current_fpth = os.path.dirname(os.path.abspath(__file__)) self.setWindowIcon( QIcon(os.path.join(current_fpth, "resources", "logo.png"))) self.setLayout(self.layout) self.show() def get_chroot_fields(self): chroot_fields = QGroupBox("Set Main Directory for Storing Workspaces:") chroot_fields.setMaximumHeight(130) chroot_layout = QGridLayout() self.given_chroot_linedt = QLineEdit(CHROOT) chroot_layout.addWidget(self.given_chroot_linedt, 1, 0, 1, 2) set_chroot_button = QPushButton("Set Workspaces Root") chroot_layout.addWidget(set_chroot_button, 1, 2) chroot_fields.setLayout(chroot_layout) set_chroot_button.clicked.connect(self.set_chroot) return chroot_fields def get_workspace_fields(self): """Gets the QGroupBox that contains all the fields for setting up the workspace. Returns: PyQt5.QWidgets.GroupBox: GroupBox with workspace fields. """ select_data_button = QPushButton("Select") workspace_fields = QGroupBox("Create New Workspace:") wf_layout = QGridLayout() wf_layout.addWidget(QLabel("Data File Path:"), 0, 0) current_data_path = Path(self.workspace_config["datasets_dir"], self.workspace_config["vol_fname"]) self.data_filepth_linedt = QLineEdit(str(current_data_path)) wf_layout.addWidget(self.data_filepth_linedt, 1, 0, 1, 2) wf_layout.addWidget(select_data_button, 1, 2) wf_layout.addWidget(QLabel("HDF5 Internal Data Path:"), 2, 0, 1, 1) ws_dataset_name = self.workspace_config["dataset_name"] internal_h5_path = (ws_dataset_name if str(ws_dataset_name).startswith("/") else "/" + ws_dataset_name) self.h5_intpth_linedt = QLineEdit(internal_h5_path) wf_layout.addWidget(self.h5_intpth_linedt, 2, 1, 1, 1) wf_layout.addWidget(QLabel("Workspace Name:"), 3, 0) self.ws_name_linedt_1 = QLineEdit( self.workspace_config["workspace_name"]) wf_layout.addWidget(self.ws_name_linedt_1, 3, 1) wf_layout.addWidget(QLabel("Downsample Factor:"), 4, 0) self.downsample_spinner = QSpinBox() self.downsample_spinner.setRange(1, 10) self.downsample_spinner.setSpecialValueText("None") self.downsample_spinner.setMaximumWidth(60) self.downsample_spinner.setValue( int(self.workspace_config["downsample_by"])) wf_layout.addWidget(self.downsample_spinner, 4, 1, 1, 1) # ROI self.setup_roi_fields() wf_layout.addWidget(self.roi_fields, 4, 2, 1, 2) self.roi_fields.hide() wf_layout.addWidget(self.create_workspace_button, 5, 0, 1, 3) workspace_fields.setLayout(wf_layout) select_data_button.clicked.connect(self.launch_data_loader) return workspace_fields def setup_roi_fields(self): """Sets up the QGroupBox that displays the ROI dimensions, if selected.""" self.roi_fields = QGroupBox("ROI:") roi_fields_layout = QHBoxLayout() # z roi_fields_layout.addWidget(QLabel("z:"), 0) self.zstart_roi_val = QLabel("0") roi_fields_layout.addWidget(self.zstart_roi_val, 1) roi_fields_layout.addWidget(QLabel("-"), 2) self.zend_roi_val = QLabel("0") roi_fields_layout.addWidget(self.zend_roi_val, 3) # y roi_fields_layout.addWidget(QLabel("y:"), 4) self.ystart_roi_val = QLabel("0") roi_fields_layout.addWidget(self.ystart_roi_val, 5) roi_fields_layout.addWidget(QLabel("-"), 6) self.yend_roi_val = QLabel("0") roi_fields_layout.addWidget(self.yend_roi_val, 7) # x roi_fields_layout.addWidget(QLabel("x:"), 8) self.xstart_roi_val = QLabel("0") roi_fields_layout.addWidget(self.xstart_roi_val, 9) roi_fields_layout.addWidget(QLabel("-"), 10) self.xend_roi_val = QLabel("0") roi_fields_layout.addWidget(self.xend_roi_val, 11) self.roi_fields.setLayout(roi_fields_layout) def setup_adv_run_fields(self): """Sets up the QGroupBox that displays the advanced optiona for starting SuRVoS2.""" self.adv_run_fields = QGroupBox("Advanced Run Settings:") adv_run_layout = QGridLayout() adv_run_layout.addWidget(QLabel("Server IP Address:"), 0, 0) self.server_ip_linedt = QLineEdit(self.run_config["server_ip"]) adv_run_layout.addWidget(self.server_ip_linedt, 0, 1) adv_run_layout.addWidget(QLabel("Server Port:"), 1, 0) self.server_port_linedt = QLineEdit(self.run_config["server_port"]) adv_run_layout.addWidget(self.server_port_linedt, 1, 1) # SSH Info self.ssh_button = QRadioButton("Use SSH") self.ssh_button.setAutoExclusive(False) adv_run_layout.addWidget(self.ssh_button, 0, 2) ssh_flag = self.run_config.get("use_ssh", False) if ssh_flag: self.ssh_button.setChecked(True) self.ssh_button.toggled.connect(self.toggle_ssh) self.adv_ssh_fields = QGroupBox("SSH Settings:") adv_ssh_layout = QGridLayout() adv_ssh_layout.setColumnStretch(2, 2) ssh_host_label = QLabel("Host") self.ssh_host_linedt = QLineEdit(self.run_config.get("ssh_host", "")) adv_ssh_layout.addWidget(ssh_host_label, 0, 0) adv_ssh_layout.addWidget(self.ssh_host_linedt, 0, 1, 1, 2) ssh_user_label = QLabel("Username") self.ssh_username_linedt = QLineEdit(self.get_login_username()) adv_ssh_layout.addWidget(ssh_user_label, 1, 0) adv_ssh_layout.addWidget(self.ssh_username_linedt, 1, 1, 1, 2) ssh_port_label = QLabel("Port") self.ssh_port_linedt = QLineEdit(self.run_config.get("ssh_port", "")) adv_ssh_layout.addWidget(ssh_port_label, 2, 0) adv_ssh_layout.addWidget(self.ssh_port_linedt, 2, 1, 1, 2) self.adv_ssh_fields.setLayout(adv_ssh_layout) #adv_run_layout.addWidget(self.adv_ssh_fields, 1, 2, 2, 5) self.adv_run_fields.setLayout(adv_run_layout) def get_run_fields(self): """Gets the QGroupBox that contains the fields for starting SuRVoS. Returns: PyQt5.QWidgets.GroupBox: GroupBox with run fields. """ self.run_button = QPushButton("Start Server") self.stop_button = QPushButton("Stop Server") self.existing_button = QPushButton("Use Existing Server") advanced_button = QRadioButton("Advanced") run_fields = QGroupBox("Run SuRVoS:") run_layout = QGridLayout() workspaces = os.listdir(CHROOT) self.workspaces_list = ComboBox() for s in workspaces: self.workspaces_list.addItem(key=s) run_layout.addWidget(QLabel("Workspace Name:"), 0, 0) self.ws_name_linedt_2 = QLineEdit( self.workspace_config["workspace_name"]) self.ws_name_linedt_2.setAlignment(Qt.AlignLeft) self.workspaces_list.setLineEdit(self.ws_name_linedt_2) # run_layout.addWidget(self.ws_name_linedt_2, 0, 1) run_layout.addWidget(self.workspaces_list, 0, 1) run_layout.addWidget(advanced_button, 1, 0) run_layout.addWidget(self.adv_run_fields, 2, 1) run_layout.addWidget(self.run_button, 3, 0, 1, 3) run_layout.addWidget(self.stop_button, 4, 0, 1, 3) run_layout.addWidget(self.existing_button, 5, 0, 1, 3) run_fields.setLayout(run_layout) advanced_button.toggled.connect(self.toggle_advanced) self.run_button.clicked.connect(self.run_clicked) self.stop_button.clicked.connect(self.stop_clicked) self.existing_button.clicked.connect(self.existing_clicked) return run_fields def get_login_username(self): try: user = getpass.getuser() except Exception: user = "" return user def refresh_chroot(self): workspaces = os.listdir(DataModel.g.CHROOT) self.workspaces_list.clear() for s in workspaces: self.workspaces_list.addItem(key=s) @pyqtSlot() def set_chroot(self): CHROOT = self.given_chroot_linedt.text() Config.update({"model": {"chroot": CHROOT}}) logger.debug(f"Setting CHROOT to {CHROOT}") DataModel.g.CHROOT = CHROOT self.refresh_chroot() @pyqtSlot() def launch_data_loader(self): """Load the dialog box widget to select data with data preview window and ROI selection.""" path = None int_h5_pth = None dialog = LoadDataDialog(self) result = dialog.exec_() self.roi_limits = None if result == QDialog.Accepted: path = dialog.winput.path.text() int_h5_pth = dialog.int_h5_pth.text() down_factor = dialog.downsample_spinner.value() if path and int_h5_pth: self.data_filepth_linedt.setText(path) self.h5_intpth_linedt.setText(int_h5_pth) self.downsample_spinner.setValue(down_factor) if dialog.roi_changed: self.roi_limits = tuple(map(str, dialog.get_roi_limits())) self.roi_fields.show() self.update_roi_fields_from_dialog() else: self.roi_fields.hide() def update_roi_fields_from_dialog(self): """Updates the ROI fields in the main window.""" x_start, x_end, y_start, y_end, z_start, z_end = self.roi_limits self.xstart_roi_val.setText(x_start) self.xend_roi_val.setText(x_end) self.ystart_roi_val.setText(y_start) self.yend_roi_val.setText(y_end) self.zstart_roi_val.setText(z_start) self.zend_roi_val.setText(z_end) @pyqtSlot() def toggle_advanced(self): """Controls displaying/hiding the advanced run fields on radio button toggle.""" rbutton = self.sender() if rbutton.isChecked(): self.adv_run_fields.show() else: self.adv_run_fields.hide() @pyqtSlot() def toggle_ssh(self): """Controls displaying/hiding the SSH fields on radio button toggle.""" rbutton = self.sender() if rbutton.isChecked(): self.adv_ssh_fields.show() else: self.adv_ssh_fields.hide() @pyqtSlot() def create_workspace_clicked(self): """Performs checks and coordinates workspace creation on button press.""" logger.debug("Creating workspace: ") # Set the path to the data file vol_path = Path(self.data_filepth_linedt.text()) if not vol_path.is_file(): err_str = f"No data file exists at {vol_path}!" logger.error(err_str) self.button_feedback_response(err_str, self.create_workspace_button, "maroon") else: self.workspace_config["datasets_dir"] = str(vol_path.parent) self.workspace_config["vol_fname"] = str(vol_path.name) dataset_name = self.h5_intpth_linedt.text() self.workspace_config["dataset_name"] = str(dataset_name).strip( "/") # Set the workspace name ws_name = self.ws_name_linedt_1.text() self.workspace_config["workspace_name"] = ws_name # Set the downsample factor ds_factor = self.downsample_spinner.value() self.workspace_config["downsample_by"] = ds_factor # Set the ROI limits if they exist if self.roi_limits: self.workspace_config["roi_limits"] = self.roi_limits try: response = init_ws(self.workspace_config) _, error = response if not error: self.button_feedback_response( "Workspace created sucessfully", self.create_workspace_button, "green", ) # Update the workspace name in the 'Run' section self.ws_name_linedt_2.setText(self.ws_name_linedt_1.text()) except WorkspaceException as e: logger.exception(e) self.button_feedback_response(str(e), self.create_workspace_button, "maroon") self.refresh_chroot() def button_feedback_response(self, message, button, colour_str, timeout=2): """Changes button colour and displays feedback message for a limited time period. Args: message (str): Message to display in button. button (PyQt5.QWidgets.QBushButton): The button to manipulate. colour_str (str): The standard CSS colour string or hex code describing the colour to change the button to. """ timeout *= 1000 msg_old = button.text() col_old = button.palette().button().color txt_col_old = button.palette().buttonText().color button.setText(message) button.setStyleSheet(f"background-color: {colour_str}; color: white") timer = QTimer() timer.singleShot( timeout, lambda: self.reset_button(button, msg_old, col_old, txt_col_old)) @pyqtSlot() def reset_button(self, button, msg_old, col_old, txt_col_old): """Sets a button back to its original display settings. Args: button (PyQt5.QWidgets.QBushButton): The button to manipulate. msg_old (str): Message to display in button. col_old (str): The standard CSS colour string or hex code describing the colour to change the button to. txt_col_old (str): The standard CSS colour string or hex code describing the colour to change the button text to. """ button.setStyleSheet(f"background-color: {col_old().name()}") button.setStyleSheet(f"color: {txt_col_old().name()}") button.setText(msg_old) button.update() @pyqtSlot() def output_config_clicked(self): """Outputs pipeline config YAML file on button click.""" out_fname = "pipeline_cfg.yml" logger.debug(f"Outputting pipeline config: {out_fname}") with open(out_fname, "w") as outfile: yaml.dump(self.pipeline_config, outfile, default_flow_style=False, sort_keys=False) def get_ssh_params(self): ssh_host = self.ssh_host_linedt.text() ssh_user = self.ssh_username_linedt.text() ssh_port = int(self.ssh_port_linedt.text()) return ssh_host, ssh_user, ssh_port def start_server_over_ssh(self): params = self.get_ssh_params() if not all(params): logger.error( "Not all SSH parameters given! Not connecting to SSH.") pass ssh_host, ssh_user, ssh_port = params # Pop up dialog to ask for password text, ok = QInputDialog.getText(None, "Login", f"Password for {ssh_user}@{ssh_host}", QLineEdit.Password) if ok and text: self.ssh_worker = SSHWorker(params, text, self.run_config) self.ssh_thread = QThread(self) self.ssh_worker.moveToThread(self.ssh_thread) self.ssh_worker.button_message_signal.connect( self.send_msg_to_run_button) self.ssh_worker.error_signal.connect(self.on_ssh_error) self.ssh_worker.finished.connect(self.start_client) self.ssh_worker.update_ip_linedt_signal.connect( self.update_ip_linedt) self.ssh_thread.started.connect( self.ssh_worker.start_server_over_ssh) self.ssh_thread.start() def closeEvent(self, event): reply = QMessageBox.question( self, "Quit", "Are you sure you want to quit? " "The server will be stopped.", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ) if reply == QMessageBox.Yes: event.accept() else: event.ignore() @pyqtSlot() def on_ssh_error(self): self.ssh_error = True @pyqtSlot(str) def update_ip_linedt(self, ip): self.server_ip_linedt.setText(ip) @pyqtSlot(list) def send_msg_to_run_button(self, param_list): self.button_feedback_response(param_list[0], self.run_button, param_list[1], param_list[2]) @pyqtSlot() def stop_clicked(self): logger.debug("Stopping server") if self.server_process is not None: self.server_process.kill() @pyqtSlot() def run_clicked(self): """Starts SuRVoS2 server and client as subprocesses when 'Run' button pressed. Raises: Exception: If survos.py not found. """ with progress(total=3) as pbar: pbar.set_description("Starting server...") pbar.update(1) self.ssh_error = ( False # Flag which will be set to True if there is an SSH error ) command_dir = os.path.abspath(os.path.dirname(__file__)) # os.getcwd() # Set current dir to survos root from pathlib import Path command_dir = Path( command_dir).absolute().parent.parent.parent.resolve() os.chdir(command_dir) self.script_fullname = os.path.join(command_dir, "survos.py") if not os.path.isfile(self.script_fullname): raise Exception("{}: Script not found".format( self.script_fullname)) # Retrieve the parameters from the fields TODO: Put some error checking in self.run_config["workspace_name"] = self.ws_name_linedt_2.text() self.run_config["server_port"] = self.server_port_linedt.text() # Temporary measure to check whether the workspace exists or not full_ws_path = os.path.join(Config["model.chroot"], self.run_config["workspace_name"]) if not os.path.isdir(full_ws_path): logger.error( f"No workspace can be found at {full_ws_path}, Not starting SuRVoS." ) self.button_feedback_response( f"Workspace {self.run_config['workspace_name']} does not appear to exist!", self.run_button, "maroon", ) return pbar.update(1) # Try some fancy SSH stuff here if self.ssh_button.isChecked(): self.start_server_over_ssh() else: self.server_process = subprocess.Popen([ "python", self.script_fullname, "start_server", self.run_config["workspace_name"], self.run_config["server_port"], DataModel.g.CHROOT, ]) try: outs, errs = self.server_process.communicate(timeout=10) print(f"OUTS: {outs, errs}") except subprocess.TimeoutExpired: pass # self.start_client() logger.info(f"setting remote: {self.server_port_linedt.text()}") remote_ip_port = "127.0.0.1:" + self.server_port_linedt.text() logger.info(f"setting remote: {remote_ip_port}") resp = Launcher.g.set_remote(remote_ip_port) logger.info(f"Response from server to setting remote: {resp}") cfg.ppw.clientEvent.emit({ "source": "server_tab", "data": "set_workspace", "workspace": self.ws_name_linedt_2.text(), }) cfg.ppw.clientEvent.emit({ "source": "panel_gui", "data": "refresh", "value": None }) #cfg.ppw.clientEvent.emit({'data' : 'view_feature', 'feature_id' : '001_raw'}) pbar.update(1) @pyqtSlot() def existing_clicked(self): ssh_ip = self.server_ip_linedt.text() remote_ip_port = ssh_ip + ":" + self.server_port_linedt.text() logger.info(f"setting remote: {remote_ip_port}") resp = Launcher.g.set_remote(remote_ip_port) logger.info(f"Response from server to setting remote: {resp}") cfg.ppw.clientEvent.emit({ "source": "server_tab", "data": "set_workspace", "workspace": self.ws_name_linedt_2.text(), }) cfg.ppw.clientEvent.emit({ "source": "panel_gui", "data": "refresh", "value": None }) def start_client(self): if not self.ssh_error: self.button_feedback_response("Starting Client.", self.run_button, "green", 7) self.run_config["server_ip"] = self.server_ip_linedt.text() self.client_process = subprocess.Popen([ "python", self.script_fullname, "nu_gui", self.run_config["workspace_name"], str(self.run_config["server_ip"]) + ":" + str(self.run_config["server_port"]), ])
class MorphologyLauncher(QWidget): def __init__(self, parent): super().__init__() self.setWindowTitle(config.thisTranslation["cp7"]) self.parent = parent self.bookList = BibleBooks.getStandardBookAbbreviations() self.setupUI() def setupUI(self): mainLayout = QVBoxLayout() subLayout = QHBoxLayout() subLayout.addWidget(self.searchFieldWidget()) button = QPushButton("Search") button.clicked.connect(self.searchMorphology) subLayout.addWidget(button) mainLayout.addLayout(subLayout) subLayout = QHBoxLayout() subLayout.addWidget(QLabel("Start:")) self.startBookCombo = QComboBox() subLayout.addWidget(self.startBookCombo) self.startBookCombo.addItems(self.bookList) self.startBookCombo.setCurrentIndex(0) subLayout.addWidget(QLabel("End:")) self.endBookCombo = QComboBox() subLayout.addWidget(self.endBookCombo) self.endBookCombo.addItems(self.bookList) self.endBookCombo.setCurrentIndex(65) subLayout.addWidget(QLabel(" ")) button = QPushButton("Entire Bible") button.clicked.connect(lambda: self.selectBookCombos(0, 65)) subLayout.addWidget(button) button = QPushButton("Current Book") button.clicked.connect(lambda: self.selectBookCombos(config.mainB-1, config.mainB-1)) subLayout.addWidget(button) button = QPushButton("OT") button.clicked.connect(lambda: self.selectBookCombos(0, 38)) subLayout.addWidget(button) button = QPushButton("NT") button.clicked.connect(lambda: self.selectBookCombos(39, 65)) subLayout.addWidget(button) button = QPushButton("Gospels") button.clicked.connect(lambda: self.selectBookCombos(39, 42)) subLayout.addWidget(button) subLayout.addStretch() mainLayout.addLayout(subLayout) subLayout = QHBoxLayout() self.searchTypeBox = QGroupBox("Type") layout = QVBoxLayout() self.strongsRadioButton = QRadioButton("Lexical") self.strongsRadioButton.setToolTip("G2424") self.strongsRadioButton.toggled.connect(lambda checked, mode="Lexical": self.searchTypeChanged(checked, mode)) self.strongsRadioButton.setChecked(True) layout.addWidget(self.strongsRadioButton) radioButton = QRadioButton("Word") radioButton.setToolTip("Ἰησοῦς") radioButton.toggled.connect(lambda checked, mode="Word": self.searchTypeChanged(checked, mode)) layout.addWidget(radioButton) radioButton = QRadioButton("Gloss") radioButton.setToolTip("Jesus") radioButton.toggled.connect(lambda checked, mode="Gloss": self.searchTypeChanged(checked, mode)) layout.addWidget(radioButton) # radioButton = QRadioButton("Transliteration") # radioButton.setToolTip("Iēsous") # radioButton.toggled.connect(lambda checked, mode="Transliteration": self.searchTypeChanged(checked, mode)) # layout.addWidget(radioButton) self.searchTypeBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.searchTypeBox) languageList = ["Greek", "Hebrew"] self.languageBox = QGroupBox("Language") layout = QVBoxLayout() for count, lang in enumerate(languageList): button = QRadioButton(lang) button.toggled.connect(lambda checked, mode=lang: self.languageChanged(checked, mode)) layout.addWidget(button) if count == 0: self.greekButton = button self.languageBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.languageBox) posList = ["Adjective", "Adverb", "Article", "Conjunction", "Interjection", "Noun", "Participle", "Preposition", "Pronoun", "Verb", ""] self.posCheckBoxes = [] self.partOfSpeechBox = QGroupBox("Part of speech") layout = QVBoxLayout() for count, pos in enumerate(posList): button = QRadioButton(pos) button.toggled.connect(lambda checked, mode=pos: self.partOfSpeechChanged(checked, mode)) layout.addWidget(button) if count == 0: self.nounButton = button self.partOfSpeechBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.partOfSpeechBox) greekCaseList = ["Accusative", "Dative", "Genitive", "Nominative", "Vocative"] self.greekCaseCheckBoxes = [] self.greekCaseBox = QGroupBox("Case") self.greekCaseBox.hide() layout = QVBoxLayout() for case in greekCaseList: checkbox = QCheckBox(case) layout.addWidget(checkbox) self.greekCaseCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, case=case: self.checkBoxChanged(checked, case, self.greekCaseCheckBoxes)) self.greekCaseBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.greekCaseBox) greekTenseList = ["Aorist", "Future", "Imperfect", "Perfect", "Pluperfect", "Present"] self.greekTenseCheckBoxes = [] self.greekTenseBox = QGroupBox("Tense") self.greekTenseBox.hide() layout = QVBoxLayout() for tense in greekTenseList: checkbox = QCheckBox(tense) layout.addWidget(checkbox) self.greekTenseCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, tense=tense: self.checkBoxChanged(checked, tense, self.greekTenseCheckBoxes)) self.greekTenseBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.greekTenseBox) voiceList = ["Active", "Middle", "Passive"] self.voiceCheckBoxes = [] self.voiceBox = QGroupBox("Voice") self.voiceBox.hide() layout = QVBoxLayout() for voice in voiceList: checkbox = QCheckBox(voice) layout.addWidget(checkbox) self.voiceCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, voice=voice: self.checkBoxChanged(checked, voice, self.voiceCheckBoxes)) self.voiceBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.voiceBox) greekMoodList = ["Imperative", "Indicative", "Optative", "Subjunctive"] self.greekMoodCheckBoxes = [] self.greekMoodBox = QGroupBox("Mood") self.greekMoodBox.hide() layout = QVBoxLayout() for mood in greekMoodList: checkbox = QCheckBox(mood) layout.addWidget(checkbox) self.greekMoodCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, mood=mood: self.checkBoxChanged(checked, mood, self.greekMoodCheckBoxes)) self.greekMoodBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.greekMoodBox) hebrewStateList = ["Construct", "Absolute"] self.hebrewStateCheckBoxes = [] self.hebrewStateBox = QGroupBox("State") self.hebrewStateBox.hide() layout = QVBoxLayout() for state in hebrewStateList: checkbox = QCheckBox(state) layout.addWidget(checkbox) self.hebrewStateCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, state=state: self.checkBoxChanged(checked, state, self.hebrewStateCheckBoxes)) self.hebrewStateBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.hebrewStateBox) hebrewStateList = ["Construct", "Absolute"] self.hebrewStateCheckBoxes = [] self.hebrewStateBox = QGroupBox("State") self.hebrewStateBox.hide() layout = QVBoxLayout() for stem in hebrewStateList: checkbox = QCheckBox(stem) layout.addWidget(checkbox) self.hebrewStateCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, stem=stem: self.checkBoxChanged(checked, stem, self.hebrewStateCheckBoxes)) self.hebrewStateBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.hebrewStateBox) hebrewPatternList = ["Hif‘il", "Hitpa“el", "Nif‘al", "Pi“el", "Pu“al", "Qal", "Wayyiqtol"] self.hebrewPatternCheckBoxes = [] self.hebrewPatternBox = QGroupBox("State") self.hebrewPatternBox.hide() layout = QVBoxLayout() for stem in hebrewPatternList: checkbox = QCheckBox(stem) layout.addWidget(checkbox) self.hebrewPatternCheckBoxes.append(checkbox) # checkbox.stateChanged.connect(lambda checked, stem=stem: self.checkBoxChanged(checked, stem, self.hebrewPatternCheckBoxes)) self.hebrewPatternBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.hebrewPatternBox) personList = ["First", "Second", "Third"] self.personCheckBoxes = [] self.personBox = QGroupBox("Person") self.personBox.hide() layout = QVBoxLayout() for person in personList: checkbox = QCheckBox(person) layout.addWidget(checkbox) self.personCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, person=person: self.checkBoxChanged(checked, person, self.personCheckBoxes)) self.personBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.personBox) numberList = ["Singular", "Plural", "Dual"] self.numberCheckBoxes = [] self.numberBox = QGroupBox("Number") self.numberBox.hide() layout = QVBoxLayout() for number in numberList: checkbox = QCheckBox(number) layout.addWidget(checkbox) self.numberCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, number=number: self.checkBoxChanged(checked, number, self.numberCheckBoxes)) self.numberBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.numberBox) genderList = ["Masculine", "Feminine", "Neuter"] self.genderCheckBoxes = [] self.genderBox = QGroupBox("Gender") self.genderBox.hide() layout = QVBoxLayout() for gender in genderList: checkbox = QCheckBox(gender) layout.addWidget(checkbox) self.genderCheckBoxes.append(checkbox) checkbox.stateChanged.connect(lambda checked, gender=gender: self.checkBoxChanged(checked, gender, self.genderCheckBoxes)) self.genderBox.setLayout(layout) layout.addStretch() subLayout.addWidget(self.genderBox) # TODO: hebrewList = ["Absolute", "", "Infinitive", "Pronominal", ""] self.spacerBox1 = QGroupBox(" ") layout = QVBoxLayout() layout.addStretch() self.spacerBox1.setLayout(layout) subLayout.addWidget(self.spacerBox1) self.spacerBox2 = QGroupBox(" ") layout = QVBoxLayout() layout.addStretch() self.spacerBox2.setLayout(layout) subLayout.addWidget(self.spacerBox2) self.spacerBox3 = QGroupBox(" ") layout = QVBoxLayout() layout.addStretch() self.spacerBox3.setLayout(layout) subLayout.addWidget(self.spacerBox3) self.spacerBox4 = QGroupBox(" ") layout = QVBoxLayout() layout.addStretch() self.spacerBox4.setLayout(layout) subLayout.addWidget(self.spacerBox4) self.spacerBox5 = QGroupBox(" ") layout = QVBoxLayout() layout.addStretch() self.spacerBox5.setLayout(layout) subLayout.addWidget(self.spacerBox5) mainLayout.addLayout(subLayout) mainLayout.addStretch() self.setLayout(mainLayout) self.greekButton.setChecked(True) self.nounButton.setChecked(True) def selectBookCombos(self, start, end): self.startBookCombo.setCurrentIndex(start) self.endBookCombo.setCurrentIndex(end) def searchTypeChanged(self, checked, type): self.type = type def searchFieldWidget(self): self.searchField = QLineEdit() self.searchField.setClearButtonEnabled(True) self.searchField.setToolTip(config.thisTranslation["menu5_searchItems"]) self.searchField.returnPressed.connect(self.searchMorphology) return self.searchField def checkBoxChanged(self, state, value, checkboxes): if int(state) > 0: for checkbox in checkboxes: if checkbox.isChecked() and value != checkbox.text(): checkbox.setChecked(False) def languageChanged(self, checked, language): if checked: self.language = language self.updateAllCheckboxes() def partOfSpeechChanged(self, checked, pos): if checked: self.pos = pos self.updateAllCheckboxes() def updateAllCheckboxes(self): self.genderBox.hide() self.numberBox.hide() self.greekCaseBox.hide() self.personBox.hide() self.greekTenseBox.hide() self.greekMoodBox.hide() self.voiceBox.hide() self.hebrewStateBox.hide() self.hebrewPatternBox.hide() self.spacerBox1.hide() self.spacerBox2.hide() self.spacerBox3.hide() self.spacerBox4.hide() self.spacerBox5.hide() if self.language == "Greek": if self.pos in ("Noun", "Adjective"): self.greekCaseBox.show() self.numberBox.show() self.genderBox.show() self.spacerBox4.show() self.spacerBox5.show() elif self.pos in ("Pronoun", "Article"): self.greekCaseBox.show() self.numberBox.show() self.genderBox.show() self.personBox.show() self.spacerBox5.show() elif self.pos == "Verb": self.greekTenseBox.show() self.voiceBox.show() self.greekMoodBox.show() self.personBox.show() self.numberBox.show() elif self.pos == "Adverb": self.greekCaseBox.show() self.numberBox.show() self.genderBox.show() self.spacerBox4.show() self.spacerBox5.show() else: self.spacerBox1.show() self.spacerBox2.show() self.spacerBox3.show() self.spacerBox4.show() self.spacerBox5.show() else: if self.pos in ("Noun", "Adjective", "Preposition", "Pronoun"): self.numberBox.show() self.genderBox.show() self.hebrewStateBox.show() self.spacerBox4.show() self.spacerBox5.show() elif self.pos in ("Verb", "Adverb"): self.personBox.show() self.genderBox.show() self.numberBox.show() self.hebrewStateBox.show() self.hebrewPatternBox.show() else: self.spacerBox1.show() self.spacerBox2.show() self.spacerBox3.show() self.spacerBox4.show() self.spacerBox5.show() def searchMorphology(self): searchTerm = self.searchField.text() if len(searchTerm) > 1: morphologyList = [] morphologyList.append(self.pos) if self.language == "Greek": if self.pos in ("Noun", "Adjective"): checkBoxList = [self.greekCaseCheckBoxes, self.numberCheckBoxes, self.genderCheckBoxes] elif self.pos == ("Pronoun", "Article"): checkBoxList = [self.greekCaseCheckBoxes, self.numberCheckBoxes, self.genderCheckBoxes, self.personCheckBoxes] elif self.pos == "Verb": checkBoxList = [self.greekTenseCheckBoxes, self.voiceCheckBoxes, self.greekMoodCheckBoxes, self.personCheckBoxes, self.numberCheckBoxes] elif self.pos == "Adverb": checkBoxList = [self.greekCaseCheckBoxes, self.numberCheckBoxes, self.genderCheckBoxes] else: checkBoxList = [] else: if self.pos in ("Noun", "Adjective", "Preposition", "Pronoun"): checkBoxList = [self.numberCheckBoxes, self.genderCheckBoxes, self.hebrewStateCheckBoxes] elif self.pos in ("Verb", "Adverb"): checkBoxList = [self.personCheckBoxes, self.genderCheckBoxes, self.numberCheckBoxes, self.hebrewStateCheckBoxes, self.hebrewPatternCheckBoxes] else: checkBoxList = [] for checkBoxes in checkBoxList: for checkbox in checkBoxes: if checkbox.isChecked(): morphologyList.append(checkbox.text()) morphology = ",".join(morphologyList) startBook = self.startBookCombo.currentIndex() + 1 endBook = self.endBookCombo.currentIndex() + 1 if endBook < startBook: endBook = startBook if self.type == "Lexical": command = "SEARCHMORPHOLOGYBYLEX:::{0}:::{1}:::{2}-{3}".format(searchTerm, morphology, startBook, endBook) elif self.type == "Word": command = "SEARCHMORPHOLOGYBYWORD:::{0}:::{1}:::{2}-{3}".format(searchTerm, morphology, startBook, endBook) elif self.type == "Gloss": command = "SEARCHMORPHOLOGYBYGLOSS:::{0}:::{1}:::{2}-{3}".format(searchTerm, morphology, startBook, endBook) self.parent.runTextCommand(command)