Ejemplo n.º 1
0
 def _make_filter_box(self):
     """
     Make the text box to filter the plots by name
     :return: A QLineEdit object with placeholder text and a
              clear button
     """
     text_box = QLineEdit(self)
     text_box.setPlaceholderText("Filter Plots")
     text_box.setClearButtonEnabled(True)
     return text_box
Ejemplo n.º 2
0
 def _make_filter_box(self):
     """
     Make the text box to filter the plots by name
     :return: A QLineEdit object with placeholder text and a
              clear button
     """
     text_box = QLineEdit(self)
     text_box.setPlaceholderText("Filter Plots")
     text_box.setClearButtonEnabled(True)
     return text_box
Ejemplo n.º 3
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.refresh_state = RefreshState.DONE
        self.already_installed = set()

        installer_type = "mamba" if running_as_constructor_app() else "pip"

        self.installer = Installer(installer=installer_type)
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.started.connect(self._on_installer_start)
        self.installer.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.cancel_all_btn.setVisible(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()
        self.close_btn.setDisabled(True)

    def _on_installer_done(self, exit_code):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()

        self.cancel_all_btn.setVisible(False)
        self.close_btn.setDisabled(False)
        self.refresh()

    def closeEvent(self, event):
        if self.close_btn.isEnabled():
            super().closeEvent(event)

        event.ignore()

    def refresh(self):
        if self.refresh_state != RefreshState.DONE:
            self.refresh_state = RefreshState.OUTDATED
            return
        self.refresh_state = RefreshState.REFRESHING
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from npe2 import PluginManager

        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        self.already_installed = set()

        def _add_to_installed(distname, enabled, npe_version=1):
            norm_name = normalized_name(distname or '')
            if distname:
                try:
                    meta = metadata(distname)
                except PackageNotFoundError:
                    self.refresh_state = RefreshState.OUTDATED
                    return  # a race condition has occurred and the package is uninstalled by another thread
                if len(meta) == 0:
                    # will not add builtins.
                    return
                self.already_installed.add(norm_name)
            else:
                meta = {}

            self.installed_list.addItem(
                PackageMetadata(
                    metadata_version="1.0",
                    name=norm_name,
                    version=meta.get('version', ''),
                    summary=meta.get('summary', ''),
                    home_page=meta.get('url', ''),
                    author=meta.get('author', ''),
                    license=meta.get('license', ''),
                ),
                installed=True,
                enabled=enabled,
                npe_version=npe_version,
            )

        pm2 = PluginManager.instance()
        for manifest in pm2.iter_manifests():
            distname = normalized_name(manifest.name or '')
            if distname in self.already_installed or distname == 'napari':
                continue
            enabled = not pm2.is_disabled(manifest.name)
            _add_to_installed(distname, enabled, npe_version=2)

        for (
                plugin_name,
                _mod_name,
                distname,
        ) in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname in self.already_installed:
                continue
            _add_to_installed(distname,
                              not plugin_manager.is_blocked(plugin_name))

        self.installed_label.setText(
            trans._(
                "Installed Plugins ({amount})",
                amount=len(self.already_installed),
            ))

        # fetch available plugins
        settings = get_settings()
        use_hub = (running_as_bundled_app() or running_as_constructor_app()
                   or settings.plugins.plugin_api.name == "napari_hub")
        if use_hub:
            conda_forge = running_as_constructor_app()
            self.worker = create_worker(iter_hub_plugin_info,
                                        conda_forge=conda_forge)
        else:
            self.worker = create_worker(iter_napari_plugin_info)

        self.worker.yielded.connect(self._handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.finished.connect(self._end_refresh)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        self.installed_label = QLabel(trans._("Installed Plugins"))
        self.packages_filter = QLineEdit()
        self.packages_filter.setPlaceholderText(trans._("filter..."))
        self.packages_filter.setMaximumWidth(350)
        self.packages_filter.setClearButtonEnabled(True)
        mid_layout = QVBoxLayout()
        mid_layout.addWidget(self.packages_filter)
        mid_layout.addWidget(self.installed_label)
        lay.addLayout(mid_layout)

        self.installed_list = QPluginList(installed, self.installer)
        self.packages_filter.textChanged.connect(self.installed_list.filter)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        mid_layout = QHBoxLayout()
        mid_layout.addWidget(self.avail_label)
        mid_layout.addStretch()
        lay.addLayout(mid_layout)
        self.available_list = QPluginList(uninstalled, self.installer)
        self.packages_filter.textChanged.connect(self.available_list.filter)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        visibility_direct_entry = not running_as_constructor_app()
        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_edit.setVisible(visibility_direct_entry)
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.setVisible(visibility_direct_entry)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)

        self.cancel_all_btn = QPushButton(trans._("cancel all actions"), self)
        self.cancel_all_btn.setObjectName("remove_button")
        self.cancel_all_btn.setVisible(False)
        self.cancel_all_btn.clicked.connect(lambda: self.installer.cancel())

        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.accept)
        self.close_btn.setObjectName("close_button")
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        if not visibility_direct_entry:
            buttonBox.addStretch()
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.cancel_all_btn)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

        self.packages_filter.setFocus()

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})", count=count))

    def _end_refresh(self):
        refresh_state = self.refresh_state
        self.refresh_state = RefreshState.DONE
        if refresh_state == RefreshState.OUTDATED:
            self.refresh()

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()

        if packages:
            self.installer.install(packages)

    def _handle_yield(self, data: Tuple[PackageMetadata, bool]):
        project_info, is_available = data
        if project_info.name in self.already_installed:
            self.installed_list.tag_outdated(project_info, is_available)
        else:
            self.available_list.addItem(project_info)
            if not is_available:
                self.available_list.tag_unavailable(project_info)

        self.filter()

    def filter(self, text: str = None) -> None:
        """Filter by text or set current text as filter."""
        if text is None:
            text = self.packages_filter.text()
        else:
            self.packages_filter.setText(text)

        self.installed_list.filter(text)
        self.available_list.filter(text)
Ejemplo n.º 4
0
class LibraryCatalogDialog(QDialog):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.setWindowTitle(config.thisTranslation["libraryCatalog"])
        self.setMinimumSize(700, 500)
        self.setupVariables()
        self.setupUI()

    def setupVariables(self):
        self.isUpdating = False
        self.catalogEntryId = None
        self.localCatalog = CatalogUtil.loadLocalCatalog()
        self.remoteCatalog = gitHubRepoCacheData
        self.localCatalogData = self.getLocalCatalogItems()
        self.remoteCatalogData = self.getRemoteCatalogItems()
        self.location = "local"
        self.textButtonStyle = "QPushButton {background-color: #333972; color: white;} QPushButton:hover {background-color: #333972;} QPushButton:pressed { background-color: #515790;}"

    def setupUI(self):
        mainLayout = QVBoxLayout()

        filterLayout = QHBoxLayout()
        filterLayout.addWidget(QLabel(config.thisTranslation["menu5_search"]))
        self.filterEntry = QLineEdit()
        self.filterEntry.setClearButtonEnabled(True)
        self.filterEntry.textChanged.connect(self.resetItems)
        filterLayout.addWidget(self.filterEntry)
        mainLayout.addLayout(filterLayout)

        self.searchTypeBox = QGroupBox("")
        locationLayout = QHBoxLayout()
        self.localRadioButton = QRadioButton("Local")
        self.localRadioButton.setChecked(True)
        self.localRadioButton.toggled.connect(
            lambda: self.setLocation("local"))
        locationLayout.addWidget(self.localRadioButton)
        self.remoteRadioButton = QRadioButton("Remote")
        self.remoteRadioButton.toggled.connect(
            lambda: self.setLocation("remote"))
        locationLayout.addWidget(self.remoteRadioButton)
        self.searchTypeBox.setLayout(locationLayout)
        mainLayout.addWidget(self.searchTypeBox)

        typesLayout = QHBoxLayout()
        button = QPushButton("All")
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(lambda: self.selectAllTypes(True))
        typesLayout.addWidget(button)
        button = QPushButton("None")
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(lambda: self.selectAllTypes(False))
        typesLayout.addWidget(button)
        self.bookCheckbox = QCheckBox("BOOK")
        self.bookCheckbox.setChecked(True)
        self.bookCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.bookCheckbox)
        self.pdfCheckbox = QCheckBox("PDF")
        self.pdfCheckbox.setChecked(True)
        self.pdfCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.pdfCheckbox)
        self.docxCheckbox = QCheckBox("DOCX")
        self.docxCheckbox.setChecked(True)
        self.docxCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.docxCheckbox)
        self.devotionalCheckbox = QCheckBox("DEVOTIONAL")
        self.devotionalCheckbox.setChecked(True)
        self.devotionalCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.devotionalCheckbox)
        self.commCheckbox = QCheckBox("COMM")
        self.commCheckbox.setChecked(True)
        self.commCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.commCheckbox)
        self.mp3Checkbox = QCheckBox("MP3")
        self.mp3Checkbox.setChecked(True)
        self.mp3Checkbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.mp3Checkbox)
        self.mp4Checkbox = QCheckBox("MP4")
        self.mp4Checkbox.setChecked(True)
        self.mp4Checkbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.mp4Checkbox)
        mainLayout.addLayout(typesLayout)

        self.dataView = QTableView()
        self.dataView.clicked.connect(self.itemClicked)
        self.dataView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.dataView.setSortingEnabled(True)
        self.dataViewModel = QStandardItemModel(self.dataView)
        self.dataView.setModel(self.dataViewModel)
        self.resetItems()
        mainLayout.addWidget(self.dataView)

        buttonLayout = QHBoxLayout()
        self.openButton = QPushButton(config.thisTranslation["open"])
        self.openButton.setEnabled(True)
        self.openButton.setStyleSheet(self.textButtonStyle)
        self.openButton.clicked.connect(self.open)
        buttonLayout.addWidget(self.openButton)
        self.downloadButton = QPushButton(config.thisTranslation["download"])
        self.downloadButton.setEnabled(False)
        self.downloadButton.clicked.connect(self.download)
        buttonLayout.addWidget(self.downloadButton)
        button = QPushButton(config.thisTranslation["close"])
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(self.close)
        buttonLayout.addWidget(button)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

    def setLocation(self, location):
        self.location = location
        self.resetItems()
        if location == "local":
            self.openButton.setEnabled(True)
            self.openButton.setStyleSheet(self.textButtonStyle)
            self.downloadButton.setEnabled(False)
        else:
            self.openButton.setEnabled(False)
            self.openButton.setStyleSheet("")
            self.downloadButton.setEnabled(True)

    def selectAllTypes(self, value):
        self.pdfCheckbox.setChecked(value)
        self.mp3Checkbox.setChecked(value)
        self.mp4Checkbox.setChecked(value)
        self.bookCheckbox.setChecked(value)
        self.docxCheckbox.setChecked(value)
        self.devotionalCheckbox.setChecked(value)
        self.commCheckbox.setChecked(value)

    def getLocalCatalogItems(self):
        return self.getCatalogItems(self.localCatalog)

    def getRemoteCatalogItems(self):
        return self.getCatalogItems(self.remoteCatalog)

    def getCatalogItems(self, catalog):
        data = {}
        pdfCount = 0
        mp3Count = 0
        mp4Count = 0
        bookCount = 0
        docxCount = 0
        commCount = 0
        lexCount = 0
        devotionalCount = 0
        for filename, type, directory, file, description, repo, installDirectory, sha in catalog:
            id = "UNKNOWN"
            if type == "PDF":
                pdfCount += 1
                id = "{0}-{1}".format(type, pdfCount)
            elif type == "MP3":
                mp3Count += 1
                id = "{0}-{1}".format(type, mp3Count)
            elif type == "MP4":
                mp4Count += 1
                id = "{0}-{1}".format(type, mp4Count)
            elif type == "BOOK":
                bookCount += 1
                id = "{0}-{1}".format(type, bookCount)
            elif type == "DOCX":
                docxCount += 1
                id = "{0}-{1}".format(type, docxCount)
            elif type == "COMM":
                commCount += 1
                id = "{0}-{1}".format(type, commCount)
            elif type == "LEX":
                lexCount += 1
                id = "{0}-{1}".format(type, lexCount)
            elif type == "DEVOTIONAL":
                devotionalCount += 1
                id = "{0}-{1}".format(type, devotionalCount)
            data[id] = [
                id, filename, type, directory, file, description, repo,
                installDirectory, sha
            ]
        return data

    def resetItems(self):
        self.isUpdating = True
        self.dataViewModel.clear()
        filterEntry = self.filterEntry.text().lower()
        rowCount = 0
        colCount = 0
        catalogData = self.localCatalogData
        if self.location == "remote":
            catalogData = self.remoteCatalogData
        for id, value in catalogData.items():
            id2, filename, type, directory, file, description, repo, installDirectory, sha = value
            if (filterEntry == "" or filterEntry in filename.lower()
                    or filterEntry in description.lower()):
                if (not self.pdfCheckbox.isChecked() and type == "PDF") or \
                        (not self.mp3Checkbox.isChecked() and type == "MP3") or \
                        (not self.mp4Checkbox.isChecked() and type == "MP4") or \
                        (not self.bookCheckbox.isChecked() and type == "BOOK") or \
                        (not self.docxCheckbox.isChecked() and type == "DOCX") or \
                        (not self.devotionalCheckbox.isChecked() and type == "DEVOTIONAL") or \
                        (not self.commCheckbox.isChecked() and type == "COMM"):
                    continue
                enable = True
                if self.location == "remote":
                    installDirectory = os.path.join(config.marvelData,
                                                    installDirectory)
                    if FileUtil.regexFileExists(
                            "{0}.*".format(GithubUtil.getShortname(filename)),
                            installDirectory):
                        enable = False
                item = QStandardItem(id)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                item = QStandardItem(file)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                item = QStandardItem(directory)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                # item = QStandardItem(description)
                # self.dataViewModel.setItem(rowCount, colCount, item)
                # colCount += 1
                # add row count
                rowCount += 1
                colCount = 0
        self.dataViewModel.setHorizontalHeaderLabels([
            "#",
            config.thisTranslation["file"],
            config.thisTranslation["directory"],
            # config.thisTranslation["description"]
        ])
        self.dataView.resizeColumnsToContents()
        self.isUpdating = False

    def itemClicked(self, index):
        selectedRow = index.row()
        self.catalogEntryId = self.dataViewModel.item(selectedRow, 0).text()
        if self.location == "remote":
            item = self.remoteCatalogData[self.catalogEntryId]
            id, filename, type, directory, file, description, repo, installDirectory, sha = item
            installDirectory = os.path.join(config.marvelData,
                                            installDirectory)
            if FileUtil.regexFileExists(
                    "{0}.*".format(GithubUtil.getShortname(filename)),
                    installDirectory):
                self.downloadButton.setEnabled(False)
                self.downloadButton.setStyleSheet("")
            else:
                self.downloadButton.setEnabled(True)
                self.downloadButton.setStyleSheet(self.textButtonStyle)

    def displayMessage(self, message="", title="UniqueBible"):
        QMessageBox.information(self, title, message)

    def saveRemoteCatalogToCache(self):
        data = CatalogUtil.loadRemoteCatalog()
        with open("util/GitHubRepoCache.py", "w", encoding="utf-8") as fileObj:
            fileObj.write("gitHubRepoCacheData = {0}\n".format(
                pprint.pformat(data)))

    def fixDirectory(self, directory, type):
        if type == "PDF":
            directory = directory.replace(config.marvelData, "")
            directory = directory.replace("/pdf", "")
        if len(directory) > 0 and not directory.endswith("/"):
            directory += "/"
        if len(directory) > 0 and directory.startswith("/"):
            directory = directory[1:]
        return directory

    def open(self):
        item = self.localCatalogData[self.catalogEntryId]
        id, filename, type, directory, file, description, repo, installDirectory, sha = item
        directory = self.fixDirectory(directory, type)
        command = ""
        if type == "PDF":
            command = "PDF:::{0}{1}".format(directory, file)
        elif type == "MP3":
            command = "VLC:::{0}{1}".format(directory, file)
        elif type == "MP4":
            command = "VLC:::{0}{1}".format(directory, file)
        elif type == "BOOK":
            if file.endswith(".book"):
                file = file.replace(".book", "")
            config.booksFolder = directory
            command = "BOOK:::{0}".format(file)
        elif type == "COMM":
            file = file.replace(".commentary", "")
            file = file[1:]
            config.commentariesFolder = directory
            command = "COMMENTARY:::{0}:::{1} {2}".format(
                file, BibleBooks.eng[str(config.mainB)][0], config.mainC)
        elif type == "DOCX":
            command = "DOCX:::{0}".format(file)
        elif type == "DEVOTIONAL":
            file = file.replace(".devotional", "")
            command = "DEVOTIONAL:::{0}".format(file)
        self.parent.runTextCommand(command)

    def download(self):
        self.downloadButton.setEnabled(False)
        self.downloadButton.setStyleSheet("")
        item = self.remoteCatalogData[self.catalogEntryId]
        id, filename, type, directory, file, description, repo, installDirectory, sha = item
        github = GithubUtil(repo)
        installDirectory = os.path.join(config.marvelData, installDirectory)
        file = os.path.join(installDirectory, filename + ".zip")
        github.downloadFile(file, sha)
        with zipfile.ZipFile(file, 'r') as zipped:
            zipped.extractall(installDirectory)
        os.remove(file)
        self.displayMessage(filename + " " +
                            config.thisTranslation["message_installed"])
        self.localCatalog = CatalogUtil.reloadLocalCatalog()
        self.localCatalogData = self.getLocalCatalogItems()
        self.resetItems()
Ejemplo n.º 5
0
class MiniBrowser(QWidget):
    def __init__(self, parent, initialUrl=None):
        super().__init__()
        # Set title
        self.setWindowTitle(config.thisTranslation["miniBrowser"])
        # Set up variables
        self.parent = parent
        self.isFfmpegInstalled = self.parent.textCommandParser.isFfmpegInstalled(
        )
        # Setup interface
        self.setupUI(initialUrl)

    def closeEvent(self, event):
        self.youTubeView.load(QUrl("about:blank"))

    def setupUI(self, initialUrl=None):
        self.youTubeView = YouTubePopover(self)

        mainLayout = QVBoxLayout()

        layout = QHBoxLayout()
        button = QPushButton("<")
        button.setToolTip(config.thisTranslation["youtube_back"])
        button.clicked.connect(self.youTubeView.back)
        layout.addWidget(button)
        button = QPushButton(">")
        button.setToolTip(config.thisTranslation["youtube_forward"])
        button.clicked.connect(self.youTubeView.forward)
        layout.addWidget(button)
        self.addressBar = QLineEdit()
        self.addressBar.setClearButtonEnabled(True)
        self.addressBar.setToolTip(config.thisTranslation["enter_fullURL"])
        self.addressBar.returnPressed.connect(self.openURL)
        layout.addWidget(self.addressBar)
        button = QPushButton("mp3")
        button.setToolTip(config.thisTranslation["youtube_mp3"])
        button.clicked.connect(lambda: self.convertToFormat("mp3"))
        layout.addWidget(button)
        if self.isFfmpegInstalled:
            button = QPushButton("mp4")
            button.setToolTip(config.thisTranslation["youtube_mp4"])
            button.clicked.connect(lambda: self.convertToFormat("mp4"))
            layout.addWidget(button)
        else:
            button = QPushButton(config.thisTranslation["menu11_video"])
            button.setToolTip(config.thisTranslation["downloadVideo"])
            button.clicked.connect(self.downloadLastOption)
            layout.addWidget(button)
        button = QPushButton("+")
        button.setToolTip(config.thisTranslation["downloadOptions"])
        button.clicked.connect(self.downloadOptions)
        layout.addWidget(button)
        mainLayout.addLayout(layout)

        self.addressBar.setText(
            config.miniBrowserHome if initialUrl is None else initialUrl)
        self.openURL()
        mainLayout.addWidget(self.youTubeView)

        self.setLayout(mainLayout)

    def getYouTubeDownloadOptions(self):
        url = self.addressBar.text()
        return self.parent.textCommandParser.getYouTubeDownloadOptions(url)

    def downloadSelectedOption(self, option):
        self.youTubeDownloadOptions.close()
        option = re.sub("^([0-9]+?) .*?$", r"\1", option)
        downloadCommand = "youtube-dl -f {0}".format(option)
        self.parent.textCommandParser.youtubeDownload(downloadCommand,
                                                      self.addressBar.text())

    def downloadLastOption(self):
        options = self.getYouTubeDownloadOptions()
        if options:
            self.downloadSelectedOption(options[-1])
        else:
            self.displayMessage(config.thisTranslation["noSupportedUrlFormat"])

    def downloadOptions(self):
        options = self.getYouTubeDownloadOptions()
        if options:
            self.youTubeDownloadOptions = YouTubeDownloadOptions(self, options)
            self.youTubeDownloadOptions.show()
            self.youTubeDownloadOptions.setFixedSize(640, 400)
        else:
            self.displayMessage(config.thisTranslation["noSupportedUrlFormat"])

    def displayMessage(self, message="", title="UniqueBible"):
        if hasattr(config, "cli") and config.cli:
            print(message)
        else:
            reply = QMessageBox.information(self, title, message)

    def openURL(self):
        address = self.addressBar.text()
        if address:
            self.youTubeView.load(QUrl(address))

    def convertToFormat(self, fileType):
        if self.isFfmpegInstalled:
            address = self.addressBar.text()
            self.downloadMpFile(fileType, address)
        else:
            self.displayMessage(config.thisTranslation["ffmpegNotFound"])
            webbrowser.open(
                "https://github.com/eliranwong/UniqueBible/wiki/Install-ffmpeg"
            )

    def downloadMpFile(self, fileType, address):
        if not address or not re.search(
                "youtube", address,
                flags=re.IGNORECASE) or "/results?search_query=" in address:
            self.displayMessage(config.thisTranslation["youTubeLinkNotFound"])
        else:
            self.parent.runTextCommand("{0}:::{1}".format(fileType, address))
Ejemplo n.º 6
0
    def generate_context_menu(self, pos: QPoint):
        """
        Generate a context menu for contextMenuEvent

        Parameters
        ----------
        pos : QPoint
            The point where the context menu was requested
        """
        model_menu = QMenu()
        skip_text = "skip me"

        # Add filterbox to the context menu
        txt_box = QLineEdit(model_menu)
        txt_box.setPlaceholderText("Filter")
        txt_box.setClearButtonEnabled(True)
        txt_box_action = QWidgetAction(model_menu)
        txt_box_action.setDefaultWidget(txt_box)
        model_menu.addAction(txt_box_action)

        # Add result treeview to the context menu
        tree_view = QTreeWidget(model_menu)
        tree_view.header().close()
        tree_view_action = QWidgetAction(model_menu)
        tree_view_action.setDefaultWidget(tree_view)
        model_menu.addAction(tree_view_action)

        top_level_items = {}
        for cat in self._scene.registry.categories():
            item = QTreeWidgetItem(tree_view)
            item.setText(0, cat)
            item.setData(0, Qt.UserRole, skip_text)
            top_level_items[cat] = item

        registry = self._scene.registry
        for model, category in registry.registered_models_category_association(
        ).items():
            self.parent = top_level_items[category]
            item = QTreeWidgetItem(self.parent)
            item.setText(0, model)
            item.setData(0, Qt.UserRole, model)

        tree_view.expandAll()

        def click_handler(item):
            model_name = item.data(0, Qt.UserRole)
            if model_name == skip_text:
                return

            type_ = self._scene.registry.create(model_name)
            if type_:
                node = self._scene.create_node(type_)
                pos_view = self.mapToScene(pos)
                node.graphics_object.setPos(pos_view)
                self._scene.node_placed.emit(node)
            else:
                logger.debug("Model not found")

            model_menu.close()

        tree_view.itemClicked.connect(click_handler)

        # Setup filtering
        def filter_handler(text):
            for name, top_lvl_item in top_level_items.items():
                for i in range(top_lvl_item.childCount()):
                    child = top_lvl_item.child(i)
                    model_name = child.data(0, Qt.UserRole)
                    child.setHidden(text not in model_name)

        txt_box.textChanged.connect(filter_handler)

        # make sure the text box gets focus so the user doesn't have to click on it
        txt_box.setFocus()
        return model_menu
Ejemplo n.º 7
0
class MiscellaneousLauncher(QWidget):
    def __init__(self, parent):
        super().__init__()
        # set title
        self.setWindowTitle(config.thisTranslation["cp4"])
        # set up variables
        self.parent = parent
        # setup interface
        self.setupUI()

    def setupUI(self):
        mainLayout = QGridLayout()
        leftLayout = QVBoxLayout()
        rightLayout = QVBoxLayout()
        self.highLightLauncher = HighlightLauncher(self)
        leftLayout.addWidget(self.highLightLauncher)
        rightLayout.addWidget(self.noteEditor())
        rightLayout.addWidget(self.textToSpeechUtility())
        rightLayout.addWidget(self.utilities())
        rightLayout.addStretch()
        mainLayout.addLayout(leftLayout, 0, 0, 1, 2)
        mainLayout.addLayout(rightLayout, 0, 2, 1, 1)
        self.setLayout(mainLayout)

    def noteEditor(self):
        box = QGroupBox(config.thisTranslation["note_editor"])
        subLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["menu7_create"])
        button.setToolTip(config.thisTranslation["menu7_create"])
        button.clicked.connect(self.parent.parent.createNewNoteFile)
        subLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["menu7_open"])
        button.setToolTip(config.thisTranslation["menu7_open"])
        button.clicked.connect(self.parent.parent.openTextFileDialog)
        subLayout.addWidget(button)
        box.setLayout(subLayout)
        return box

    def utilities(self):
        box = QGroupBox(config.thisTranslation["utilities"])
        subLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["presentation"])
        button.setToolTip(config.thisTranslation["presentation"])
        button.clicked.connect(
            lambda: self.parent.parent.runPlugin("Presentation"))
        subLayout.addWidget(button)
        if config.isYoutubeDownloaderInstalled:
            button = QPushButton(config.thisTranslation["youtube_utility"])
            button.setToolTip(config.thisTranslation["youtube_utility"])
            button.clicked.connect(self.parent.parent.openYouTube)
            subLayout.addWidget(button)
        box.setLayout(subLayout)
        return box

    def textToSpeechUtility(self):
        box = QGroupBox(config.thisTranslation["tts_utility"])

        layout = QVBoxLayout()

        subLayout = QHBoxLayout()
        self.ttsEdit = QLineEdit()
        self.ttsEdit.setClearButtonEnabled(True)
        self.ttsEdit.setToolTip(config.thisTranslation["enter_text_here"])
        self.ttsEdit.returnPressed.connect(self.speakText)
        subLayout.addWidget(self.ttsEdit)
        layout.addLayout(subLayout)

        self.ttsSlider = QSlider(Qt.Horizontal)
        self.ttsSlider.setToolTip(config.thisTranslation["adjustSpeed"])
        self.ttsSlider.setMinimum(10)
        self.ttsSlider.setMaximum(310)
        self.ttsSlider.setValue(config.espeakSpeed if config.espeak else (
            160 + config.qttsSpeed * 150))
        self.ttsSlider.valueChanged.connect(
            self.changeEspeakSpeed if config.espeak else self.changeQttsSpeed)
        layout.addWidget(self.ttsSlider)

        subLayout = QHBoxLayout()

        self.languageCombo = QComboBox()
        subLayout.addWidget(self.languageCombo)
        if config.espeak:
            languages = TtsLanguages().isoLang2epeakLang
        else:
            languages = TtsLanguages().isoLang2qlocaleLang
        self.languageCodes = list(languages.keys())
        for code in self.languageCodes:
            self.languageCombo.addItem(languages[code][1])
        # Check if selected tts engine has the language user specify.
        if not (config.ttsDefaultLangauge in self.languageCodes):
            config.ttsDefaultLangauge = "en"
        # Set initial index
        # It is essential.  Otherwise, default tts language is changed by defaultTtsLanguageChanged method.
        ttsLanguageIndex = self.languageCodes.index(config.ttsDefaultLangauge)
        self.languageCombo.setCurrentIndex(ttsLanguageIndex)
        # Change default tts language as users select a new language
        self.languageCombo.currentIndexChanged.connect(
            self.defaultTtsLanguageChanged)

        button = QPushButton(config.thisTranslation["speak"])
        button.setToolTip(config.thisTranslation["speak"])
        button.clicked.connect(self.speakText)
        subLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["stop"])
        button.setToolTip(config.thisTranslation["stop"])
        button.clicked.connect(
            self.parent.parent.textCommandParser.stopTtsAudio)
        subLayout.addWidget(button)
        layout.addLayout(subLayout)

        box.setLayout(layout)
        return box

    def defaultTtsLanguageChanged(self, index):
        config.ttsDefaultLangauge = self.languageCodes[index]

    def speakText(self):
        text = self.ttsEdit.text()
        if text:
            if config.isTtsInstalled:
                if ":::" in text:
                    text = text.split(":::")[-1]
                command = "SPEAK:::{0}:::{1}".format(
                    self.languageCodes[self.languageCombo.currentIndex()],
                    text)
                self.parent.isRefreshing = True
                self.parent.runTextCommand(command)
                self.parent.isRefreshing = False
            else:
                self.parent.displayMessage(
                    config.thisTranslation["message_noSupport"])
        else:
            self.parent.displayMessage(
                config.thisTranslation["enterTextFirst"])

    def changeQttsSpeed(self, value):
        config.qttsSpeed = (value * (1.5 / 300) - .5)

    def changeEspeakSpeed(self, value):
        config.espeakSpeed = value

    def refresh(self):
        ttsLanguageIndex = self.languageCodes.index(config.ttsDefaultLangauge)
        self.languageCombo.setCurrentIndex(ttsLanguageIndex)
        self.highLightLauncher.refresh()
Ejemplo n.º 8
0
class MiniControl(QWidget):
    def __init__(self, parent, selectedTab=0):
        super().__init__()
        self.textButtonStyleEnabled = "QPushButton {background-color: #151B54; color: white;} QPushButton:hover {background-color: #333972;} QPushButton:pressed { background-color: #515790;}"
        self.textButtonStyleDisabled = "QPushButton {background-color: #323232; color: #323232;} QPushButton:hover {background-color: #323232;} QPushButton:pressed { background-color: #323232;}"
        self.setWindowTitle(config.thisTranslation["remote_control"])
        self.parent = parent
        self.devotionals = sorted(
            glob.glob(config.marvelData + "/devotionals/*.devotional"))
        # specify window size
        if config.qtMaterial and config.qtMaterialTheme:
            self.resizeWindow(1 / 2, 1 / 3)
        else:
            self.resizeWindow(2 / 5, 1 / 3)
        self.resizeEvent = (lambda old_method:
                            (lambda event:
                             (self.onResized(event), old_method(event))[-1]))(
                                 self.resizeEvent)
        self.bibleButtons = {}
        self.commentaryButtons = {}
        self.bookIntroButtons = {}
        # setup interface
        self.bible_layout = None
        self.setupUI()
        self.tabs.setCurrentIndex(selectedTab)

    # window appearance
    def resizeWindow(self, widthFactor, heightFactor):
        availableGeometry = QGuiApplication.instance().desktop(
        ).availableGeometry()
        self.setMinimumWidth(500)
        self.resize(availableGeometry.width() * widthFactor,
                    availableGeometry.height() * heightFactor)

    def onResized(self, event):
        pass

    def closeEvent(self, event):
        config.miniControl = False

    # manage key capture
    def event(self, event):
        if event.type() == QEvent.KeyRelease:
            if event.modifiers() == Qt.ControlModifier:
                if event.key() == Qt.Key_B:
                    self.tabs.setCurrentIndex(0)
                elif event.key() == Qt.Key_T:
                    self.tabs.setCurrentIndex(1)
                elif event.key() == Qt.Key_C:
                    self.tabs.setCurrentIndex(2)
                elif event.key() == Qt.Key_L:
                    self.tabs.setCurrentIndex(3)
                elif event.key() == Qt.Key_D:
                    self.tabs.setCurrentIndex(4)
                elif event.key() == Qt.Key_O:
                    self.tabs.setCurrentIndex(5)
            elif event.key() == Qt.Key_Escape:
                self.close()
        return QWidget.event(self, event)

    # setup ui
    def setupUI(self):
        textButtonStyle = "QPushButton {background-color: #151B54; color: white;} QPushButton:hover {background-color: #333972;} QPushButton:pressed { background-color: #515790;}"

        mainLayout = QGridLayout()

        commandBox = QVBoxLayout()
        commandBox.setSpacing(3)

        commandBar = QWidget()
        commandLayout1 = QBoxLayout(QBoxLayout.LeftToRight)
        commandLayout1.setSpacing(5)
        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setClearButtonEnabled(True)
        self.searchLineEdit.setToolTip(
            config.thisTranslation["enter_command_here"])
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.searchLineEdit.setFixedWidth(450)
        commandLayout1.addWidget(self.searchLineEdit)

        enterButton = QPushButton(config.thisTranslation["enter"])
        enterButton.setFixedWidth(100)
        enterButton.clicked.connect(self.searchLineEntered)
        commandLayout1.addWidget(enterButton)

        # commandLayout1.addStretch()
        commandBox.addLayout(commandLayout1)

        if config.showMiniKeyboardInMiniControl:
            commandLayout2 = QBoxLayout(QBoxLayout.LeftToRight)
            commandLayout2.setSpacing(5)

            keys = [
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ':', '-',
                ',', '.', ' ', '<', 'X'
            ]
            for key in keys:
                button = QPushButton(key)
                button.setMaximumWidth(30)
                button.clicked.connect(partial(self.keyEntryAction, key))
                commandLayout2.addWidget(button)

            commandLayout2.addStretch()
            commandBox.addLayout(commandLayout2)

        if config.showMiniKeyboardInMiniControl and config.isTtsInstalled:
            ttsLayout = QBoxLayout(QBoxLayout.LeftToRight)
            ttsLayout.setSpacing(5)

            self.languageCombo = QComboBox()
            ttsLayout.addWidget(self.languageCombo)
            if config.espeak:
                languages = TtsLanguages().isoLang2epeakLang
            else:
                languages = TtsLanguages().isoLang2qlocaleLang
            self.languageCodes = list(languages.keys())
            for code in self.languageCodes:
                self.languageCombo.addItem(languages[code][1])
            # Check if selected tts engine has the language user specify.
            if not (config.ttsDefaultLangauge in self.languageCodes):
                config.ttsDefaultLangauge = "en"
            # Set initial item
            initialIndex = self.languageCodes.index(config.ttsDefaultLangauge)
            self.languageCombo.setCurrentIndex(initialIndex)

            # setting tts default language here is confusing; better place in menu
            #setDefaultButton = QPushButton(config.thisTranslation["setDefault"])
            #setDefaultButton.setFixedWidth(130)
            #setDefaultButton.clicked.connect(self.setTtsDefaultLanguage)
            #ttsLayout.addWidget(setDefaultButton)

            speakButton = QPushButton(config.thisTranslation["speak"])
            speakButton.setFixedWidth(100)
            speakButton.clicked.connect(self.speakCommandFieldText)
            ttsLayout.addWidget(speakButton)

            stopButton = QPushButton(config.thisTranslation["stop"])
            stopButton.setFixedWidth(100)
            stopButton.clicked.connect(
                self.parent.textCommandParser.stopTtsAudio)
            ttsLayout.addWidget(stopButton)

            ttsLayout.addStretch()

            commandBox.addLayout(ttsLayout)

        commandBar.setLayout(commandBox)
        mainLayout.addWidget(commandBar, 0, 0, Qt.AlignCenter)

        self.tabs = QTabWidget()
        self.tabs.currentChanged.connect(self.tabChanged)
        mainLayout.addWidget(self.tabs, 1, 0, Qt.AlignCenter)

        parser = BibleVerseParser(config.parserStandarisation)
        self.bookMap = parser.standardAbbreviation
        bookNums = list(self.bookMap.keys())
        self.bookNumGps = [
            bookNums[0:10],
            bookNums[10:20],
            bookNums[20:30],
            bookNums[30:39],
            bookNums[39:49],
            bookNums[49:59],
            bookNums[59:69],
            bookNums[69:79],
            bookNums[79:86],
            bookNums[86:94],
            bookNums[94:99],
            bookNums[99:104],
            bookNums[104:110],
            bookNums[110:119],
            bookNums[119:124],
            bookNums[124:129],
            bookNums[129:139],
            bookNums[139:149],
            bookNums[149:159],
            bookNums[159:169],
            bookNums[169:174],
            bookNums[174:179],
            bookNums[179:189],
            bookNums[189:199],
        ]

        # Bible books tab

        self.bible = QWidget()
        self.populateBooksButtons(config.mainText)
        self.tabs.addTab(self.bible, config.thisTranslation["bible"])

        # Bible translations tab

        self.biblesBox = QWidget()
        self.biblesBoxContainer = QVBoxLayout()
        collectionsLayout = self.newRowLayout()
        if len(config.bibleCollections) > 0:
            button = QPushButton("All")
            button.setStyleSheet(textButtonStyle)
            button.clicked.connect(partial(self.selectCollection, "All"))
            collectionsLayout.addWidget(button)
            count = 0
            for collection in sorted(config.bibleCollections.keys()):
                button = QPushButton(collection)
                button.setStyleSheet(textButtonStyle)
                button.clicked.connect(
                    partial(self.selectCollection, collection))
                collectionsLayout.addWidget(button)
                count += 1
                if count > 5:
                    count = 0
                    self.biblesBoxContainer.addLayout(collectionsLayout)
                    collectionsLayout = self.newRowLayout()

        self.biblesBoxContainer.addLayout(collectionsLayout)
        self.bibleBoxWidget = QWidget()
        self.bibleBoxLayout = QVBoxLayout()
        self.bibleBoxLayout.setContentsMargins(0, 0, 0, 0)
        self.bibleBoxLayout.setSpacing(1)
        row_layout = self.newRowLayout()
        row_layout.setContentsMargins(0, 0, 0, 0)
        row_layout.setSpacing(1)
        biblesSqlite = BiblesSqlite()
        bibles = biblesSqlite.getBibleList()
        count = 0
        for bible in bibles:
            button = QPushButton(bible)
            if bible in config.bibleDescription:
                button.setToolTip("{0}".format(config.bibleDescription[bible]))
            button.clicked.connect(partial(self.bibleAction, bible))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                self.bibleBoxLayout.addLayout(row_layout)
                row_layout = self.newRowLayout()
            self.bibleButtons[bible] = button
        self.bibleBoxLayout.addLayout(row_layout)
        self.bibleBoxLayout.addStretch()
        self.biblesBoxContainer.addLayout(self.bibleBoxLayout)
        self.biblesBoxContainer.addStretch()
        self.biblesBox.setLayout(self.biblesBoxContainer)
        self.tabs.addTab(self.biblesBox,
                         config.thisTranslation["translations"])

        # Commentaries tab

        commentaries_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setContentsMargins(0, 0, 0, 0)
        box_layout.setSpacing(1)
        row_layout = self.newRowLayout()
        button = QPushButton(config.thisTranslation["activeOnly"])
        button.setStyleSheet(textButtonStyle)
        button.clicked.connect(self.activeCommentaries)
        row_layout.addWidget(button)
        box_layout.addLayout(row_layout)
        row_layout = self.newRowLayout()
        commentaries = Commentary().getCommentaryList()
        count = 0
        for commentary in commentaries:
            button = QPushButton(commentary)
            button.setToolTip(Commentary.fileLookup[commentary])
            button.clicked.connect(partial(self.commentaryAction, commentary))
            self.commentaryButtons[commentary] = button
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        commentaries_box.setLayout(box_layout)

        self.tabs.addTab(commentaries_box,
                         config.thisTranslation["commentaries"])

        # Lexicons tab

        lexicons_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setContentsMargins(0, 0, 0, 0)
        box_layout.setSpacing(1)
        row_layout = self.newRowLayout()
        lexicons = LexiconData().lexiconList
        count = 0
        for lexicon in lexicons:
            button = QPushButton(lexicon)
            if lexicon in config.lexiconDescription:
                button.setToolTip("{0}".format(
                    config.lexiconDescription[lexicon]))
            button.clicked.connect(partial(self.lexiconAction, lexicon))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        lexicons_box.setLayout(box_layout)

        self.tabs.addTab(lexicons_box, config.thisTranslation["lexicons"])

        # Dictionaries tab

        dictionaries_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setContentsMargins(0, 0, 0, 0)
        box_layout.setSpacing(1)
        row_layout = self.newRowLayout()
        dictionaries = IndexesSqlite().dictionaryList
        count = 0
        for dictionary in dictionaries:
            button = QPushButton(dictionary[0])
            button.setToolTip(dictionary[1])
            button.clicked.connect(
                partial(self.dictionaryAction, dictionary[0]))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        dictionaries_box.setLayout(box_layout)

        self.tabs.addTab(dictionaries_box,
                         config.thisTranslation["dictionaries"])

        # Book intros tab

        bookIntros_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setContentsMargins(0, 0, 0, 0)
        box_layout.setSpacing(1)
        row_layout = self.newRowLayout()
        button = QPushButton(config.thisTranslation["activeOnly"])
        button.setStyleSheet(textButtonStyle)
        button.clicked.connect(self.activeBookIntros)
        row_layout.addWidget(button)
        box_layout.addLayout(row_layout)
        row_layout = self.newRowLayout()
        commentaries = Commentary().getCommentaryList()
        count = 0
        for commentary in commentaries:
            button = QPushButton(commentary)
            button.setToolTip(Commentary.fileLookup[commentary])
            button.clicked.connect(partial(self.bookIntroAction, commentary))
            self.bookIntroButtons[commentary] = button
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        bookIntros_box.setLayout(box_layout)

        self.tabs.addTab(bookIntros_box, config.thisTranslation["bookIntro"])

        # Devotionals tab

        if len(self.devotionals) > 0:
            devotionals_box = QWidget()
            box_layout = QVBoxLayout()
            box_layout.setContentsMargins(0, 0, 0, 0)
            box_layout.setSpacing(1)
            row_layout = self.newRowLayout()
            count = 0
            for file in self.devotionals:
                name = Path(file).stem
                button = QPushButton(name)
                # button.setToolTip(dictionary[1])
                button.clicked.connect(partial(self.devotionalAction, name))
                row_layout.addWidget(button)
                count += 1
                if count > 2:
                    count = 0
                    box_layout.addLayout(row_layout)
                    row_layout.addStretch()
                    row_layout = self.newRowLayout()
            for i in range(count, 3):
                button = QPushButton("")
                row_layout.addWidget(button)
            box_layout.addLayout(row_layout)
            box_layout.addStretch()
            devotionals_box.setLayout(box_layout)

            self.tabs.addTab(devotionals_box,
                             config.thisTranslation["devotionals"])

        self.tabs.setCurrentIndex(config.miniControlInitialTab)
        self.setLayout(mainLayout)

    def populateBooksButtons(self, bibleName):
        books = Bible(bibleName).getBookList()
        if self.bible_layout is not None:
            while self.bible_layout.count():
                child = self.bible_layout.takeAt(0)
                if child.widget():
                    child.widget().deleteLater()
        else:
            self.bible_layout = QVBoxLayout()
        self.bible_layout.setContentsMargins(0, 0, 0, 0)
        self.bible_layout.setSpacing(1)
        for bookNumGp in self.bookNumGps:
            gp = QWidget()
            layout = self.newRowLayout()
            for bookNum in bookNumGp:
                if int(bookNum) in books:
                    text = self.bookMap[bookNum]
                    button = QPushButton(text)
                    if config.developer:
                        button.setToolTip("{0} - {1}".format(
                            BibleBooks.eng[bookNum][1], bookNum))
                    else:
                        button.setToolTip("{0}".format(
                            BibleBooks.eng[bookNum][1]))
                    button.clicked.connect(
                        partial(self.bibleBookAction, bookNum))
                    layout.addWidget(button)
            gp.setLayout(layout)
            self.bible_layout.addWidget(gp)
        # for bookNumGp in self.bookNumGps[5:]:
        #     gp = QWidget()
        #     layout = self.newRowLayout()
        #     for bookNum in bookNumGp:
        #         text = self.bookMap[bookNum]
        #         button = QPushButton(text)
        #         button.clicked.connect(partial(self.bibleBookAction, bookNum))
        #         layout.addWidget(button)
        #     gp.setLayout(layout)
        #     bible_layout.addWidget(gp)
        self.bible_layout.addStretch()
        self.bible.setLayout(self.bible_layout)

    def newRowLayout(self):
        row_layout = QHBoxLayout()
        row_layout.setContentsMargins(0, 0, 0, 0)
        row_layout.setSpacing(1)
        return row_layout

    def tabChanged(self, index):
        prefix = ""
        if index == 0:
            prefix = "BIBLE:::{0}:::".format(config.mainText)
        elif index == 1:
            prefix = "TEXT:::"
        elif index == 2:
            prefix = "COMMENTARY:::{0}:::".format(config.commentaryText)
        elif index == 3:
            prefix = "LEXICON:::"
        elif index == 4:
            prefix = "SEARCHTOOL:::"
        if not config.clearCommandEntry:
            self.searchLineEdit.setText(prefix)

    def searchLineEntered(self):

        saveOpenBibleWindowContentOnNextTab = config.openBibleWindowContentOnNextTab
        searchString = self.searchLineEdit.text()
        if ":::" not in searchString or ":::{0}:::".format(
                config.mainText) in searchString:
            config.openBibleWindowContentOnNextTab = False
        self.parent.textCommandLineEdit.setText(searchString)
        self.parent.runTextCommand(searchString)
        self.searchLineEdit.setFocus()
        self.populateBooksButtons(config.mainText)
        config.openBibleWindowContentOnNextTab = saveOpenBibleWindowContentOnNextTab

    #def setTtsDefaultLanguage(self):
    #config.ttsDefaultLangauge = self.languageCodes[self.languageCombo.currentIndex()]

    def speakCommandFieldText(self):
        text = self.searchLineEdit.text()
        if ":::" in text:
            text = text.split(":::")[-1]
        command = "SPEAK:::{0}:::{1}".format(
            self.languageCodes[self.languageCombo.currentIndex()], text)
        self.runCommmand(command)

    def bibleBookAction(self, book):
        command = "{0} ".format(self.bookMap[book])
        self.runCommmand(command)
        self.searchLineEdit.setFocus()

    def keyEntryAction(self, key):
        text = self.searchLineEdit.text()
        if key == "X":
            text = ""
        elif key == "<":
            text = text[:-1]
        else:
            text += key
        self.searchLineEdit.setText(text)

    def bibleAction(self, bible):
        command = "BIBLE:::{0}:::{1}".format(
            bible,
            self.parent.verseReference("main")[1])
        self.runCommmand(command)
        command = "_bibleinfo:::{0}".format(bible)
        self.parent.runTextCommand(command)
        self.populateBooksButtons(config.mainText)

    def commentaryAction(self, commentary):
        command = "COMMENTARY:::{0}:::{1}".format(
            commentary,
            self.parent.verseReference("main")[1])
        self.runCommmand(command)
        command = "_commentaryinfo:::{0}".format(commentary)
        self.parent.runTextCommand(command)

    def bookIntroAction(self, commentary):
        command = "COMMENTARY:::{0}:::{1}".format(
            commentary,
            BibleBooks().eng[str(config.mainB)][-1])
        self.runCommmand(command)
        command = "_commentaryinfo:::{0}".format(commentary)
        self.parent.runTextCommand(command)

    def devotionalAction(self, devotional):
        command = "DEVOTIONAL:::{0}".format(devotional)
        self.runCommmand(command)

    def lexiconAction(self, lexicon):
        searchString = self.searchLineEdit.text()
        if ":::" not in searchString:
            TextCommandParser.last_lexicon_entry = searchString
        command = "SEARCHLEXICON:::{0}:::{1}".format(
            lexicon, TextCommandParser.last_lexicon_entry)
        self.runCommmand(command)

    def dictionaryAction(self, dictionary):
        searchString = self.searchLineEdit.text()
        if ":::" not in searchString:
            TextCommandParser.last_text_search = searchString
        command = "SEARCHTOOL:::{0}:::{1}".format(
            dictionary, TextCommandParser.last_text_search)
        self.runCommmand(command)

    def runCommmand(self, command):
        self.searchLineEdit.setText(command)
        self.parent.runTextCommand(command)
        self.parent.textCommandLineEdit.setText(command)
        self.populateBooksButtons(config.mainText)

    def selectCollection(self, collection):

        if not collection == "All":
            biblesInCollection = config.bibleCollections[collection]
        for bible in self.bibleButtons.keys():
            button = self.bibleButtons[bible]
            if collection == "All":
                button.setEnabled(True)
                button.setStyleSheet("")
            else:
                if bible in biblesInCollection:
                    button.setEnabled(True)
                    button.setStyleSheet("")
                else:
                    button.setEnabled(False)
                    button.setStyleSheet(self.textButtonStyleDisabled)

    def activeCommentaries(self):
        activeCommentaries = [
            item[0]
            for item in Commentary().getCommentaryListThatHasBookAndChapter(
                config.mainB, config.mainC)
        ]
        for commentary in self.commentaryButtons.keys():
            button = self.commentaryButtons[commentary]
            if commentary in activeCommentaries:
                button.setEnabled(True)
                button.setStyleSheet("")
            else:
                button.setEnabled(False)
                button.setStyleSheet(self.textButtonStyleDisabled)

    def activeBookIntros(self):
        activeCommentaries = [
            item[0]
            for item in Commentary().getCommentaryListThatHasBookAndChapter(
                config.mainB, 0)
        ]
        for commentary in self.bookIntroButtons.keys():
            button = self.bookIntroButtons[commentary]
            if commentary in activeCommentaries:
                button.setEnabled(True)
                button.setStyleSheet("")
            else:
                button.setEnabled(False)
                button.setStyleSheet(self.textButtonStyleDisabled)
Ejemplo n.º 9
0
class MasterControl(QWidget):
    def __init__(self,
                 parent,
                 initialTab=0,
                 b=config.mainB,
                 c=config.mainC,
                 v=config.mainV,
                 text=config.mainText):
        super().__init__()

        self.isRefreshing = True

        self.parent = parent
        # set title
        self.setWindowTitle(config.thisTranslation["controlPanel"])
        if config.restrictControlPanelWidth and config.screenWidth > config.masterControlWidth:
            self.setFixedWidth(config.masterControlWidth)
        # setup item option lists
        self.setupResourceLists()
        # setup interface
        self.text = text
        self.setupUI(b, c, v, text, initialTab)
        # setup keyboard shortcuts
        self.setupKeyboardShortcuts()

        self.isRefreshing = False

    def setupKeyboardShortcuts(self):
        for index, shortcut in enumerate(
            (sc.openControlPanelTab0, sc.openControlPanelTab1,
             sc.openControlPanelTab2, sc.openControlPanelTab3,
             sc.openControlPanelTab4, sc.openControlPanelTab5)):
            shortcut = QShortcut(QKeySequence(shortcut), self)
            shortcut.activated.connect(
                lambda index=index: self.tabs.setCurrentIndex(index))

    # manage key capture
    def event(self, event):
        if event.type() == QEvent.KeyRelease:
            if event.key() == Qt.Key_Escape:
                self.hide()
        if isinstance(event, QEvent):
            return QWidget.event(self, event)

    def closeEvent(self, event):
        # Control panel is designed for frequent use
        # Hiding it instead of closing may save time from reloading
        event.ignore()
        self.hide()

    def setupResourceLists(self):
        self.parent.setupResourceLists()
        # bible versions
        self.textList = self.parent.textList
        self.textFullNameList = self.parent.textFullNameList
        self.strongBibles = self.parent.strongBibles
        if self.parent.versionCombo is not None and config.menuLayout in (
                "classic", "focus", "aleph"):
            for index, fullName in enumerate(self.textFullNameList):
                self.parent.versionCombo.setItemData(index, fullName,
                                                     Qt.ToolTipRole)
        # commentaries
        self.commentaryList = self.parent.commentaryList
        #self.commentaryFullNameList = [Commentary(module).commentaryInfo() for module in self.commentaryList]
        self.commentaryFullNameList = self.parent.commentaryFullNameList
        # reference book
        # menu10_dialog
        self.referenceBookList = self.parent.referenceBookList
        # topic
        # menu5_topics
        self.topicListAbb = self.parent.topicListAbb
        self.topicList = self.parent.topicList
        # lexicon
        # context1_originalLexicon
        self.lexiconList = self.parent.lexiconList
        # dictionary
        # context1_dict
        self.dictionaryListAbb = self.parent.dictionaryListAbb
        self.dictionaryList = self.parent.dictionaryList
        # encyclopedia
        # context1_encyclopedia
        self.encyclopediaListAbb = self.parent.encyclopediaListAbb
        self.encyclopediaList = self.parent.encyclopediaList
        # 3rd-party dictionary
        # menu5_3rdDict
        self.thirdPartyDictionaryList = self.parent.thirdPartyDictionaryList
        # pdf list
        self.pdfList = self.parent.pdfList
        # docx list
        self.docxList = self.parent.docxList

    def setupUI(self, b, c, v, text, initialTab):
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.sharedWidget())
        mainLayout.addWidget(self.tabWidget(b, c, v, text, initialTab))
        self.setLayout(mainLayout)

    def sharedWidget(self):
        sharedWidget = QWidget()
        sharedWidgetLayout = QVBoxLayout()
        subLayout = QHBoxLayout()
        subLayout.addWidget(self.commandFieldWidget())
        subLayout.addWidget(self.autoCloseCheckBox())
        sharedWidgetLayout.addLayout(subLayout)
        sharedWidget.setLayout(sharedWidgetLayout)
        return sharedWidget

    def updateBibleTabText(self, reference):
        self.tabs.setTabText(0, reference)

    def tabWidget(self, b, c, v, text, initialTab):
        self.tabs = QTabWidget()
        # 0
        self.bibleTab = BibleExplorer(self, (b, c, v, text))
        self.tabs.addTab(self.bibleTab, config.thisTranslation["cp0"])
        self.tabs.setTabToolTip(0, sc.openControlPanelTab0)
        # 1
        libraryTab1 = LibraryLauncher(self)
        self.tabs.addTab(libraryTab1, config.thisTranslation["cp1"])
        self.tabs.setTabToolTip(1, sc.openControlPanelTab1)
        # 2
        libraryTab2 = Library2Launcher(self)
        self.tabs.addTab(libraryTab2, config.thisTranslation["cp2"])
        self.tabs.setTabToolTip(2, sc.openControlPanelTab2)
        # 3
        self.toolTab = SearchLauncher(self)
        self.tabs.addTab(self.toolTab, config.thisTranslation["cp3"])
        self.tabs.setTabToolTip(3, sc.openControlPanelTab3)
        # 4
        self.historyTab = HistoryLauncher(self)
        self.tabs.addTab(self.historyTab, config.thisTranslation["cp4"])
        self.tabs.setTabToolTip(4, sc.openControlPanelTab4)
        # 5
        self.miscellaneousTab = MiscellaneousLauncher(self)
        self.tabs.addTab(self.miscellaneousTab, config.thisTranslation["cp5"])
        self.tabs.setTabToolTip(5, sc.openControlPanelTab5)
        # 6
        if config.isVlcInstalled:
            mediaTab = MediaLauncher(self)
            self.tabs.addTab(mediaTab, config.thisTranslation["mediaPlayer"])
            self.tabs.setTabToolTip(6, sc.openControlPanelTab6)
        #7
        self.morphologyTab = MorphologyLauncher(self)
        self.tabs.addTab(self.morphologyTab, config.thisTranslation["cp7"])
        self.tabs.setTabToolTip(7, sc.openControlPanelTab7)

        # set action with changing tabs
        self.tabs.currentChanged.connect(self.tabChanged)
        # set initial tab
        self.tabs.setCurrentIndex(initialTab)
        return self.tabs

    def commandFieldWidget(self):
        self.commandField = QLineEdit()
        self.commandField.setClearButtonEnabled(True)
        self.commandField.setToolTip(
            config.thisTranslation["enter_command_here"])
        self.commandField.returnPressed.connect(self.commandEntered)
        return self.commandField

    def autoCloseCheckBox(self):
        checkbox = QCheckBox()
        checkbox.setText(config.thisTranslation["autoClose"])
        checkbox.setToolTip(config.thisTranslation["autoCloseToolTip"])
        checkbox.setChecked(config.closeControlPanelAfterRunningCommand)
        checkbox.stateChanged.connect(
            self.closeControlPanelAfterRunningCommandChanged)
        return checkbox

    # Common layout

    def buttonsWidget(self,
                      buttonElementTupleTuple,
                      r2l=False,
                      translation=True):
        buttons = QWidget()
        buttonsLayouts = QVBoxLayout()
        buttonsLayouts.setSpacing(3)
        for buttonElementTuple in buttonElementTupleTuple:
            buttonsLayouts.addLayout(
                self.buttonsLayout(buttonElementTuple, r2l, translation))
        buttons.setLayout(buttonsLayouts)
        return buttons

    def buttonsLayout(self, buttonElementTuple, r2l=False, translation=True):
        buttonsLayout = QBoxLayout(
            QBoxLayout.RightToLeft if r2l else QBoxLayout.LeftToRight)
        buttonsLayout.setSpacing(5)
        for label, action in buttonElementTuple:
            buttonLabel = config.thisTranslation[
                label] if translation else label
            button = QPushButton(buttonLabel)
            button.clicked.connect(action)
            buttonsLayout.addWidget(button)
        return buttonsLayout

    def comboFeatureLayout(self, feature, combo, action):
        # QGridLayout: https://stackoverflow.com/questions/61451279/how-does-setcolumnstretch-and-setrowstretch-works
        layout = QGridLayout()
        layout.setSpacing(5)
        # combo
        layout.addWidget(combo, 0, 0, 1, 3)
        # button
        button = QPushButton(config.thisTranslation[feature])
        button.clicked.connect(action)
        layout.addWidget(button, 0, 3, 1, 1)
        return layout

    # Actions

    def closeControlPanelAfterRunningCommandChanged(self):
        config.closeControlPanelAfterRunningCommand = not config.closeControlPanelAfterRunningCommand

    def updateBCVText(self, b, c, v, text):
        self.bibleTab.updateBCVText(b, c, v, text)

    def commandEntered(self):
        command = self.commandField.text()
        self.runTextCommand(command, False)

    def runTextCommand(self,
                       command,
                       printCommand=True,
                       reloadMainWindow=False):
        if printCommand:
            self.commandField.setText(command)
        self.parent.textCommandLineEdit.setText(command)
        self.parent.runTextCommand(command)
        if reloadMainWindow:
            self.parent.reloadCurrentRecord()
        if config.closeControlPanelAfterRunningCommand and not self.isRefreshing:
            self.hide()

    def tabChanged(self, index):
        self.isRefreshing = True

        # refresh content
        if index == 4:
            self.historyTab.refresh()
        elif index == 5:
            self.miscellaneousTab.refresh()

        # set focus
        if index == 3:
            self.toolTab.searchField.setFocus()
            if config.contextItem:
                self.toolTab.searchField.setText(config.contextItem)
                config.contextItem = ""
            elif self.parent.mainView.currentWidget().selectedText():
                self.toolTab.searchField.setText(
                    self.parent.mainView.currentWidget().selectedText())
            elif self.parent.studyView.currentWidget().selectedText():
                self.toolTab.searchField.setText(
                    self.parent.studyView.currentWidget().selectedText())
        else:
            self.commandField.setFocus()

        self.isRefreshing = False

    def displayMessage(self, message="", title="UniqueBible"):
        reply = QMessageBox.information(self, title, message)
Ejemplo n.º 10
0
class PropertyBrowser(QDialog):
    def __init__(self,
                 mmcore: Optional[CMMCorePlus] = None,
                 parent: Optional[QWidget] = None):
        super().__init__(parent)
        self._mmc = mmcore or get_core_singleton()

        self._prop_table = PropertyTable(mmcore)
        self._show_read_only: bool = True

        self._filters: Set[DeviceType] = set()
        self._filter_text = QLineEdit()
        self._filter_text.setClearButtonEnabled(True)
        self._filter_text.setPlaceholderText(
            "Filter by device or property name...")
        self._filter_text.textChanged.connect(self._update_filter)

        right = QWidget()
        right.setLayout(QVBoxLayout())
        right.layout().addWidget(self._filter_text)
        right.layout().addWidget(self._prop_table)

        left = QWidget()
        left.setLayout(QVBoxLayout())
        left.layout().addWidget(self._make_checkboxes())

        self.setLayout(QHBoxLayout())
        self.layout().setContentsMargins(6, 12, 12, 12)
        self.layout().setSpacing(0)
        self.layout().addWidget(left)
        self.layout().addWidget(right)
        self._mmc.events.systemConfigurationLoaded.connect(self._update_filter)

        self.destroyed.connect(self._disconnect)

    def _disconnect(self) -> None:
        self._mmc.events.systemConfigurationLoaded.disconnect(
            self._update_filter)

    def _update_filter(self):
        filt = self._filter_text.text().lower()
        for r in range(self._prop_table.rowCount()):
            wdg = cast(PropertyWidget, self._prop_table.cellWidget(r, 1))
            if wdg.isReadOnly() and not self._show_read_only:  # sourcery skip
                self._prop_table.hideRow(r)
            elif wdg.deviceType() in self._filters:
                self._prop_table.hideRow(r)
            elif filt and filt not in self._prop_table.item(r,
                                                            0).text().lower():
                self._prop_table.hideRow(r)
            else:
                self._prop_table.showRow(r)

    def _toggle_filter(self, label: str):
        self._filters.symmetric_difference_update(DevTypeLabels[label])
        self._update_filter()

    def _make_checkboxes(self):
        dev_gb = QGroupBox("Device Type")
        dev_gb.setLayout(QGridLayout())
        dev_gb.layout().setSpacing(6)
        all_btn = QPushButton("All")
        dev_gb.layout().addWidget(all_btn, 0, 0, 1, 1)
        none_btn = QPushButton("None")
        dev_gb.layout().addWidget(none_btn, 0, 1, 1, 1)
        for i, label in enumerate(DevTypeLabels):
            cb = QCheckBox(label)
            cb.setChecked(DevTypeLabels[label] not in self._filters)
            cb.toggled.connect(partial(self._toggle_filter, label))
            dev_gb.layout().addWidget(cb, i + 1, 0, 1, 2)

        @all_btn.clicked.connect
        def _check_all():
            for cxbx in dev_gb.findChildren(QCheckBox):
                cxbx.setChecked(True)

        @none_btn.clicked.connect
        def _check_none():
            for cxbx in dev_gb.findChildren(QCheckBox):
                cxbx.setChecked(False)

        for i in dev_gb.findChildren(QWidget):
            i.setFocusPolicy(Qt.FocusPolicy.NoFocus)

        ro = QCheckBox("Show read-only")
        ro.setChecked(self._show_read_only)
        ro.toggled.connect(self._set_show_read_only)
        ro.setFocusPolicy(Qt.FocusPolicy.NoFocus)

        c = QWidget()
        c.setLayout(QVBoxLayout())
        c.layout().addWidget(dev_gb)
        c.layout().addWidget(ro)
        c.layout().addStretch()
        return c

    def _set_show_read_only(self, state: bool):
        self._show_read_only = bool(state)
        self._update_filter()
Ejemplo n.º 11
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installer = Installer()
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.process.started.connect(self._on_installer_start)
        self.installer.process.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.show_status_btn.setChecked(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()

    def _on_installer_done(self, exit_code, exit_status):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()
        else:
            self.show_status_btn.setChecked(False)
        self.refresh()
        self.plugin_sorter.refresh()

    def refresh(self):
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        already_installed = set()

        for plugin_name, mod_name, distname in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname:
                already_installed.add(distname)
                meta = standard_metadata(distname)
            else:
                meta = {}
            self.installed_list.addItem(
                ProjectInfo(
                    normalized_name(distname or ''),
                    meta.get('version', ''),
                    meta.get('url', ''),
                    meta.get('summary', ''),
                    meta.get('author', ''),
                    meta.get('license', ''),
                ),
                plugin_name=plugin_name,
                enabled=plugin_name in plugin_manager.plugins,
            )
        # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10])

        # fetch available plugins
        self.worker = create_worker(iter_napari_plugin_info)

        def _handle_yield(project_info):
            if project_info.name in already_installed:
                self.installed_list.tag_outdated(project_info)
            else:
                self.available_list.addItem(project_info)

        self.worker.yielded.connect(_handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)
        self.plugin_sorter = QtPluginSorter(parent=self.h_splitter)
        self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0)
        self.plugin_sorter.hide()

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        self.installed_label = QLabel(trans._("Installed Plugins"))
        self.installed_filter = QLineEdit()
        self.installed_filter.setPlaceholderText("search...")
        self.installed_filter.setMaximumWidth(350)
        self.installed_filter.setClearButtonEnabled(True)
        mid_layout = QHBoxLayout()
        mid_layout.addWidget(self.installed_label)
        mid_layout.addWidget(self.installed_filter)
        mid_layout.addStretch()
        lay.addLayout(mid_layout)

        self.installed_list = QPluginList(installed, self.installer)
        self.installed_filter.textChanged.connect(self.installed_list.filter)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        self.avail_filter = QLineEdit()
        self.avail_filter.setPlaceholderText("search...")
        self.avail_filter.setMaximumWidth(350)
        self.avail_filter.setClearButtonEnabled(True)
        mid_layout = QHBoxLayout()
        mid_layout.addWidget(self.avail_label)
        mid_layout.addWidget(self.avail_filter)
        mid_layout.addStretch()
        lay.addLayout(mid_layout)
        self.available_list = QPluginList(uninstalled, self.installer)
        self.avail_filter.textChanged.connect(self.available_list.filter)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)
        self.show_sorter_btn = QPushButton(trans._("<< Show Sorter"), self)
        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.accept)
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(60)
        buttonBox.addWidget(self.show_sorter_btn)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.show_sorter_btn.setCheckable(True)
        self.show_sorter_btn.setChecked(False)
        self.show_sorter_btn.toggled.connect(self._toggle_sorter)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

        self.avail_filter.setFocus()

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})", count=count))

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_sorter(self, show):
        if show:
            self.show_sorter_btn.setText(trans._(">> Hide Sorter"))
            self.plugin_sorter.show()
        else:
            self.show_sorter_btn.setText(trans._("<< Show Sorter"))
            self.plugin_sorter.hide()

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()
        if packages:
            self.installer.install(packages)
Ejemplo n.º 12
0
class SearchLauncher(QWidget):

    def __init__(self, parent):
        super().__init__()

        self.parent = parent

        # set title
        self.setWindowTitle(config.thisTranslation["tools"])
        # set up variables
        self.bibleSearchModeTuple = ("SEARCH", "SEARCHALL", "ANDSEARCH", "ORSEARCH", "ADVANCEDSEARCH", "REGEXSEARCH")
        config.bibleSearchRange = config.thisTranslation["all"]
        # setup interface
        self.setupUI()

    def setupUI(self):
        mainLayout0 = QVBoxLayout()
        mainLayout0.addWidget(self.searchFieldWidget())
        mainLayout = QHBoxLayout()
        mainLayout.addWidget(self.column1Widget())
        mainLayout.addWidget(self.column2Widget())
        mainLayout0.addLayout(mainLayout)
        self.setLayout(mainLayout0)
        self.searchField.clear()

    def column1Widget(self):
        widget = QWidget()

        widgetLayout0 = QVBoxLayout()

        bibleWidget = QGroupBox(config.thisTranslation["bible"])
        bibleLayout = QVBoxLayout()
        bibleLayout.setSpacing(10)
        self.bibleCombo = CheckableComboBox(self.parent.textList, [config.mainText], toolTips=self.parent.textFullNameList)
        bibleLayout.addLayout(self.parent.comboFeatureLayout("html_searchBible2", self.bibleCombo, self.searchBible))
        subLayout = QHBoxLayout()
        subLayout.setSpacing(5)
        leftGroupLayout = QVBoxLayout()
        centerGroupLayout = QVBoxLayout()
        rightGroupLayout = QVBoxLayout()
        subLayout.addLayout(leftGroupLayout)
        subLayout.addLayout(centerGroupLayout)
        subLayout.addLayout(rightGroupLayout)
        for index, searchMode in enumerate(self.bibleSearchModeTuple):
            radioButton = QRadioButton(searchMode)
            radioButton.setToolTip(config.thisTranslation["searchRB{0}".format(index)])
            radioButton.toggled.connect(lambda checked, mode=index: self.searchModeChanged(checked, mode))
            if index == config.bibleSearchMode:
                radioButton.setChecked(True)
            if index % 3 == 0:
                leftGroupLayout.addWidget(radioButton)
            elif index % 3 == 1:
                centerGroupLayout.addWidget(radioButton)
            else:
                rightGroupLayout.addWidget(radioButton)
        leftGroupLayout.addStretch()
        centerGroupLayout.addStretch()
        rightGroupLayout.addStretch()
        bibleLayout.addLayout(subLayout)

        if len(config.bibleCollections) > 0:
            navigationLayout6 = self.navigationLayout6()
            bibleLayout.addWidget(navigationLayout6)

        bibleWidget.setLayout(bibleLayout)
        
        widgetLayout0.addWidget(bibleWidget)

        # Books range selection
        booksWidget = QGroupBox(config.thisTranslation["menu10_books"])
        booksLayout = QHBoxLayout()
        booksLayout.setSpacing(1)
        for range in [config.thisTranslation["all"], "OT", "NT", "Custom"]:
            radioButton = QRadioButton(range)
            radioButton.toggled.connect(lambda checked, range=range: self.booksChanged(checked, range))
            if config.bibleSearchRange == range:
                radioButton.setChecked(True)
            booksLayout.addWidget(radioButton)
            if range == "Custom":
                self.customRangeRadioButton = radioButton
        self.customBooksRangeSearchField = QLineEdit()
        self.customBooksRangeSearchField.setText(config.customBooksRangeSearch)
        self.customBooksRangeSearchField.textChanged.connect(self.customBooksRangeChanged)
        booksLayout.addWidget(self.customBooksRangeSearchField)
        booksWidget.setLayout(booksLayout)
        widgetLayout0.addWidget(booksWidget)

        subLayout = QHBoxLayout()
        buttonRow = (
            ("menu_bookNotes", lambda: self.runSearchCommand("SEARCHBOOKNOTE")),
            ("menu_chapterNotes", lambda: self.runSearchCommand("SEARCHCHAPTERNOTE")),
            ("menu_verseNotes", lambda: self.runSearchCommand("SEARCHVERSENOTE")),
        )
        subLayout.addLayout(self.parent.buttonsLayout(buttonRow))
        #subLayout.addWidget(self.highlightNoteSearchResultCheckBox())
        #subLayout.addStretch()
        widgetLayout0.addLayout(subLayout)

        buttonRow1 = (
            ("menu5_names", lambda: self.runSearchCommand("SEARCHTOOL:::HBN")),
            ("menu5_characters", lambda: self.runSearchCommand("SEARCHTOOL:::EXLBP")),
            ("menu5_locations", lambda: self.runSearchCommand("SEARCHTOOL:::EXLBL")),
            ("biblePromises", lambda: self.runSearchCommand("SEARCHBOOK:::Bible_Promises")),
        )
        buttonRow2 = (
            ("bibleHarmonies", lambda: self.runSearchCommand("SEARCHBOOK:::Harmonies_and_Parallels")),
            ("menu5_allBook", lambda: self.runSearchCommand("SEARCHBOOK:::ALL")),
            ("favouriteBooks", lambda: self.runSearchCommand("SEARCHBOOK:::FAV")),
            ("pdfFiles", lambda: self.runSearchCommand("SEARCHPDF")),
        )
        buttonRow3 = (
            ("allBooksPDF", lambda: self.runSearchCommand("SEARCHALLBOOKSPDF")),
            ("_blank", lambda: self.blankOperation()),
            ("_blank", lambda: self.blankOperation()),
            ("_blank", lambda: self.blankOperation()),
        )
        widgetLayout0.addWidget(self.parent.buttonsWidget((buttonRow1, buttonRow2, buttonRow3)))

        widgetLayout0.addStretch()
        widget.setLayout(widgetLayout0)
        return widget

    def navigationLayout6(self):
        rows = []
        row = [
            ("All", lambda: self.selectCollection("All")),
            ("None", lambda: self.selectCollection("None")),
        ]
        count = len(row)
        for collection in sorted(config.bibleCollections.keys()):
            row.append((collection, partial(self.selectCollection, collection)))
            count += 1
            if count % 6 == 0:
                rows.append(row)
                row = []
        if len(row) > 0:
            rows.append(row)
        return self.parent.buttonsWidget(rows, False, False)

    def column2Widget(self):
        widget = QWidget()

        widgetLayout = QVBoxLayout()
        widgetLayout.setSpacing(10)

        subLayout = QHBoxLayout()
        self.bookCombo = CheckableComboBox(self.parent.referenceBookList, [config.book])
        subLayout.addLayout(self.parent.comboFeatureLayout("menu5_selectBook", self.bookCombo, self.searchBook))
        #checkbox = self.highlightBookSearchResultCheckBox()
        #subLayout.addWidget(checkbox)
        widgetLayout.addLayout(subLayout)

        self.topicCombo = QComboBox()
        initialTopicIndex = self.parent.topicListAbb.index(config.topic) if config.topic in self.parent.topicListAbb else 0
        self.lexiconCombo = QComboBox()
        initialLexiconIndex = self.parent.lexiconList.index(config.lexicon) if config.lexicon in self.parent.lexiconList else 0
        self.reverseLexiconCombo = QComboBox()
        initialReverseLexiconIndex = self.parent.lexiconList.index(config.lexicon) if config.lexicon in self.parent.lexiconList else 0
        self.encyclopediaCombo = QComboBox()
        initialEncyclopediaIndex = self.parent.encyclopediaListAbb.index(config.encyclopedia) if config.encyclopedia in self.parent.encyclopediaListAbb else 0
        self.dictionaryCombo = QComboBox()
        initialDictionaryIndex = self.parent.dictionaryListAbb.index(config.dictionary) if config.dictionary in self.parent.dictionaryListAbb else 0
        self.thirdPartyDictionaryCombo = QComboBox()
        initialThridPartyDictionaryIndex = self.parent.thirdPartyDictionaryList.index(config.thirdDictionary) if config.thirdDictionary in self.parent.thirdPartyDictionaryList else 0
        self.lexiconList = self.parent.lexiconList
        self.lexiconList.append(config.thisTranslation['searchAllLexicons'])
        self.dictionaryList = self.parent.dictionaryList
        self.dictionaryList.append(config.thisTranslation['searchAllDictionaries'])
        self.dictionaryListAbb = self.parent.dictionaryListAbb
        self.dictionaryListAbb.append(config.thisTranslation['searchAllDictionaries'])
        self.thirdPartyDictionaryList = self.parent.thirdPartyDictionaryList
        self.thirdPartyDictionaryList.append(config.thisTranslation['searchAllDictionaries'])

        features = (
            (self.topicCombo, "menu5_topics", lambda: self.runSearchSelection("topic"), self.parent.topicList, initialTopicIndex),
            (self.lexiconCombo, "menu5_lexicon", lambda: self.runSearchSelection("lexicon"), self.lexiconList, initialLexiconIndex),
            (self.reverseLexiconCombo, "menu5_reverseLexicon", lambda: self.runSearchSelection("reverselexicon"), self.lexiconList, initialReverseLexiconIndex),
            (self.encyclopediaCombo, "context1_encyclopedia", lambda: self.runSearchSelection("encyclopedia"), self.parent.encyclopediaList, initialEncyclopediaIndex),
            (self.dictionaryCombo, "context1_dict", lambda: self.runSearchSelection("dictionary"), self.dictionaryList, initialDictionaryIndex),
            (self.thirdPartyDictionaryCombo, "menu5_3rdDict", lambda: self.runSearchSelection("thirdPartyDictionary"), self.thirdPartyDictionaryList, initialThridPartyDictionaryIndex),
        )
        for combo, feature, action, items, initialIndex in features:
            widgetLayout.addLayout(self.singleSelectionLayout(combo, feature, action, items, initialIndex))

        widget.setLayout(widgetLayout)
        return widget

    def searchFieldWidget(self):
        self.searchField = QLineEdit()
        self.searchField.setClearButtonEnabled(True)
        self.searchField.setToolTip(config.thisTranslation["menu5_searchItems"])
        self.searchField.returnPressed.connect(self.searchBible)
        return self.searchField

    def singleSelectionLayout(self, combo, feature, action, items, initialIndex=0):
        combo.addItems(items)
        combo.setCurrentIndex(initialIndex)
        return self.parent.comboFeatureLayout(feature, combo, action)

    def highlightNoteSearchResultCheckBox(self):
        self.searchNoteCheckbox = QCheckBox()
        self.searchNoteCheckbox.setMaximumWidth(30)
        self.searchNoteCheckbox.setToolTip(config.thisTranslation["highlightNoteSearchResult"])
        self.searchNoteCheckbox.setChecked(True if config.noteSearchString else False)
        self.searchNoteCheckbox.stateChanged.connect(self.searchNoteCheckboxChanged)
        return self.searchNoteCheckbox

    def highlightBookSearchResultCheckBox(self):
        self.searchBookCheckbox = QCheckBox()
        self.searchBookCheckbox.setMaximumWidth(30)
        self.searchBookCheckbox.setToolTip(config.thisTranslation["highlightBookSearchResult"])
        self.searchBookCheckbox.setChecked(True if config.bookSearchString else False)
        self.searchBookCheckbox.stateChanged.connect(self.searchBookCheckboxChanged)
        return self.searchBookCheckbox

    # Button actions

    def searchModeChanged(self, checked, mode):
        if checked:
            config.bibleSearchMode = mode

    def booksChanged(self, checked, range):
        if checked:
            config.bibleSearchRange = range

    def customBooksRangeChanged(self, text):
        if len(text) > 0:
            self.customRangeRadioButton.setChecked(True)
            config.customBooksRangeSearch = text

    def getSearchItem(self):
        searchItem = self.searchField.text()
        noItemMessage = config.thisTranslation["menu5_searchItems"]
        if not searchItem:
            self.searchField.setText(noItemMessage)
            return ""
        elif searchItem == noItemMessage:
            return ""
        else:
            return searchItem

    def searchHighlight(self, index):
        command = "SEARCHHIGHLIGHT:::hl{0}".format(index + 1)
        self.parent.runTextCommand(command)

    def searchBible(self):
        searchItem = self.getSearchItem()
        if searchItem:
            command = "{0}:::{1}:::{2}".format(self.bibleSearchModeTuple[config.bibleSearchMode], "_".join(self.bibleCombo.checkItems), self.searchField.text())
            if config.bibleSearchRange == "Custom":
                command += ":::{0}".format(config.customBooksRangeSearch)
            elif config.bibleSearchRange != config.thisTranslation["all"]:
                command += ":::{0}".format(config.bibleSearchRange)
            self.parent.runTextCommand(command)

    def searchBook(self):
        searchItem = self.getSearchItem()
        if searchItem:
            command = "{0}:::{1}:::{2}".format("SEARCHBOOK", ",".join(self.bookCombo.checkItems), self.searchField.text())
            self.parent.runTextCommand(command)

    def searchBookCheckboxChanged(self, state):
        if not state:
            config.bookSearchString = ""
            self.parent.parent.reloadCurrentRecord()
            if config.closeControlPanelAfterRunningCommand and not self.isRefreshing:
                self.parent.hide()

    def searchNoteCheckboxChanged(self, state):
        if not state:
            config.noteSearchString = ""
            self.parent.parent.reloadCurrentRecord()
            if config.closeControlPanelAfterRunningCommand and not self.parent.isRefreshing:
                self.parent.hide()

    def runSearchCommand(self, prefix):
        searchItem = self.getSearchItem()
        if searchItem:
            command = "{0}:::{1}".format(prefix, self.searchField.text())
            self.parent.runTextCommand(command)

    def runSearchSelection(self, resource):
        searchItem = self.getSearchItem()
        if searchItem:
            comboDict = {
                "topic": (self.topicCombo, self.parent.topicListAbb),
                "lexicon": (self.lexiconCombo, self.lexiconList),
                "reverselexicon": (self.reverseLexiconCombo, self.lexiconList),
                "encyclopedia": (self.encyclopediaCombo, self.parent.encyclopediaListAbb),
                "dictionary": (self.dictionaryCombo, self.dictionaryListAbb),
                "thirdPartyDictionary": (self.thirdPartyDictionaryCombo, self.thirdPartyDictionaryList),
            }
            combo, resourceList = comboDict[resource]
            selectedItem = resourceList[combo.currentIndex()]
            if resource == "lexicon":
                keyword = "LEXICON"
            elif resource == "reverselexicon":
                keyword = "REVERSELEXICON"
            elif resource == "thirdPartyDictionary":
                keyword = "SEARCHTHIRDDICTIONARY"
            else:
                keyword = "SEARCHTOOL"
            prefix = "{0}:::{1}".format(keyword, selectedItem)
            self.runSearchCommand(prefix)

    def blankOperation(self):
        return

    def selectCollection(self, collection):
        if collection == "All":
            self.bibleCombo.checkAll()
        elif collection == "None":
            self.bibleCombo.clearAll()
        else:
            self.bibleCombo.checkFromList(config.bibleCollections[collection])
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
class MiniControl(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.setWindowTitle(config.thisTranslation["remote_control"])
        self.parent = parent
        # specify window size
        if config.qtMaterial and config.qtMaterialTheme:
            self.resizeWindow(1 / 2, 1 / 3)
        else:
            self.resizeWindow(2 / 5, 1 / 3)
        self.resizeEvent = (lambda old_method:
                            (lambda event:
                             (self.onResized(event), old_method(event))[-1]))(
                                 self.resizeEvent)
        # setup interface
        self.setupUI()

    # window appearance
    def resizeWindow(self, widthFactor, heightFactor):
        availableGeometry = QGuiApplication.instance().desktop(
        ).availableGeometry()
        self.setMinimumWidth(500)
        self.resize(availableGeometry.width() * widthFactor,
                    availableGeometry.height() * heightFactor)

    def onResized(self, event):
        pass

    def closeEvent(self, event):
        config.miniControl = False

    # manage key capture
    def event(self, event):
        if event.type() == QEvent.KeyRelease:
            if event.modifiers() == Qt.ControlModifier:
                if event.key() == Qt.Key_B:
                    self.tabs.setCurrentIndex(0)
                elif event.key() == Qt.Key_T:
                    self.tabs.setCurrentIndex(1)
                elif event.key() == Qt.Key_C:
                    self.tabs.setCurrentIndex(2)
                elif event.key() == Qt.Key_L:
                    self.tabs.setCurrentIndex(3)
                elif event.key() == Qt.Key_D:
                    self.tabs.setCurrentIndex(4)
            elif event.key() == Qt.Key_Escape:
                self.close()
        return QWidget.event(self, event)

    # setup ui
    def setupUI(self):
        mainLayout = QGridLayout()

        commandBox = QVBoxLayout()
        commandBox.setSpacing(3)

        commandBar = QWidget()
        commandLayout1 = QBoxLayout(QBoxLayout.LeftToRight)
        commandLayout1.setSpacing(5)
        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setClearButtonEnabled(True)
        self.searchLineEdit.setToolTip(
            config.thisTranslation["enter_command_here"])
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.searchLineEdit.setFixedWidth(300)
        commandLayout1.addWidget(self.searchLineEdit)

        enterButton = QPushButton(config.thisTranslation["enter"])
        enterButton.setFixedWidth(100)
        enterButton.clicked.connect(self.searchLineEntered)
        commandLayout1.addWidget(enterButton)

        commandLayout1.addStretch()
        commandBox.addLayout(commandLayout1)

        commandLayout2 = QBoxLayout(QBoxLayout.LeftToRight)
        commandLayout2.setSpacing(5)

        keys = [
            '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ':', '-', ',',
            '.', ' ', '<', 'X'
        ]
        for key in keys:
            button = QPushButton(key)
            button.setMaximumWidth(30)
            button.clicked.connect(partial(self.keyEntryAction, key))
            commandLayout2.addWidget(button)

        commandLayout2.addStretch()
        commandBox.addLayout(commandLayout2)

        if config.isTtsInstalled:
            ttsLayout = QBoxLayout(QBoxLayout.LeftToRight)
            ttsLayout.setSpacing(5)

            self.languageCombo = QComboBox()
            ttsLayout.addWidget(self.languageCombo)
            if config.espeak:
                languages = TtsLanguages().isoLang2epeakLang
            else:
                languages = TtsLanguages().isoLang2qlocaleLang
            self.languageCodes = list(languages.keys())
            for code in self.languageCodes:
                self.languageCombo.addItem(languages[code][1])
            # Check if selected tts engine has the language user specify.
            if not (config.ttsDefaultLangauge in self.languageCodes):
                config.ttsDefaultLangauge = "en"
            # Set initial item
            initialIndex = self.languageCodes.index(config.ttsDefaultLangauge)
            self.languageCombo.setCurrentIndex(initialIndex)

            # setting tts default language here is confusing; better place in menu
            #setDefaultButton = QPushButton(config.thisTranslation["setDefault"])
            #setDefaultButton.setFixedWidth(130)
            #setDefaultButton.clicked.connect(self.setTtsDefaultLanguage)
            #ttsLayout.addWidget(setDefaultButton)

            speakButton = QPushButton(config.thisTranslation["speak"])
            speakButton.setFixedWidth(100)
            speakButton.clicked.connect(self.speakCommandFieldText)
            ttsLayout.addWidget(speakButton)

            stopButton = QPushButton(config.thisTranslation["stop"])
            stopButton.setFixedWidth(100)
            stopButton.clicked.connect(
                self.parent.textCommandParser.stopTtsAudio)
            ttsLayout.addWidget(stopButton)

            ttsLayout.addStretch()

            commandBox.addLayout(ttsLayout)

        commandBar.setLayout(commandBox)
        mainLayout.addWidget(commandBar, 0, 0, Qt.AlignCenter)

        self.tabs = QTabWidget()
        self.tabs.currentChanged.connect(self.tabChanged)
        mainLayout.addWidget(self.tabs, 1, 0, Qt.AlignCenter)

        parser = BibleVerseParser(config.parserStandarisation)
        self.bookMap = parser.standardAbbreviation
        bookNums = list(self.bookMap.keys())
        bookNumGps = [
            bookNums[0:10],
            bookNums[10:20],
            bookNums[20:30],
            bookNums[30:39],
            bookNums[39:49],
            bookNums[49:59],
            bookNums[59:66],
        ]

        bible = QWidget()
        bible_layout = QVBoxLayout()
        bible_layout.setMargin(0)
        bible_layout.setSpacing(0)
        for bookNumGp in bookNumGps[0:5]:
            gp = QWidget()
            layout = self.newRowLayout()
            for bookNum in bookNumGp:
                text = self.bookMap[bookNum]
                button = QPushButton(text)
                button.clicked.connect(partial(self.bibleBookAction, bookNum))
                layout.addWidget(button)
            gp.setLayout(layout)
            bible_layout.addWidget(gp)

        for bookNumGp in bookNumGps[5:]:
            gp = QWidget()
            layout = self.newRowLayout()
            for bookNum in bookNumGp:
                text = self.bookMap[bookNum]
                button = QPushButton(text)
                button.clicked.connect(partial(self.bibleBookAction, bookNum))
                layout.addWidget(button)
            gp.setLayout(layout)
            bible_layout.addWidget(gp)

        bible_layout.addStretch()
        bible.setLayout(bible_layout)
        self.tabs.addTab(bible, config.thisTranslation["bible"])

        bibles_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setMargin(0)
        box_layout.setSpacing(0)
        row_layout = self.newRowLayout()
        biblesSqlite = BiblesSqlite()
        bibles = biblesSqlite.getBibleList()
        count = 0
        for bible in bibles:
            button = QPushButton(bible)
            button.clicked.connect(partial(self.bibleAction, bible))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        bibles_box.setLayout(box_layout)

        self.tabs.addTab(bibles_box, config.thisTranslation["translations"])

        commentaries_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setMargin(0)
        box_layout.setSpacing(0)
        row_layout = self.newRowLayout()
        commentaries = Commentary().getCommentaryList()
        count = 0
        for commentary in commentaries:
            button = QPushButton(commentary)
            button.clicked.connect(partial(self.commentaryAction, commentary))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        commentaries_box.setLayout(box_layout)

        self.tabs.addTab(commentaries_box,
                         config.thisTranslation["commentaries"])

        lexicons_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setMargin(0)
        box_layout.setSpacing(0)
        row_layout = self.newRowLayout()
        lexicons = LexiconData().lexiconList
        count = 0
        for lexicon in lexicons:
            button = QPushButton(lexicon)
            button.clicked.connect(partial(self.lexiconAction, lexicon))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        lexicons_box.setLayout(box_layout)

        self.tabs.addTab(lexicons_box, config.thisTranslation["lexicons"])

        dictionaries_box = QWidget()
        box_layout = QVBoxLayout()
        box_layout.setMargin(0)
        box_layout.setSpacing(0)
        row_layout = self.newRowLayout()
        dictionaries = IndexesSqlite().dictionaryList
        count = 0
        for dictionary in dictionaries:
            button = QPushButton(dictionary[0])
            button.setToolTip(dictionary[1])
            button.clicked.connect(
                partial(self.dictionaryAction, dictionary[0]))
            row_layout.addWidget(button)
            count += 1
            if count > 6:
                count = 0
                box_layout.addLayout(row_layout)
                row_layout = self.newRowLayout()
        box_layout.addLayout(row_layout)
        box_layout.addStretch()
        dictionaries_box.setLayout(box_layout)

        self.tabs.addTab(dictionaries_box,
                         config.thisTranslation["dictionaries"])
        self.tabs.setCurrentIndex(config.miniControlInitialTab)
        self.setLayout(mainLayout)

    def newRowLayout(self):
        row_layout = QHBoxLayout()
        row_layout.setSpacing(0)
        row_layout.setMargin(0)
        return row_layout

    def tabChanged(self, index):
        prefix = ""
        if index == 0:
            prefix = "BIBLE:::{0}:::".format(config.mainText)
        elif index == 1:
            prefix = "TEXT:::"
        elif index == 2:
            prefix = "COMMENTARY:::{0}:::".format(config.commentaryText)
        elif index == 3:
            prefix = "LEXICON:::"
        elif index == 4:
            prefix = "SEARCHTOOL:::"
        if not config.clearCommandEntry:
            self.searchLineEdit.setText(prefix)

    def searchLineEntered(self):
        searchString = self.searchLineEdit.text()
        self.parent.textCommandLineEdit.setText(searchString)
        self.parent.runTextCommand(searchString)
        self.searchLineEdit.setFocus()

    #def setTtsDefaultLanguage(self):
    #config.ttsDefaultLangauge = self.languageCodes[self.languageCombo.currentIndex()]

    def speakCommandFieldText(self):
        text = self.searchLineEdit.text()
        if ":::" in text:
            text = text.split(":::")[-1]
        command = "SPEAK:::{0}:::{1}".format(
            self.languageCodes[self.languageCombo.currentIndex()], text)
        self.runCommmand(command)

    def bibleBookAction(self, book):
        command = "{0} ".format(self.bookMap[book])
        self.runCommmand(command)
        self.searchLineEdit.setFocus()

    def keyEntryAction(self, key):
        text = self.searchLineEdit.text()
        if key == "X":
            text = ""
        elif key == "<":
            text = text[:-1]
        else:
            text += key
        self.searchLineEdit.setText(text)

    def bibleAction(self, bible):
        command = "BIBLE:::{0}:::{1}".format(
            bible,
            self.parent.verseReference("main")[1])
        self.runCommmand(command)
        command = "_bibleinfo:::{0}".format(bible)
        self.parent.runTextCommand(command)

    def commentaryAction(self, commentary):
        command = "COMMENTARY:::{0}:::{1}".format(
            commentary,
            self.parent.verseReference("main")[1])
        self.runCommmand(command)
        command = "_commentaryinfo:::{0}".format(commentary)
        self.parent.runTextCommand(command)

    def lexiconAction(self, lexicon):
        command = "LEXICON:::{0}:::{1}".format(
            lexicon, TextCommandParser.last_lexicon_entry)
        self.runCommmand(command)

    def dictionaryAction(self, dictionary):
        command = "SEARCHTOOL:::{0}:::{1}".format(
            dictionary, TextCommandParser.last_text_search)
        self.runCommmand(command)

    def runCommmand(self, command):
        self.searchLineEdit.setText(command)
        self.parent.runTextCommand(command)
        self.parent.textCommandLineEdit.setText(command)
Ejemplo n.º 15
0
class NoteEditor(QMainWindow):

    def __init__(self, parent, noteType, noteFileName="", b=None, c=None, v=None):
        super().__init__()
        self.parent, self.noteType = parent, noteType
        self.noteFileName = noteFileName
        if not self.noteType == "file":
            if v:
                self.b, self.c, self.v = b, c, v
            else:
                self.b, self.c, self.v = config.studyB, config.studyC, config.studyV

        # default - "Rich" mode for editing
        self.html = True
        # default - text is not modified; no need for saving new content
        self.parent.noteSaved = True
        config.noteOpened = True
        config.lastOpenedNote = (noteType, b, c, v)

        # specify window size
        self.resizeWindow(2/3, 2/3)

        # setup interface
        self.setupMenuBar()
        self.addToolBarBreak()
        self.setupToolBar()
        if config.hideNoteEditorStyleToolbar:
            self.toolBar.hide()
        self.addToolBarBreak()
        self.setupTextUtility()
        if config.hideNoteEditorTextUtility:
            self.ttsToolbar.hide()
            self.translateToolbar.hide()
        self.setupLayout()

        # display content when first launched
        self.displayInitialContent()
        self.editor.setFocus()

        # specify window title
        self.updateWindowTitle()

    # re-implementing close event, when users close this widget
    def closeEvent(self, event):
        if self.parent.noteSaved:
            config.noteOpened = False
            event.accept()
            if config.lastOpenedNote and config.openBibleNoteAfterEditorClosed:
                #if config.lastOpenedNote[0] == "file":
                #    self.parent.externalFileButtonClicked()
                if config.lastOpenedNote[0] == "book":
                    self.parent.openStudyBookNote()
                elif config.lastOpenedNote[0] == "chapter":
                    self.parent.openStudyChapterNote()
                elif config.lastOpenedNote[0] == "verse":
                    self.parent.openStudyVerseNote()
        else:
            if self.parent.warningNotSaved():
                self.parent.noteSaved = True
                config.noteOpened = False
                event.accept()
            else:
                self.parent.bringToForeground(self)
                event.ignore()

    # re-implement keyPressEvent, control+S for saving file
    def keyPressEvent(self, event):
        keys = {
            Qt.Key_O: self.openFileDialog,
            Qt.Key_S: self.saveNote,
            Qt.Key_B: self.format_bold,
            Qt.Key_I: self.format_italic,
            Qt.Key_U: self.format_underline,
            Qt.Key_M: self.format_custom,
            Qt.Key_D: self.format_clear,
            Qt.Key_F: self.focusSearchField,
        }
        key = event.key()
        if event.modifiers() == Qt.ControlModifier and key in keys:
            keys[key]()

    # window appearance
    def resizeWindow(self, widthFactor, heightFactor):
        availableGeometry = QGuiApplication.instance().desktop().availableGeometry()
        self.resize(availableGeometry.width() * widthFactor, availableGeometry.height() * heightFactor)

    def updateWindowTitle(self):
        if self.noteType == "file":
            if self.noteFileName:
                *_, title = os.path.split(self.noteFileName)
            else:
                title = "NEW"
        else:
            title = self.parent.bcvToVerseReference(self.b, self.c, self.v)
            if self.noteType == "book":
                title, *_ = title.split(" ")            
            elif self.noteType == "chapter":
                title, *_ = title.split(":")
        mode = {True: "rich", False: "plain"}
        notModified = {True: "", False: " [modified]"}
        self.setWindowTitle("Note Editor ({1} mode) - {0}{2}".format(title, mode[self.html], notModified[self.parent.noteSaved]))

    # switching between "rich" & "plain" mode
    def switchMode(self):
        if self.html:
            note = self.editor.toHtml()
            note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note)
            self.editor.setPlainText(note)
            self.html = False
            self.updateWindowTitle()
        else:
            note = self.editor.toPlainText()
            self.editor.setHtml(note)
            self.html = True
            self.updateWindowTitle()
        # without this hide / show command below, QTextEdit does not update the text in some devices
        self.hide()
        self.show()

    def setupMenuBar(self):
        if config.toolBarIconFullSize:
            self.setupMenuBarFullIconSize()
        else:
            self.setupMenuBarStandardIconSize()

    def setupMenuBarStandardIconSize(self):

        self.menuBar = QToolBar()
        self.menuBar.setWindowTitle(config.thisTranslation["note_title"])
        self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # In QWidget, self.menuBar is treated as the menubar without the following line
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.menuBar)

        newButton = QPushButton()
        newButton.setToolTip("{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"]))
        newButtonFile = os.path.join("htmlResources", "newfile.png")
        newButton.setIcon(QIcon(newButtonFile))
        newButton.clicked.connect(self.newNoteFile)
        self.menuBar.addWidget(newButton)

        openButton = QPushButton()
        openButton.setToolTip("{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"]))
        openButtonFile = os.path.join("htmlResources", "open.png")
        openButton.setIcon(QIcon(openButtonFile))
        openButton.clicked.connect(self.openFileDialog)
        self.menuBar.addWidget(openButton)

        self.menuBar.addSeparator()

        saveButton = QPushButton()
        saveButton.setToolTip("{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"]))
        saveButtonFile = os.path.join("htmlResources", "save.png")
        saveButton.setIcon(QIcon(saveButtonFile))
        saveButton.clicked.connect(self.saveNote)
        self.menuBar.addWidget(saveButton)

        saveAsButton = QPushButton()
        saveAsButton.setToolTip(config.thisTranslation["note_saveAs"])
        saveAsButtonFile = os.path.join("htmlResources", "saveas.png")
        saveAsButton.setIcon(QIcon(saveAsButtonFile))
        saveAsButton.clicked.connect(self.openSaveAsDialog)
        self.menuBar.addWidget(saveAsButton)

        self.menuBar.addSeparator()

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_print"])
        toolBarButtonFile = os.path.join("htmlResources", "print.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.printNote)
        self.menuBar.addWidget(toolBarButton)

        self.menuBar.addSeparator()

        switchButton = QPushButton()
        switchButton.setToolTip(config.thisTranslation["note_mode"])
        switchButtonFile = os.path.join("htmlResources", "switch.png")
        switchButton.setIcon(QIcon(switchButtonFile))
        switchButton.clicked.connect(self.switchMode)
        self.menuBar.addWidget(switchButton)

        self.menuBar.addSeparator()

#        decreaseFontSizeButton = QPushButton()
#        decreaseFontSizeButton.setToolTip(config.thisTranslation["menu2_smaller"])
#        decreaseFontSizeButtonFile = os.path.join("htmlResources", "fontMinus.png")
#        decreaseFontSizeButton.setIcon(QIcon(decreaseFontSizeButtonFile))
#        decreaseFontSizeButton.clicked.connect(self.decreaseNoteEditorFontSize)
#        self.menuBar.addWidget(decreaseFontSizeButton)
#
#        increaseFontSizeButton = QPushButton()
#        increaseFontSizeButton.setToolTip(config.thisTranslation["menu2_larger"])
#        increaseFontSizeButtonFile = os.path.join("htmlResources", "fontPlus.png")
#        increaseFontSizeButton.setIcon(QIcon(increaseFontSizeButtonFile))
#        increaseFontSizeButton.clicked.connect(self.increaseNoteEditorFontSize)
#        self.menuBar.addWidget(increaseFontSizeButton)

#        self.menuBar.addSeparator()

        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setClearButtonEnabled(True)
        self.searchLineEdit.setToolTip(config.thisTranslation["menu5_search"])
        self.searchLineEdit.setMaximumWidth(400)
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.menuBar.addWidget(self.searchLineEdit)

        self.menuBar.addSeparator()

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_toolbar"])
        toolBarButtonFile = os.path.join("htmlResources", "toolbar.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.toggleToolbar)
        self.menuBar.addWidget(toolBarButton)

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_textUtility"])
        toolBarButtonFile = os.path.join("htmlResources", "textUtility.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.toggleTextUtility)
        self.menuBar.addWidget(toolBarButton)

        self.menuBar.addSeparator()

    def setupMenuBarFullIconSize(self):

        self.menuBar = QToolBar()
        self.menuBar.setWindowTitle(config.thisTranslation["note_title"])
        self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # In QWidget, self.menuBar is treated as the menubar without the following line
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.menuBar)

        iconFile = os.path.join("htmlResources", "newfile.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"]), self.newNoteFile)

        iconFile = os.path.join("htmlResources", "open.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"]), self.openFileDialog)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "save.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"]), self.saveNote)

        iconFile = os.path.join("htmlResources", "saveas.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_saveAs"], self.openSaveAsDialog)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "print.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_print"], self.printNote)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "switch.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_mode"], self.switchMode)

        self.menuBar.addSeparator()

#        iconFile = os.path.join("htmlResources", "fontMinus.png")
#        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_smaller"], self.decreaseNoteEditorFontSize)
#
#        iconFile = os.path.join("htmlResources", "fontPlus.png")
#        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_larger"], self.increaseNoteEditorFontSize)

#        self.menuBar.addSeparator()

        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setToolTip("{0}\n[Ctrl/Cmd + F]".format(config.thisTranslation["menu5_search"]))
        self.searchLineEdit.setMaximumWidth(400)
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.menuBar.addWidget(self.searchLineEdit)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "toolbar.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_toolbar"], self.toggleToolbar)

        iconFile = os.path.join("htmlResources", "textUtility.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_textUtility"], self.toggleTextUtility)

        self.menuBar.addSeparator()

    def toggleToolbar(self):
        if config.hideNoteEditorStyleToolbar:
            self.toolBar.show()
            config.hideNoteEditorStyleToolbar = False
        else:
            self.toolBar.hide()
            config.hideNoteEditorStyleToolbar = True

    def toggleTextUtility(self):
        if config.hideNoteEditorTextUtility:
            self.ttsToolbar.show()
            self.translateToolbar.show()
            config.hideNoteEditorTextUtility = False
        else:
            self.ttsToolbar.hide()
            self.translateToolbar.hide()
            config.hideNoteEditorTextUtility = True

    def printNote(self):
        #document = QTextDocument("Sample Page")
        document = self.editor.document()
        printer = QPrinter()

        myPrintDialog = QPrintDialog(printer, self)
        if myPrintDialog.exec_() == QDialog.Accepted:
            return document.print_(printer)

    def setupToolBar(self):
        if config.toolBarIconFullSize:
            self.setupToolBarFullIconSize()
        else:
            self.setupToolBarStandardIconSize()

    def setupToolBarStandardIconSize(self):

        self.toolBar = QToolBar()
        self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.toolBar)
        
        items = (
            ("noteTool_textFont", "font.png", self.format_font),
            ("noteTool_textColor", "textColor.png", self.format_textColor),
            ("noteTool_textBackgroundColor", "textBgColor.png", self.format_textBackgroundColor),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_header1", "header1.png", self.format_header1),
            ("noteTool_header2", "header2.png", self.format_header2),
            ("noteTool_header3", "header3.png", self.format_header3),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()
        
        items = (
            ("{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), "bold.png", self.format_bold),
            ("{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), "italic.png", self.format_italic),
            ("{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), "underline.png", self.format_underline),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_superscript", "superscript.png", self.format_superscript),
            ("noteTool_subscript", "subscript.png", self.format_subscript),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), "custom.png", self.format_custom, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_left", "align_left.png", self.format_left),
            ("noteTool_centre", "align_center.png", self.format_center),
            ("noteTool_right", "align_right.png", self.format_right),
            ("noteTool_justify", "align_justify.png", self.format_justify),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), "clearFormat.png", self.format_clear, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_hyperlink", "hyperlink.png", self.openHyperlinkDialog),
            ("noteTool_externalImage", "gallery.png", self.openImageDialog),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_image", "addImage.png", self.addInternalImage),
            ("noteTool_exportImage", "export.png", self.exportNoteImages),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

    def setupToolBarFullIconSize(self):

        self.toolBar = QToolBar()
        self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.toolBar)

        iconFile = os.path.join("htmlResources", "font.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textFont"], self.format_font)

        iconFile = os.path.join("htmlResources", "textColor.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textColor"], self.format_textColor)

        iconFile = os.path.join("htmlResources", "textBgColor.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textBackgroundColor"], self.format_textBackgroundColor)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "header1.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header1"], self.format_header1)

        iconFile = os.path.join("htmlResources", "header2.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header2"], self.format_header2)

        iconFile = os.path.join("htmlResources", "header3.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header3"], self.format_header3)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "bold.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), self.format_bold)

        iconFile = os.path.join("htmlResources", "italic.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), self.format_italic)

        iconFile = os.path.join("htmlResources", "underline.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), self.format_underline)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "custom.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), self.format_custom)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "align_left.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_left"], self.format_left)

        iconFile = os.path.join("htmlResources", "align_center.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_centre"], self.format_center)

        iconFile = os.path.join("htmlResources", "align_right.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_right"], self.format_right)

        iconFile = os.path.join("htmlResources", "align_justify.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_justify"], self.format_justify)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "clearFormat.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), self.format_clear)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "hyperlink.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_hyperlink"], self.openHyperlinkDialog)

        iconFile = os.path.join("htmlResources", "gallery.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_externalImage"], self.openImageDialog)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "addImage.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_image"], self.addInternalImage)

        iconFile = os.path.join("htmlResources", "export.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_exportImage"], self.exportNoteImages)

        self.toolBar.addSeparator()

    def setupLayout(self):
        self.editor = QTextEdit()  
        self.editor.setStyleSheet("font-family:'{0}'; font-size:{1}pt;".format(config.font, config.fontSize));
        self.editor.textChanged.connect(self.textChanged)
        self.setCentralWidget(self.editor)

        #self.layout = QGridLayout()
        #self.layout.setMenuBar(self.menuBar)
        #self.layout.addWidget(self.toolBar, 0, 0)
        #self.layout.addWidget(self.editor, 1, 0)
        #self.setLayout(self.layout)

    # adjustment of note editor font size
    def increaseNoteEditorFontSize(self):
        if self.html:
            self.editor.selectAll()
            config.noteEditorFontSize += 1
            self.editor.setFontPointSize(config.noteEditorFontSize)
            self.hide()
            self.show()

    def decreaseNoteEditorFontSize(self):
        if self.html and not config.noteEditorFontSize == 0:
            self.editor.selectAll()
            config.noteEditorFontSize -= 1
            self.editor.setFontPointSize(config.noteEditorFontSize)
            self.hide()
            self.show()

    # search field entered
    def searchLineEntered(self):
        searchString = self.searchLineEdit.text()
        if searchString:
            cursor = self.editor.document().find(searchString, self.editor.textCursor())
        if cursor:
            self.editor.setTextCursor(cursor)
        self.hide()
        self.show()

    def focusSearchField(self):
        self.searchLineEdit.setFocus()

    # track if the text being modified
    def textChanged(self):
        if self.parent.noteSaved:
            self.parent.noteSaved = False
            self.updateWindowTitle()

    # display content when first launched
    def displayInitialContent(self):
        if self.noteType == "file":
            if self.noteFileName:
                self.openNoteFile(self.noteFileName)
            else:
                self.newNoteFile()
        else:
            self.openBibleNote()

        self.editor.selectAll()
        self.editor.setFontPointSize(config.noteEditorFontSize)
        self.editor.moveCursor(QTextCursor.Start, QTextCursor.MoveAnchor)

        self.parent.noteSaved = True

    def getEmptyPage(self):
        strict = ''
        if config.includeStrictDocTypeInNote:
            strict = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">'
        return """{4}<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li {0} white-space: pre-wrap; {1}
</style></head><body style="font-family:'{2}'; font-size:{3}pt; font-weight:400; font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""\
            .format("{", "}", config.font, config.fontSize, strict)

    # load chapter / verse notes from sqlite database
    def openBibleNote(self):
        if self.noteType == "book":
            note = NoteService.getBookNote(self.b)
        elif self.noteType == "chapter":
            note = NoteService.getChapterNote(self.b, self.c)
        elif self.noteType == "verse":
            note = NoteService.getVerseNote(self.b, self.c, self.v)
        if note == config.thisTranslation["empty"]:
            note = self.getEmptyPage()
        else:
            note = self.fixNoteFont(note)
        if self.html:
            self.editor.setHtml(note)
        else:
            self.editor.setPlainText(note)

    # File I / O
    def newNoteFile(self):
        if self.parent.noteSaved:
            self.newNoteFileAction()
        elif self.parent.warningNotSaved():
            self.newNoteFileAction()

    def newNoteFileAction(self):
        self.noteType = "file"
        self.noteFileName = ""
        #self.editor.clear()
        defaultText = self.getEmptyPage()
        if self.html:
            self.editor.setHtml(defaultText)
        else:
            self.editor.setPlainText(defaultText)
        self.parent.noteSaved = True
        self.updateWindowTitle()
        self.hide()
        self.show()

    def openFileDialog(self):
        if self.parent.noteSaved:
            self.openFileDialogAction()
        elif self.parent.warningNotSaved():
            self.openFileDialogAction()

    def openFileDialogAction(self):
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getOpenFileName(self,
                config.thisTranslation["menu7_open"],
                "notes",
                "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options)
        if fileName:
            self.openNoteFile(fileName)

    def openNoteFile(self, fileName):
        try:
            f = open(fileName, "r", encoding="utf-8")
        except:
            print("Failed to open '{0}'".format(fileName))
        note = f.read()
        f.close()
        self.noteType = "file"
        self.noteFileName = fileName
        note = self.fixNoteFont(note)
        if self.html:
            self.editor.setHtml(note)
        else:
            self.editor.setPlainText(note)
        self.parent.noteSaved = True
        self.updateWindowTitle()
        self.hide()
        self.show()

    def saveNote(self):
        if self.html:
            note = self.editor.toHtml()
        else:
            note = self.editor.toPlainText()
        note = self.fixNoteFont(note)
        if self.noteType == "book":
            NoteService.saveBookNote(self.b, note)
            if config.openBibleNoteAfterSave:
                self.parent.openBookNote(self.b,)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "chapter":
            NoteService.saveChapterNote(self.b, self.c, note)
            if config.openBibleNoteAfterSave:
                self.parent.openChapterNote(self.b, self.c)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "verse":
            NoteService.saveVerseNote(self.b, self.c, self.v, note)
            if config.openBibleNoteAfterSave:
                self.parent.openVerseNote(self.b, self.c, self.v)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "file":
            if self.noteFileName == "":
                self.openSaveAsDialog()
            else:
                self.saveAsNote(self.noteFileName)

    def openSaveAsDialog(self):
        if self.noteFileName:
            *_, defaultName = os.path.split(self.noteFileName)
        else:
            defaultName = "new.uba"
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getSaveFileName(self,
                config.thisTranslation["note_saveAs"],
                os.path.join("notes", defaultName),
                "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options)
        if fileName:
            if not "." in os.path.basename(fileName):
                fileName = fileName + ".uba"
            self.saveAsNote(fileName)

    def saveAsNote(self, fileName):
        if self.html:
            note = self.editor.toHtml()
        else:
            note = self.editor.toPlainText()
        note = self.fixNoteFont(note)
        f = open(fileName, "w", encoding="utf-8")
        f.write(note)
        f.close()
        self.noteFileName = fileName
        self.parent.addExternalFileHistory(fileName)
        self.parent.setExternalFileButton()
        self.parent.noteSaved = True
        self.updateWindowTitle()

    def fixNoteFont(self, note):
        note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note)
        if not config.includeStrictDocTypeInNote:
            note = re.sub("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">\n""", "", note)
        return note


    # formatting styles
    def format_clear(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                selectedText = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, selectedText)
                self.editor.insertHtml(selectedText)
            else:
                selectedText = re.sub("<[^\n<>]*?>", "", selectedText)
                self.editor.insertPlainText(selectedText)
        else:
            self.selectTextFirst()

    def format_header1(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h1>{0}</h1>".format(selectedText))
            else:
                self.editor.insertPlainText("<h1>{0}</h1>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_header2(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h2>{0}</h2>".format(selectedText))
            else:
                self.editor.insertPlainText("<h2>{0}</h2>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_header3(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h3>{0}</h3>".format(selectedText))
            else:
                self.editor.insertPlainText("<h3>{0}</h3>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_font(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            ok, font = QFontDialog.getFont(QFont(config.font, config.fontSize), self)
            if ok:
                if self.html:
                    self.editor.setCurrentFont(font)
                else:
                    fontFamily, fontSize, i1, i2, fontWeight, italic, underline, strikeout, *_ = font.key().split(",")
                    spanTag = """<span style="font-family:'{0}'; font-size:{1}pt;""".format(fontFamily, fontSize)
                    # add font weight
                    if fontWeight == "25":
                        spanTag += " font-weight:200;"
                    elif fontWeight == "75":
                        spanTag += " font-weight:600;"
                    # add italic style
                    if italic == "1":
                        spanTag += " font-style:italic;"
                    # add both underline and strikeout style
                    if underline == "1" and strikeout == "1":
                        spanTag += " text-decoration: underline line-through;"
                    # add underline style
                    elif underline == "1":
                        spanTag += " text-decoration: underline;"
                    # add strikeout style
                    elif strikeout == "1":
                        spanTag += " text-decoration: line-through;"
                    # close tag
                    spanTag += '">'
                    self.editor.insertPlainText("{0}{1}</span>".format(spanTag, selectedText))
        else:
            self.selectTextFirst()
        
    def format_textColor(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            color = QColorDialog.getColor(Qt.darkRed, self)
            if color.isValid():
                if self.html:
                    self.editor.setTextColor(color)
                else:
                    self.editor.insertPlainText('<span style="color:{0};">{1}</span>'.format(color.name(), self.editor.textCursor().selectedText()))
        else:
            self.selectTextFirst()

    def format_textBackgroundColor(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            color = QColorDialog.getColor(Qt.yellow, self)
            if color.isValid():
                if self.html:
                    self.editor.setTextBackgroundColor(color)
                else:
                    self.editor.insertPlainText('<span style="background-color:{0};">{1}</span>'.format(color.name(), selectedText))
        else:
            self.selectTextFirst()

    def format_bold(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                # Reference: https://doc.qt.io/qt-5/qfont.html#Weight-enum
                # Bold = 75
                self.editor.setFontWeight(75)
            else:
                self.editor.insertPlainText("<b>{0}</b>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_italic(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setFontItalic(True)
            else:
                self.editor.insertPlainText("<i>{0}</i>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_underline(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setFontUnderline(True)
            else:
                self.editor.insertPlainText("<u>{0}</u>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_superscript(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<sup>{0}</sup>".format(selectedText))
            else:
                self.editor.insertPlainText("<sup>{0}</sup>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_subscript(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<sub>{0}</sub>".format(selectedText))
            else:
                self.editor.insertPlainText("<sub>{0}</sub>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_center(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignCenter)
            else:
                self.editor.insertPlainText("<div style='text-align:center;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_justify(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignJustify)
            else:
                self.editor.insertPlainText("<div style='text-align:justify;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_left(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignLeft)
            else:
                self.editor.insertPlainText("<div style='text-align:left;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_right(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignRight)
            else:
                self.editor.insertPlainText("<div style='text-align:right;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_custom(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            selectedText = self.customFormat(selectedText)
            if self.html:
                self.editor.insertHtml(selectedText)
            else:
                self.editor.insertPlainText(selectedText)
        else:
            self.selectTextFirst()

    def customFormat(self, text):
        # QTextEdit's line break character by pressing ENTER in plain & html mode "
"
        # please note that "
" is not an empty string
        text = text.replace("
", "\n")

        text = re.sub("^\*[0-9]+? (.*?)$", r"<ol><li>\1</li></ol>", text, flags=re.M)
        text = text.replace("</ol>\n<ol>", "\n")
        text = re.sub("^\* (.*?)$", r"<ul><li>\1</li></ul>", text, flags=re.M)
        text = text.replace("</ul>\n<ul>", "\n")
        text = re.sub("^{.*?}$", self.formatHTMLTable, text, flags=re.M)
        text = text.replace("</table>\n<table>", "\n")

        # add style to table here
        # please note that QTextEdit supports HTML 4, rather than HTML 5
        # take this old reference: https://www.w3schools.com/tags/tag_table.asp
        text = text.replace('<table>', '<table border="1" cellpadding="5">')

        # convert back to QTextEdit linebreak
        text = text.replace("\n", "
")

        # wrap with default font and font-size
        text = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, text)
        return text

    def formatHTMLTable(self, match):
        row = match.group()[1:-1]
        row = "".join(["<td>{0}</td>".format(cell) for cell in row.split("|")])
        return "<table><tr>{0}</tr></table>".format(row)

    def addInternalImage(self):
        self.openImageDialog(external=False)

    def openImageDialog(self, external=True):
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getOpenFileName(self,
                config.thisTranslation["html_open"],
                self.parent.openFileNameLabel.text(),
                "JPG Files (*.jpg);;JPEG Files (*.jpeg);;PNG Files (*.png);;GIF Files (*.gif);;BMP Files (*.bmp);;All Files (*)", "", options)
        if fileName:
            if external:
                self.linkExternalImage(fileName)
            else:
                self.embedImage(fileName)

    def embedImage(self, fileName):
        name, extension = os.path.splitext(os.path.basename(fileName))
        with open(fileName, "rb") as fileObject:
            binaryData = fileObject.read()
            encodedData = base64.b64encode(binaryData)
            asciiString = encodedData.decode('ascii')
            imageTag = '<img src="data:image/{2};base64,{0}" alt="{1}">'.format(asciiString, name, extension[1:])
            if self.html:
                self.editor.insertHtml(imageTag)
            else:
                self.editor.insertPlainText(imageTag)

    def exportNoteImages(self):
        options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
        directory = QFileDialog.getExistingDirectory(self,
                config.thisTranslation["select_a_folder"],
                self.parent.directoryLabel.text(), options)
        if directory:
            if self.html:
                htmlText = self.editor.toHtml()
            else:
                htmlText = self.editor.toPlainText()
            searchPattern = r'src=(["{0}])data:image/([^<>]+?);[ ]*?base64,[ ]*?([^ <>]+?)\1'.format("'")
            for counter, value in enumerate(re.findall(searchPattern, htmlText)):
                *_, ext, asciiString = value
                binaryString = asciiString.encode("ascii")
                binaryData = base64.b64decode(binaryString)
                imageFilePath = os.path.join(directory, "image{0}.{1}".format(counter + 1, ext))
                with open(imageFilePath, "wb") as fileObject:
                    fileObject.write(binaryData)

    def linkExternalImage(self, fileName):
        imageTag = '<img src="{0}" alt="UniqueBible.app">'.format(fileName)
        if self.html:
            self.editor.insertHtml(imageTag)
        else:
            self.editor.insertPlainText(imageTag)

    def openHyperlinkDialog(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            text, ok = QInputDialog.getText(self, "UniqueBible.app",
                    config.thisTranslation["noteTool_hyperlink"], QLineEdit.Normal,
                    selectedText)
            if ok and text != '':
                hyperlink = '<a href="{0}">{1}</a>'.format(text, selectedText)
                hyperlink = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, hyperlink)
                if self.html:
                    self.editor.insertHtml(hyperlink)
                else:
                    self.editor.insertPlainText(hyperlink)
        else:
            self.selectTextFirst()

    def setupTextUtility(self):

        self.ttsToolbar = QToolBar()
        self.ttsToolbar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.ttsToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.ttsToolbar)

        self.languageCombo = QComboBox()
        self.ttsToolbar.addWidget(self.languageCombo)
        if config.espeak:
            languages = TtsLanguages().isoLang2epeakLang
        else:
            languages = TtsLanguages().isoLang2qlocaleLang
        self.languageCodes = list(languages.keys())
        for code in self.languageCodes:
            self.languageCombo.addItem(languages[code][1])
        # Check if selected tts engine has the language user specify.
        if not (config.ttsDefaultLangauge in self.languageCodes):
            config.ttsDefaultLangauge = "en"
        # Set initial item
        initialIndex = self.languageCodes.index(config.ttsDefaultLangauge)
        self.languageCombo.setCurrentIndex(initialIndex)

        button = QPushButton(config.thisTranslation["speak"])
        button.setToolTip(config.thisTranslation["speak"])
        button.clicked.connect(self.speakText)
        self.ttsToolbar.addWidget(button)
        button = QPushButton(config.thisTranslation["stop"])
        button.setToolTip(config.thisTranslation["stop"])
        button.clicked.connect(self.parent.textCommandParser.stopTtsAudio)
        self.ttsToolbar.addWidget(button)

        self.translateToolbar = QToolBar()
        self.translateToolbar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.translateToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.translateToolbar)

        self.fromLanguageCombo = QComboBox()
        self.translateToolbar.addWidget(self.fromLanguageCombo)
        self.fromLanguageCombo.addItems(["[Auto]"] +Translator.fromLanguageNames)
        initialIndex = 0
        self.fromLanguageCombo.setCurrentIndex(initialIndex)

        button = QPushButton(config.thisTranslation["context1_translate"])
        button.setToolTip(config.thisTranslation["context1_translate"])
        button.clicked.connect(self.translateText)
        self.translateToolbar.addWidget(button)

        self.toLanguageCombo = QComboBox()
        self.translateToolbar.addWidget(self.toLanguageCombo)
        self.toLanguageCombo.addItems(Translator.toLanguageNames)
        initialIndex = Translator.toLanguageNames.index(config.userLanguage)
        self.toLanguageCombo.setCurrentIndex(initialIndex)

    def speakText(self):
        text = self.editor.textCursor().selectedText()
        if text:
            if config.isTtsInstalled:
                if ":::" in text:
                    text = text.split(":::")[-1]
                command = "SPEAK:::{0}:::{1}".format(self.languageCodes[self.languageCombo.currentIndex()], text)
                self.parent.runTextCommand(command)
            else:
                self.displayMessage(config.thisTranslation["message_noSupport"])
        else:
            self.selectTextFirst()

    def translateText(self):
        text = self.editor.textCursor().selectedText()
        if text:
            translator = Translator()
            if translator.language_translator is not None:
                fromLanguage = Translator.fromLanguageCodes[self.fromLanguageCombo.currentIndex() - 1] if self.fromLanguageCombo.currentIndex() != 0 else translator.identify(text)
                toLanguage = Translator.toLanguageCodes[self.toLanguageCombo.currentIndex()]
                result = translator.translate(text, fromLanguage, toLanguage)
                self.editor.insertPlainText(result)
            else:
                self.displayMessage(config.thisTranslation["ibmWatsonNotEnalbed"])
                webbrowser.open("https://github.com/eliranwong/UniqueBible/wiki/IBM-Watson-Language-Translator")
        else:
            self.selectTextFirst()

    def selectTextFirst(self):
        self.displayMessage(config.thisTranslation["selectTextFirst"])

    def displayMessage(self, message="", title="UniqueBible"):
        reply = QMessageBox.information(self, title, message)
Ejemplo n.º 16
0
class MasterControl(QWidget):
    def __init__(self,
                 parent,
                 initialTab=0,
                 b=config.mainB,
                 c=config.mainC,
                 v=config.mainV,
                 text=config.mainText):
        super().__init__()

        self.isRefreshing = True

        self.parent = parent
        # set title
        self.setWindowTitle(config.thisTranslation["controlPanel"])
        if config.restrictControlPanelWidth and config.screenWidth > config.masterControlWidth:
            self.setFixedWidth(config.masterControlWidth)
        # setup item option lists
        self.setupResourceLists()
        # setup interface
        self.text = text
        self.setupUI(b, c, v, text, initialTab)

        self.isRefreshing = False

    # manage key capture
    def event(self, event):
        if event.type() == QEvent.KeyRelease:
            if event.modifiers() == Qt.ControlModifier:
                if event.key() == Qt.Key_B:
                    self.tabs.setCurrentIndex(0)
                elif event.key() == Qt.Key_L:
                    self.tabs.setCurrentIndex(1)
                elif event.key() == Qt.Key_F:
                    self.tabs.setCurrentIndex(2)
                elif event.key() == Qt.Key_Y:
                    self.tabs.setCurrentIndex(3)
                elif event.key() == Qt.Key_M:
                    self.tabs.setCurrentIndex(4)
            elif event.key() == Qt.Key_Escape:
                self.hide()
        return QWidget.event(self, event)

    def closeEvent(self, event):
        # Control panel is designed for frequent use
        # Hiding it instead of closing may save time from reloading
        event.ignore()
        self.hide()

    def setupResourceLists(self):
        self.parent.setupResourceLists()
        # bible versions
        self.textList = self.parent.textList
        self.textFullNameList = self.parent.textFullNameList
        self.strongBibles = self.parent.strongBibles
        if self.parent.versionCombo is not None and config.menuLayout in (
                "classic", "focus", "aleph"):
            for index, fullName in enumerate(self.textFullNameList):
                self.parent.versionCombo.setItemData(index, fullName,
                                                     Qt.ToolTipRole)
        # commentaries
        self.commentaryList = self.parent.commentaryList
        #self.commentaryFullNameList = [Commentary(module).commentaryInfo() for module in self.commentaryList]
        self.commentaryFullNameList = self.parent.commentaryFullNameList
        # reference book
        # menu10_dialog
        self.referenceBookList = self.parent.referenceBookList
        # topic
        # menu5_topics
        self.topicListAbb = self.parent.topicListAbb
        self.topicList = self.parent.topicList
        # lexicon
        # context1_originalLexicon
        self.lexiconList = self.parent.lexiconList
        # dictionary
        # context1_dict
        self.dictionaryListAbb = self.parent.dictionaryListAbb
        self.dictionaryList = self.parent.dictionaryList
        # encyclopedia
        # context1_encyclopedia
        self.encyclopediaListAbb = self.parent.encyclopediaListAbb
        self.encyclopediaList = self.parent.encyclopediaList
        # 3rd-party dictionary
        # menu5_3rdDict
        self.thirdPartyDictionaryList = self.parent.thirdPartyDictionaryList

#    def setupItemLists(self):
#        # bible versions
#        self.textList = BiblesSqlite().getBibleList()
#        self.textFullNameList = [Bible(text).bibleInfo() for text in self.textList]
#        self.strongBibles =  [text for text in self.textList if Bible(text).bibleStrong()]
#        if self.parent.versionCombo is not None and config.menuLayout in ("classic", "focus", "aleph"):
#            for index, fullName in enumerate(self.textFullNameList):
#                self.parent.versionCombo.setItemData(index, fullName, Qt.ToolTipRole)
#        # commentaries
#        self.commentaryList = Commentary().getCommentaryList()
#        #self.commentaryFullNameList = [Commentary(module).commentaryInfo() for module in self.commentaryList]
#        self.commentaryFullNameList = []
#        for module in self.commentaryList:
#            info = Commentary(module).commentaryInfo()
#            if info == "https://Marvel.Bible Commentary" and module in Commentary.marvelCommentaries:
#                info = Commentary.marvelCommentaries[module]
#            self.commentaryFullNameList.append(info)
#        # reference book
#        # menu10_dialog
#        bookData = BookData()
#        self.referenceBookList = [book for book, *_ in bookData.getBookList()]
#        # open database
#        indexes = IndexesSqlite()
#        # topic
#        # menu5_topics
#        topicDictAbb2Name = {abb: name for abb, name in indexes.topicList}
#        self.topicListAbb = list(topicDictAbb2Name.keys())
#        topicDict = {name: abb for abb, name in indexes.topicList}
#        self.topicList = list(topicDict.keys())
#        # lexicon
#        # context1_originalLexicon
#        self.lexiconList = LexiconData().lexiconList
#        # dictionary
#        # context1_dict
#        dictionaryDictAbb2Name = {abb: name for abb, name in indexes.dictionaryList}
#        self.dictionaryListAbb = list(dictionaryDictAbb2Name.keys())
#        dictionaryDict = {name: abb for abb, name in indexes.dictionaryList}
#        self.dictionaryList = list(dictionaryDict.keys())
#        # encyclopedia
#        # context1_encyclopedia
#        encyclopediaDictAbb2Name = {abb: name for abb, name in indexes.encyclopediaList}
#        self.encyclopediaListAbb = list(encyclopediaDictAbb2Name.keys())
#        encyclopediaDict = {name: abb for abb, name in indexes.encyclopediaList}
#        self.encyclopediaList = list(encyclopediaDict.keys())
#        # 3rd-party dictionary
#        # menu5_3rdDict
#        self.thirdPartyDictionaryList = ThirdPartyDictionary(self.parent.textCommandParser.isThridPartyDictionary(config.thirdDictionary)).moduleList

    def setupUI(self, b, c, v, text, initialTab):
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.sharedWidget())
        mainLayout.addWidget(self.tabWidget(b, c, v, text, initialTab))
        self.setLayout(mainLayout)

    def sharedWidget(self):
        sharedWidget = QWidget()
        sharedWidgetLayout = QVBoxLayout()
        subLayout = QHBoxLayout()
        subLayout.addWidget(self.commandFieldWidget())
        subLayout.addWidget(self.autoCloseCheckBox())
        sharedWidgetLayout.addLayout(subLayout)
        sharedWidget.setLayout(sharedWidgetLayout)
        return sharedWidget

    def updateBibleTabText(self, reference):
        self.tabs.setTabText(0, reference)

    def tabWidget(self, b, c, v, text, initialTab):
        self.tabs = QTabWidget()
        # 0
        self.bibleTab = BibleExplorer(self, (b, c, v, text))
        self.tabs.addTab(self.bibleTab, config.thisTranslation["cp0"])
        self.tabs.setTabToolTip(0, config.thisTranslation["cp0Tip"])
        # 1
        libraryTab = LibraryLauncher(self)
        self.tabs.addTab(libraryTab, config.thisTranslation["cp1"])
        self.tabs.setTabToolTip(1, config.thisTranslation["cp1Tip"])
        # 2
        self.toolTab = SearchLauncher(self)
        self.tabs.addTab(self.toolTab, config.thisTranslation["cp2"])
        self.tabs.setTabToolTip(2, config.thisTranslation["cp2Tip"])
        # 3
        self.historyTab = HistoryLauncher(self)
        self.tabs.addTab(self.historyTab, config.thisTranslation["cp3"])
        self.tabs.setTabToolTip(3, config.thisTranslation["cp3Tip"])
        # 4
        self.miscellaneousTab = MiscellaneousLauncher(self)
        self.tabs.addTab(self.miscellaneousTab, config.thisTranslation["cp4"])
        self.tabs.setTabToolTip(4, config.thisTranslation["cp4Tip"])
        # set action with changing tabs
        self.tabs.currentChanged.connect(self.tabChanged)
        # set initial tab
        self.tabs.setCurrentIndex(initialTab)
        return self.tabs

    def commandFieldWidget(self):
        self.commandField = QLineEdit()
        self.commandField.setClearButtonEnabled(True)
        self.commandField.setToolTip(
            config.thisTranslation["enter_command_here"])
        self.commandField.returnPressed.connect(self.commandEntered)
        return self.commandField

    def autoCloseCheckBox(self):
        checkbox = QCheckBox()
        checkbox.setText(config.thisTranslation["autoClose"])
        checkbox.setToolTip(config.thisTranslation["autoCloseToolTip"])
        checkbox.setChecked(config.closeControlPanelAfterRunningCommand)
        checkbox.stateChanged.connect(
            self.closeControlPanelAfterRunningCommandChanged)
        return checkbox

    # Common layout

    def buttonsWidget(self,
                      buttonElementTupleTuple,
                      r2l=False,
                      translation=True):
        buttons = QWidget()
        buttonsLayouts = QVBoxLayout()
        buttonsLayouts.setSpacing(3)
        for buttonElementTuple in buttonElementTupleTuple:
            buttonsLayouts.addLayout(
                self.buttonsLayout(buttonElementTuple, r2l, translation))
        buttons.setLayout(buttonsLayouts)
        return buttons

    def buttonsLayout(self, buttonElementTuple, r2l=False, translation=True):
        buttonsLayout = QBoxLayout(
            QBoxLayout.RightToLeft if r2l else QBoxLayout.LeftToRight)
        buttonsLayout.setSpacing(5)
        for label, action in buttonElementTuple:
            buttonLabel = config.thisTranslation[
                label] if translation else label
            button = QPushButton(buttonLabel)
            button.clicked.connect(action)
            buttonsLayout.addWidget(button)
        return buttonsLayout

    def comboFeatureLayout(self, feature, combo, action):
        # QGridLayout: https://stackoverflow.com/questions/61451279/how-does-setcolumnstretch-and-setrowstretch-works
        layout = QGridLayout()
        layout.setSpacing(5)
        # combo
        layout.addWidget(combo, 0, 0, 1, 3)
        # button
        button = QPushButton(config.thisTranslation[feature])
        button.clicked.connect(action)
        layout.addWidget(button, 0, 3, 1, 1)
        return layout

    # Actions

    def closeControlPanelAfterRunningCommandChanged(self):
        config.closeControlPanelAfterRunningCommand = not config.closeControlPanelAfterRunningCommand

    def updateBCVText(self, b, c, v, text):
        self.bibleTab.updateBCVText(b, c, v, text)

    def commandEntered(self):
        command = self.commandField.text()
        self.runTextCommand(command, False)

    def runTextCommand(self,
                       command,
                       printCommand=True,
                       reloadMainWindow=False):
        if printCommand:
            self.commandField.setText(command)
        self.parent.textCommandLineEdit.setText(command)
        self.parent.runTextCommand(command)
        if reloadMainWindow:
            self.parent.reloadCurrentRecord()
        if config.closeControlPanelAfterRunningCommand and not self.isRefreshing:
            self.hide()

    def tabChanged(self, index):
        self.isRefreshing = True

        # refresh content
        if index == 3:
            self.historyTab.refresh()
        elif index == 4:
            self.miscellaneousTab.refresh()

        # set focus
        if index == 2:
            self.toolTab.searchField.setFocus()
            if config.contextItem:
                self.toolTab.searchField.setText(config.contextItem)
                config.contextItem = ""
            elif self.parent.mainView.currentWidget().selectedText():
                self.toolTab.searchField.setText(
                    self.parent.mainView.currentWidget().selectedText())
            elif self.parent.studyView.currentWidget().selectedText():
                self.toolTab.searchField.setText(
                    self.parent.studyView.currentWidget().selectedText())
        else:
            self.commandField.setFocus()

        self.isRefreshing = False

    def displayMessage(self, message="", title="UniqueBible"):
        reply = QMessageBox.information(self, title, message)
Ejemplo n.º 17
0
class SampleLogsView(QSplitter):
    """Sample Logs View

    This contains a table of the logs, a plot of the currently
    selected logs, and the statistics of the selected log.
    """
    def __init__(self,
                 presenter,
                 parent=None,
                 window_flags=Qt.Window,
                 name='',
                 isMD=False,
                 noExp=0):
        super(SampleLogsView, self).__init__(parent)

        self.presenter = presenter

        self.setWindowTitle("{} sample logs".format(name))
        self.setWindowFlags(window_flags)
        self.setAttribute(Qt.WA_DeleteOnClose, True)

        # left hand side
        self.frame_left = QFrame()
        layout_left = QVBoxLayout()

        # add a spin box for MD workspaces
        if isMD:
            layout_mult_expt_info = QHBoxLayout()
            layout_mult_expt_info.addWidget(QLabel("Experiment Info #"))
            self.experimentInfo = QSpinBox()
            self.experimentInfo.setMaximum(noExp - 1)
            self.experimentInfo.valueChanged.connect(
                self.presenter.changeExpInfo)
            layout_mult_expt_info.addWidget(self.experimentInfo)
            layout_mult_expt_info.addSpacerItem(
                QSpacerItem(10, 10, QSizePolicy.Expanding))
            layout_left.addLayout(layout_mult_expt_info)

        # create a line edit to allow for filtering keys
        self.line_edit = QLineEdit()
        self.line_edit.setClearButtonEnabled(True)
        self.line_edit.setToolTip("Type here to filter the logs")
        self.line_edit.setPlaceholderText("Search the logs")
        self.line_edit.textEdited.connect(self.presenter.search_key_changed)
        layout_left.addWidget(self.line_edit)
        # Create sample log table
        self.table = QTableView()
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.doubleClicked.connect(self.presenter.doubleClicked)
        self.table.contextMenuEvent = self.tableMenu
        layout_left.addWidget(self.table)
        self.frame_left.setLayout(layout_left)
        self.addWidget(self.frame_left)

        #right hand side
        self.frame_right = QFrame()
        layout_right = QVBoxLayout()

        #Add full_time and experimentinfo options
        layout_options = QHBoxLayout()

        if isMD:
            layout_options.addWidget(QLabel("Experiment Info #"))
            self.experimentInfo = QSpinBox()
            self.experimentInfo.setMaximum(noExp - 1)
            self.experimentInfo.valueChanged.connect(
                self.presenter.changeExpInfo)
            layout_options.addWidget(self.experimentInfo)

        #check boxes
        self.full_time = QCheckBox("Relative Time")
        self.full_time.setToolTip(
            "Shows relative time in seconds from the start of the run.")
        self.full_time.setChecked(True)
        self.full_time.stateChanged.connect(self.presenter.plot_logs)
        layout_options.addWidget(self.full_time)
        self.show_filtered = QCheckBox("Filtered Data")
        self.show_filtered.setToolTip(
            "Filtered data only shows data while running and in this period.\nInvalid values are also filtered."
        )
        self.show_filtered.setChecked(True)
        self.show_filtered.stateChanged.connect(
            self.presenter.filtered_changed)
        layout_options.addWidget(self.show_filtered)
        self.spaceItem = QSpacerItem(10, 10, QSizePolicy.Expanding)
        layout_options.addSpacerItem(self.spaceItem)
        layout_right.addLayout(layout_options)

        # Sample log plot
        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.canvas.mpl_connect('button_press_event',
                                self.presenter.plot_clicked)
        self.ax = self.fig.add_subplot(111, projection='mantid')
        layout_right.addWidget(self.canvas)

        # Sample stats
        self.create_stats_widgets()
        layout_stats = QFormLayout()
        layout_stats.addRow('', QLabel("Log Statistics"))
        layout_stats.addRow('Min:', self.stats_widgets["minimum"])
        layout_stats.addRow('Max:', self.stats_widgets["maximum"])
        layout_stats.addRow('Time Avg:', self.stats_widgets["time_mean"])
        layout_stats.addRow('Time Std Dev:',
                            self.stats_widgets["time_standard_deviation"])
        layout_stats.addRow('Mean (unweighted):', self.stats_widgets["mean"])
        layout_stats.addRow('Median (unweighted):',
                            self.stats_widgets["median"])
        layout_stats.addRow('Std Dev:',
                            self.stats_widgets["standard_deviation"])
        layout_stats.addRow('Duration:', self.stats_widgets["duration"])
        layout_right.addLayout(layout_stats)
        self.frame_right.setLayout(layout_right)

        self.addWidget(self.frame_right)
        self.setStretchFactor(0, 1)

        self.resize(1200, 800)
        self.show()

    def closeEvent(self, event):
        self.deleteLater()
        super(SampleLogsView, self).closeEvent(event)

    def tableMenu(self, event):
        """Right click menu for table, can plot or print selected logs"""
        menu = QMenu(self)
        plotAction = menu.addAction("Plot selected")
        plotAction.triggered.connect(self.presenter.new_plot_logs)
        plotAction = menu.addAction("Print selected")
        plotAction.triggered.connect(self.presenter.print_selected_logs)
        menu.exec_(event.globalPos())

    def set_model(self, model):
        """Set the model onto the table"""
        self.model = model
        self.table.setModel(self.model)
        self.table.resizeColumnsToContents()
        self.table.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.table.selectionModel().selectionChanged.connect(
            self.presenter.update)

    def show_plot_and_stats(self, show_plot_and_stats):
        """sets wether the plot and stats section should be visible"""
        if self.frame_right.isVisible() != show_plot_and_stats:
            # the desired state is nor the current state
            self.setUpdatesEnabled(False)
            current_width = self.frame_right.width()
            if current_width:
                self.last_width = current_width
            else:
                current_width = self.last_width

            if show_plot_and_stats:
                self.resize(self.width() + current_width, self.height())
            else:
                self.resize(self.width() - current_width, self.height())
            self.frame_right.setVisible(show_plot_and_stats)
            self.setUpdatesEnabled(True)

    def plot_selected_logs(self, ws, exp, rows):
        """Update the plot with the selected rows"""
        if self.frame_right.isVisible():
            self.ax.clear()
            self.create_ax_by_rows(self.ax, ws, exp, rows)
            try:
                self.fig.canvas.draw()
            except ValueError as ve:
                #this can throw an error if the plot has recently been hidden, but the error does not matter
                if not str(ve).startswith("Image size of"):
                    raise

    def new_plot_selected_logs(self, ws, exp, rows):
        """Create a new plot, in a separate window for selected rows"""
        fig, ax = plt.subplots(subplot_kw={'projection': 'mantid'})
        self.create_ax_by_rows(ax, ws, exp, rows)
        fig.show()

    def create_ax_by_rows(self, ax, ws, exp, rows):
        """Creates the plots for given rows onto axis ax"""
        for row in rows:
            log_text = self.get_row_log_name(row)
            ax.plot(ws,
                    LogName=log_text,
                    label=log_text,
                    FullTime=not self.full_time.isChecked(),
                    Filtered=self.show_filtered.isChecked(),
                    ExperimentInfo=exp)

        ax.set_ylabel('')
        if ax.get_legend_handles_labels()[0]:
            ax.legend()

    def set_log_controls(self, are_logs_filtered):
        """Sets log specific settings based on the log clicked on"""
        self.show_filtered.setEnabled(are_logs_filtered)

    def get_row_log_name(self, i):
        """Returns the log name of particular row"""
        return str(self.model.item(i, 0).text())

    def get_exp(self):
        """Get set experiment info number"""
        return self.experimentInfo.value()

    def get_selected_row_indexes(self):
        """Return a list of selected row from table"""
        return [
            row.row() for row in self.table.selectionModel().selectedRows()
        ]

    def set_selected_rows(self, rows):
        """Set seleceted rows in table"""
        mode = QItemSelectionModel.Select | QItemSelectionModel.Rows
        for row in rows:
            self.table.selectionModel().select(self.model.index(row, 0), mode)

    def create_stats_widgets(self):
        """Creates the statistics widgets"""
        self.stats_widgets = {
            "minimum": QLineEdit(),
            "maximum": QLineEdit(),
            "mean": QLineEdit(),
            "median": QLineEdit(),
            "standard_deviation": QLineEdit(),
            "time_mean": QLineEdit(),
            "time_standard_deviation": QLineEdit(),
            "duration": QLineEdit()
        }
        for widget in self.stats_widgets.values():
            widget.setReadOnly(True)

    def set_statistics(self, stats):
        """Updates the statistics widgets from stats dictionary"""
        for param in self.stats_widgets.keys():
            self.stats_widgets[param].setText('{:.6}'.format(
                getattr(stats, param)))

    def clear_statistics(self):
        """Clears the values in statistics widgets"""
        for widget in self.stats_widgets.values():
            widget.clear()