Пример #1
0
 def commentaryListView(self):
     # https://doc.qt.io/archives/qtforpython-5.12/PySide2/QtCore/QStringListModel.html
     # https://gist.github.com/minoue/9f384cd36339429eb0bf
     # https://www.pythoncentral.io/pyside-pyqt-tutorial-qlistview-and-qstandarditemmodel/
     list = QListView()
     list.setEditTriggers(QAbstractItemView.NoEditTriggers)
     model = QStandardItemModel(list)
     for index, commentary in enumerate(self.parent.commentaryFullNameList):
         item = QStandardItem(commentary)
         item.setToolTip(self.parent.commentaryList[index])
         #item.setCheckable(True)
         #item.setCheckState(Qt.CheckState.Checked)
         #item.setCheckState(Qt.CheckState.Unchecked)
         #print(item.checkState() is Qt.CheckState.Checked)
         model.appendRow(item)
     #model = QStringListModel(self.parent.commentaryList)
     #model = QStringListModel(self.parent.commentaryFullNameList)
     list.setModel(model)
     if config.commentaryText in self.parent.commentaryList:
         list.setCurrentIndex(
             model.index(
                 self.parent.commentaryList.index(config.commentaryText),
                 0))
     list.selectionModel().selectionChanged.connect(self.commentarySelected)
     return list
Пример #2
0
    def setupUI(self):
        layout = QVBoxLayout()
        # Add a label
        layout.addWidget(QLabel(config.thisTranslation["downloadOptions"]))
        # Add a list view
        list = QListView()
        list.setEditTriggers(QAbstractItemView.NoEditTriggers)
        model = QStringListModel(self.options)
        list.setModel(model)
        list.selectionModel().selectionChanged.connect(self.optionSelected)
        list.setCurrentIndex(model.index(len(self.options) - 1, 0))
        layout.addWidget(list)

        subLayout = QHBoxLayout()

        # Add a cancel button
        button = QPushButton(config.thisTranslation["message_cancel"])
        button.clicked.connect(self.close)
        subLayout.addWidget(button)
        # Add a download button
        button = QPushButton(config.thisTranslation["download"])
        button.clicked.connect(
            lambda: self.parent.downloadSelectedOption(self.selectedOption))
        subLayout.addWidget(button)

        layout.addLayout(subLayout)

        # Set layout
        self.setLayout(layout)
Пример #3
0
 def devotionsListView(self):
     list = QListView()
     list.setEditTriggers(QAbstractItemView.NoEditTriggers)
     model = QStandardItemModel(list)
     for devotional in self.devotionals:
         item = QStandardItem(devotional)
         model.appendRow(item)
     list.setModel(model)
     list.selectionModel().selectionChanged.connect(self.devotionalSelected)
     return list
Пример #4
0
 def videoListView(self):
     list = QListView()
     list.setEditTriggers(QAbstractItemView.NoEditTriggers)
     model = QStandardItemModel(list)
     for file in self.videoList:
         item = QStandardItem(file)
         model.appendRow(item)
     list.setModel(model)
     list.selectionModel().selectionChanged.connect(self.playSelectedVideo)
     return list
Пример #5
0
 def pdfListView(self):
     list = QListView()
     list.setEditTriggers(QAbstractItemView.NoEditTriggers)
     model = QStandardItemModel(list)
     for pdf in self.pdfList:
         item = QStandardItem(pdf)
         model.appendRow(item)
     list.setModel(model)
     if config.pdfText in self.parent.pdfList:
         list.setCurrentIndex(
             model.index(self.parent.pdfList.index(config.pdfText), 0))
     list.selectionModel().selectionChanged.connect(self.pdfSelected)
     return list
Пример #6
0
class Switcher(QDialog):
    """
    A multi purpose switcher.

    Example
    -------
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherSeparator: [---------------------------------------]
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherItem:      [title description    <shortcut> section]
    """

    # Dismissed switcher
    sig_rejected = Signal()
    # Search/Filter text changes
    sig_text_changed = Signal(TEXT_TYPES[-1])
    # Current item changed
    sig_item_changed = Signal(object)
    # List item selected, mode and cleaned search text
    sig_item_selected = Signal(object, TEXT_TYPES[-1], TEXT_TYPES[-1], )
    sig_mode_selected = Signal(TEXT_TYPES[-1])

    _MAX_NUM_ITEMS = 15
    _MIN_WIDTH = 580
    _MIN_HEIGHT = 200
    _MAX_HEIGHT = 390
    _ITEM_WIDTH = _MIN_WIDTH - 20

    def __init__(self, parent, help_text=None, item_styles=ITEM_STYLES,
                 item_separator_styles=ITEM_SEPARATOR_STYLES):
        """Multi purpose switcher."""
        super(Switcher, self).__init__(parent)
        self._modes = {}
        self._mode_on = ''
        self._item_styles = item_styles
        self._item_separator_styles = item_separator_styles

        # Widgets
        self.edit = QLineEdit(self)
        self.list = QListView(self)
        self.model = QStandardItemModel(self.list)
        self.proxy = SwitcherProxyModel(self.list)
        self.filter = KeyPressFilter()

        # Widgets setup
        self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint)
        self.setWindowOpacity(0.95)
#        self.setMinimumHeight(self._MIN_HEIGHT)
        self.setMaximumHeight(self._MAX_HEIGHT)
        self.edit.installEventFilter(self.filter)
        self.edit.setPlaceholderText(help_text if help_text else '')
        self.list.setMinimumWidth(self._MIN_WIDTH)
        self.list.setItemDelegate(SwitcherDelegate(self))
        self.list.setFocusPolicy(Qt.NoFocus)
        self.list.setSelectionBehavior(self.list.SelectItems)
        self.list.setSelectionMode(self.list.SingleSelection)
        self.list.setVerticalScrollMode(QAbstractItemView.ScrollPerItem)
        self.proxy.setSourceModel(self.model)
        self.list.setModel(self.proxy)

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.edit)
        layout.addWidget(self.list)
        self.setLayout(layout)

        # Signals
        self.filter.sig_up_key_pressed.connect(self.previous_row)
        self.filter.sig_down_key_pressed.connect(self.next_row)
        self.filter.sig_enter_key_pressed.connect(self.enter)
        self.edit.textChanged.connect(self.setup)
        self.edit.textChanged.connect(self.sig_text_changed)
        self.edit.returnPressed.connect(self.enter)
        self.list.clicked.connect(self.enter)
        self.list.clicked.connect(self.edit.setFocus)
        self.list.selectionModel().currentChanged.connect(
            self.current_item_changed)
        self.edit.setFocus()

    # --- Helper methods
    def _add_item(self, item, last_item=True):
        """Perform common actions when adding items."""
        item.set_width(self._ITEM_WIDTH)
        self.model.appendRow(item)
        if last_item:
            # Only set the current row to the first item when the added item is
            # the last one in order to prevent performance issues when
            # adding multiple items
            self.set_current_row(0)
            self.set_height()
        self.setup_sections()

    # --- API
    def clear(self):
        """Remove all items from the list and clear the search text."""
        self.set_placeholder_text('')
        self.model.beginResetModel()
        self.model.clear()
        self.model.endResetModel()
        self.setMinimumHeight(self._MIN_HEIGHT)

    def set_placeholder_text(self, text):
        """Set the text appearing on the empty line edit."""
        self.edit.setPlaceholderText(text)

    def add_mode(self, token, description):
        """Add mode by token key and description."""
        if len(token) == 1:
            self._modes[token] = description
        else:
            raise Exception('Token must be of length 1!')

    def get_mode(self):
        """Get the current mode the switcher is in."""
        return self._mode_on

    def remove_mode(self, token):
        """Remove mode by token key."""
        if token in self._modes:
            self._modes.pop(token)

    def clear_modes(self):
        """Delete all modes spreviously defined."""
        del self._modes
        self._modes = {}

    def add_item(self, icon=None, title=None, description=None, shortcut=None,
                 section=None, data=None, tool_tip=None, action_item=False,
                 last_item=True):
        """Add switcher list item."""
        item = SwitcherItem(
            parent=self.list,
            icon=icon,
            title=title,
            description=description,
            data=data,
            shortcut=shortcut,
            section=section,
            action_item=action_item,
            tool_tip=tool_tip,
            styles=self._item_styles
        )
        self._add_item(item, last_item=last_item)

    def add_separator(self):
        """Add separator item."""
        item = SwitcherSeparatorItem(parent=self.list,
                                     styles=self._item_separator_styles)
        self._add_item(item)

    def setup(self):
        """Set-up list widget content based on the filtering."""
        # Check exited mode
        mode = self._mode_on
        if mode:
            search_text = self.search_text()[len(mode):]
        else:
            search_text = self.search_text()

        # Check exited mode
        if self.search_text() == '':
            self._mode_on = ''
            self.clear()
            self.proxy.set_filter_by_score(False)
            self.sig_mode_selected.emit(self._mode_on)
            return

        # Check entered mode
        for key in self._modes:
            if self.search_text().startswith(key) and not mode:
                self._mode_on = key
                self.sig_mode_selected.emit(key)
                return

        # Filter by text
        titles = []
        for row in range(self.model.rowCount()):
            item = self.model.item(row)
            if isinstance(item, SwitcherItem):
                title = item.get_title()
            else:
                title = ''
            titles.append(title)

        search_text = clean_string(search_text)
        scores = get_search_scores(to_text_string(search_text),
                                   titles, template=u"<b>{0}</b>")

        for idx, (title, rich_title, score_value) in enumerate(scores):
            item = self.model.item(idx)
            if not self._is_separator(item) and not item.is_action_item():
                rich_title = rich_title.replace(" ", "&nbsp;")
                item.set_rich_title(rich_title)
            item.set_score(score_value)
        self.proxy.set_filter_by_score(True)

        self.setup_sections()
        if self.count():
            self.set_current_row(0)
        else:
            self.set_current_row(-1)
        self.set_height()

    def setup_sections(self):
        """Set-up which sections appear on the item list."""
        mode = self._mode_on
        if mode:
            search_text = self.search_text()[len(mode):]
        else:
            search_text = self.search_text()

        if search_text:
            for row in range(self.model.rowCount()):
                item = self.model.item(row)
                if isinstance(item, SwitcherItem):
                    item.set_section_visible(False)
        else:
            sections = []
            for row in range(self.model.rowCount()):
                item = self.model.item(row)
                if isinstance(item, SwitcherItem):
                    sections.append(item.get_section())
                    item.set_section_visible(bool(search_text))
                else:
                    sections.append('')

                if row != 0:
                    visible = sections[row] != sections[row - 1]
                    if not self._is_separator(item):
                        item.set_section_visible(visible)
                else:
                    item.set_section_visible(True)

        self.proxy.sortBy('_score')
        self.sig_item_changed.emit(self.current_item())

    def set_height(self):
        """Set height taking into account the number of items."""
        if self.count() >= self._MAX_NUM_ITEMS:
            switcher_height = self._MAX_HEIGHT
        elif self.count() != 0 and self.current_item():
            current_item = self.current_item()
            item_height = current_item.get_height()
            list_height = item_height * (self.count() + 3)
            edit_height = self.edit.height()
            spacing_height = self.layout().spacing() * 4
            switcher_height = list_height + edit_height + spacing_height
            switcher_height = max(switcher_height, self._MIN_HEIGHT)
        else:
            switcher_height = self._MIN_HEIGHT
        self.setFixedHeight(int(switcher_height))

    def set_position(self, top):
        """Set the position of the dialog."""
        parent = self.parent()
        if parent is not None:
            geo = parent.geometry()
            width = self.list.width()  # This has been set in setup
            left = parent.geometry().width()/2 - width/2

            while parent:
                geo = parent.geometry()
                top += geo.top()
                left += geo.left()
                parent = parent.parent()

            self.move(round(left), top)

    @Slot(QModelIndex, QModelIndex)
    def current_item_changed(self, current, previous):
        """Handle item selection."""
        self.sig_item_changed.emit(self.current_item())

    # --- Qt overrides
    # ------------------------------------------------------------------------
    @Slot()
    @Slot(QListWidgetItem)
    def enter(self, itemClicked=None):
        """Override Qt method."""
        row = self.current_row()
        model_index = self.proxy.mapToSource(self.proxy.index(row, 0))
        item = self.model.item(model_index.row())
        if item:
            mode = self._mode_on
            self.sig_item_selected.emit(item, mode,
                                        self.search_text()[len(mode):])

    def accept(self):
        """Override Qt method."""
        super(Switcher, self).accept()

    def reject(self):
        """Override Qt method."""
        self.set_search_text('')
        self.sig_rejected.emit()
        super(Switcher, self).reject()

    def resizeEvent(self, event):
        """Override Qt method."""
        super(Switcher, self).resizeEvent(event)

    # --- Helper methods: Lineedit widget
    def search_text(self):
        """Get the normalized (lowecase) content of the search text."""
        return to_text_string(self.edit.text()).lower()

    def set_search_text(self, string):
        """Set the content of the search text."""
        self.edit.setText(string)

    # --- Helper methods: List widget
    def _is_separator(self, item):
        """Check if item is an separator item (SwitcherSeparatorItem)."""
        return isinstance(item, SwitcherSeparatorItem)

    def _select_row(self, steps):
        """Select row in list widget based on a number of steps with direction.

        Steps can be positive (next rows) or negative (previous rows).
        """
        row = self.current_row() + steps
        if 0 <= row < self.count():
            self.set_current_row(row)

    def count(self):
        """Get the item count in the list widget."""
        return self.proxy.rowCount()

    def current_row(self):
        """Return the current selected row in the list widget."""
        return self.list.currentIndex().row()

    def current_item(self):
        """Return the current selected item in the list widget."""
        row = self.current_row()
        model_index = self.proxy.mapToSource(self.proxy.index(row, 0))
        item = self.model.item(model_index.row())
        return item

    def set_current_row(self, row):
        """Set the current selected row in the list widget."""
        proxy_index = self.proxy.index(row, 0)
        selection_model = self.list.selectionModel()

        # https://doc.qt.io/qt-5/qitemselectionmodel.html#SelectionFlag-enum
        selection_model.setCurrentIndex(
            proxy_index, selection_model.ClearAndSelect)

        # Ensure that the selected item is visible
        self.list.scrollTo(proxy_index, QAbstractItemView.EnsureVisible)

    def previous_row(self):
        """Select previous row in list widget."""
        steps = 1
        prev_row = self.current_row() - steps

        if prev_row == -1:
            self.set_current_row(self.count() - 1)
        else:
            if prev_row >= 0:
                # Need to map the filtered list to the actual model items
                list_index = self.proxy.index(prev_row, 0)
                model_index = self.proxy.mapToSource(list_index)
                item = self.model.item(model_index.row(), 0)
                if self._is_separator(item):
                    steps += 1
            self._select_row(-steps)

    def next_row(self):
        """Select next row in list widget."""
        steps = 1
        next_row = self.current_row() + steps

        # Need to map the filtered list to the actual model items
        list_index = self.proxy.index(next_row, 0)
        model_index = self.proxy.mapToSource(list_index)
        item = self.model.item(model_index.row(), 0)

        if next_row >= self.count():
            self.set_current_row(0)
        else:
            if item:
                if self._is_separator(item):
                    steps += 1
            self._select_row(steps)
Пример #7
0
class DataTypeKeysWidget(QWidget):
    dataTypeKeySelected = Signal()

    def __init__(self, model):
        QWidget.__init__(self)

        self.__filter_popup = FilterPopup(self)
        self.__filter_popup.filterSettingsChanged.connect(self.onItemChanged)

        layout = QVBoxLayout()

        self.model = model
        self.filter_model = DataTypeProxyModel(self.model)

        filter_layout = QHBoxLayout()

        self.search_box = SearchBox()
        self.search_box.filterChanged.connect(self.setSearchString)
        filter_layout.addWidget(self.search_box)

        filter_popup_button = QToolButton()
        filter_popup_button.setIcon(resourceIcon("ide/cog_edit.png"))
        filter_popup_button.clicked.connect(self.showFilterPopup)
        filter_layout.addWidget(filter_popup_button)
        layout.addLayout(filter_layout)

        self.data_type_keys_widget = QListView()
        self.data_type_keys_widget.setModel(self.filter_model)
        self.data_type_keys_widget.selectionModel().selectionChanged.connect(
            self.itemSelected)

        layout.addSpacing(15)
        layout.addWidget(self.data_type_keys_widget, 2)
        layout.addStretch()

        # layout.addWidget(Legend("Default types", DataTypeKeysListModel.DEFAULT_DATA_TYPE))
        layout.addWidget(
            Legend("Observations available",
                   DataTypeKeysListModel.HAS_OBSERVATIONS))

        self.setLayout(layout)

    def onItemChanged(self, item):
        # self.filter_model.setShowBlockKeys(item["block"])
        self.filter_model.setShowSummaryKeys(item["summary"])
        self.filter_model.setShowGenKWKeys(item["gen_kw"])
        self.filter_model.setShowGenDataKeys(item["gen_data"])
        self.filter_model.setShowCustomKwKeys(item["custom_kw"])
        # self.filter_model.setShowCustomPcaKeys(item["custom_pca"])

    def itemSelected(self):
        selected_item = self.getSelectedItem()
        if selected_item is not None:
            self.dataTypeKeySelected.emit()

    def getSelectedItem(self):
        """ @rtype: str """
        index = self.data_type_keys_widget.currentIndex()
        source_index = self.filter_model.mapToSource(index)
        item = self.model.itemAt(source_index)
        return item

    def selectDefault(self):
        self.data_type_keys_widget.setCurrentIndex(
            self.filter_model.index(0, 0))

    def setSearchString(self, filter):
        self.filter_model.setFilterFixedString(filter)

    def showFilterPopup(self):
        self.__filter_popup.show()
Пример #8
0
class ConfigDialog(QDialog):
    def __init__(self):
        super(ConfigDialog, self).__init__()

        # Set size and position
        self.setGeometry(0, 0, 900, 550)
        frameGm = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

        self.contentsWidget = QListView()
        self.contentsWidget.setViewMode(QListView.IconMode)
        # self.contentsWidget.setIconSize(QSize(96, 84))
        self.contentsWidget.setMovement(QListView.Static)
        self.contentsWidget.setMaximumWidth(174)
        self.contentsWidget.setSpacing(12)
        self.contentsWidget.setSelectionMode(QAbstractItemView.SingleSelection)

        self.contentsModel = QStandardItemModel()
        self.contentsWidget.setModel(self.contentsModel)
        self.contentsWidget.selectionModel().currentChanged.connect(self.changePage)

        self.buttonboxWidget = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Apply# | QDialogButtonBox.Help
        )
        self.buttonboxWidget.button(QDialogButtonBox.Ok).clicked.connect(self.ok)
        self.buttonboxWidget.button(QDialogButtonBox.Apply).clicked.connect(self.apply)
        self.buttonboxWidget.button(QDialogButtonBox.Cancel).clicked.connect(self.close)

        self.pagesWidget = QStackedWidget()

        horizontalLayout = QHBoxLayout()
        horizontalLayout.addWidget(self.contentsWidget)
        horizontalLayout.addWidget(self.pagesWidget, 1)

        mainLayout = QVBoxLayout()
        mainLayout.addLayout(horizontalLayout)
        # mainLayout.addStretch(1)
        mainLayout.addSpacing(12)
        mainLayout.addWidget(self.buttonboxWidget)

        self.setLayout(mainLayout)
        self.setWindowTitle("Config Dialog")

        # Set modality
        self.setModal(True)

        self.lastwidget = None

        self.createIcons()
        self.restore()

        pluginmanager.attach(self.pluginsChanged)

    def createIcons(self):
        self.contentsModel.clear()
        for pluginInfo in pluginmanager.getPluginsOfCategory("SettingsPlugin"):
            item = QStandardItem(pluginInfo.plugin_object.icon, pluginInfo.plugin_object.name())
            item.widget = pluginInfo.plugin_object.widget
            item.setTextAlignment(Qt.AlignHCenter)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            item.setSizeHint(QSize(136, 80))
            self.contentsModel.appendRow(item)

    def show(self):
        if self.lastwidget:
            self.pagesWidget.addWidget(self.lastwidget)
            self.pagesWidget.setCurrentWidget(self.lastwidget)
        self.restore()
        super(ConfigDialog, self).show()

    def changePage(self, current, previous):
        if not current:
            current = previous
        current = self.contentsModel.itemFromIndex(current)
        self.pagesWidget.addWidget(current.widget)
        self.pagesWidget.setCurrentWidget(current.widget)
        self.lastwidget = current.widget

    def pluginsChanged(self):
        self.createIcons()

    def restore(self):
        for pluginInfo in pluginmanager.getPluginsOfCategory("SettingsPlugin"):
            pluginInfo.plugin_object.restore()

        self.apply()

    def ok(self):
        self._empty()
        self.apply()
        self.accept()

    def apply(self):
        for pluginInfo in pluginmanager.getPluginsOfCategory("SettingsPlugin"):
            pluginInfo.plugin_object.save()

    def close(self):
        self._empty()
        self.restore()
        self.reject()

    def _empty(self):
        """
        Disown all widget children (otherwise their c++ objects are force deleted when the dialog closes).
        Must be run in reverse to avoid index update errors
        """
        for i in reversed(range(self.pagesWidget.count())):
            self.pagesWidget.widget(i).setParent(None)

    def closeEvent(self, event):
        self.close()
        event.accept()

    def keyPressEvent(self, e: QKeyEvent):
        if e.key() != Qt.Key_Escape:
            super(ConfigDialog, self).keyPressEvent(e)
        else:
            self.close()
Пример #9
0
class HistoryLauncher(QWidget):
    def __init__(self, parent):
        super().__init__()
        # set title
        self.setWindowTitle(config.thisTranslation["menu_history"])
        # set up variables
        self.parent = parent
        self.startup = True
        # setup interface
        self.setupUI()

    def setupUI(self):
        mainLayout = QHBoxLayout()

        leftColumnWidget = QGroupBox(config.thisTranslation["mainWindow"])
        layout = QVBoxLayout()
        layout.addWidget(self.createMainListView())
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(lambda: self.openLastRecord("main"))
        layout.addWidget(button)
        leftColumnWidget.setLayout(layout)

        middleColumnWidget = QGroupBox(config.thisTranslation["studyWindow"])
        layout = QVBoxLayout()
        layout.addWidget(self.createStudyListView())
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(lambda: self.openLastRecord("study"))
        layout.addWidget(button)
        middleColumnWidget.setLayout(layout)

        rightColumnWidget = QGroupBox(
            config.thisTranslation["menu_external_notes"])
        layout = QVBoxLayout()
        layout.addWidget(self.createExternalListView())
        subLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(lambda: self.externalFileAction(False))
        subLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["edit"])
        button.clicked.connect(lambda: self.externalFileAction(True))
        subLayout.addWidget(button)
        layout.addLayout(subLayout)
        rightColumnWidget.setLayout(layout)

        mainLayout.addWidget(leftColumnWidget)
        mainLayout.addWidget(middleColumnWidget)
        mainLayout.addWidget(rightColumnWidget)
        self.setLayout(mainLayout)

    def createMainListView(self):
        # Main and study history records are editable, so users can slightly modify a command and execute a new one.
        self.mainListView = QListView()
        self.mainModel = QStringListModel()
        self.mainListView.setModel(self.mainModel)
        self.mainListView.selectionModel().selectionChanged.connect(
            lambda selection: self.historyAction(selection, "main"))
        return self.mainListView

    def createStudyListView(self):
        #studyItems = list(reversed(config.history["study"]))
        # Main and study history records are editable, so users can slightly modify a command and execute a new one.
        self.studyListView = QListView()
        self.studyModel = QStringListModel()
        self.studyListView.setModel(self.studyModel)
        self.studyListView.selectionModel().selectionChanged.connect(
            lambda selection: self.historyAction(selection, "study"))
        return self.studyListView

    def createExternalListView(self):
        self.externalListView = QListView()
        # Only external file history record is not editable
        self.externalListView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.externalModel = QStringListModel()
        self.externalListView.setModel(self.externalModel)
        self.externalListView.selectionModel().selectionChanged.connect(
            lambda selection: self.historyAction(selection, "external"))
        return self.externalListView

    def filterExternalFileRecords(self):
        # Hide those which do not exist on the current platform
        # This may be useful when users use the same config.py across different platforms
        files = list(reversed(config.history["external"]))
        return [file for file in files if os.path.isfile(file)]

    def refresh(self):
        mainItems = list(reversed(config.history["main"]))
        studyItems = list(reversed(config.history["study"]))
        externalItems = self.filterExternalFileRecords()
        self.mainModel.setStringList(mainItems)
        self.studyModel.setStringList(studyItems)
        self.externalModel.setStringList(externalItems)
        self.setSelection(mainItems, studyItems, externalItems)

    def setSelection(self, mainItems, studyItems, externalItems):
        if mainItems:
            self.mainListView.setCurrentIndex(self.mainModel.index(0, 0))
        if studyItems:
            self.studyListView.setCurrentIndex(self.studyModel.index(0, 0))
        if externalItems:
            self.externalListView.setCurrentIndex(
                self.externalModel.index(0, 0))

    def openLastRecord(self, key):
        selectedItem = config.history[key][-1]
        self.openSelectedItem(selectedItem, key)

    def externalFileAction(self, edit):
        command = "{0}:::-1".format("_editfile" if edit else "_openfile")
        self.parent.runTextCommand(command)

    def historyAction(self, selection, key):
        if not self.parent.isRefreshing:
            selectedItem = selection[0].indexes()[0].data()
            self.openSelectedItem(selectedItem, key)

    def openSelectedItem(self, selectedItem, key):
        if key == "external":
            command = "OPENNOTE:::{0}".format(selectedItem)
            self.parent.runTextCommand(command)
        else:
            self.parent.runTextCommand(selectedItem)
Пример #10
0
class DataTypeKeysWidget(QWidget):
    dataTypeKeySelected = Signal()

    def __init__(self, key_defs):
        QWidget.__init__(self)

        self.__filter_popup = FilterPopup(self, key_defs)
        self.__filter_popup.filterSettingsChanged.connect(self.onItemChanged)

        layout = QVBoxLayout()

        self.model = DataTypeKeysListModel(key_defs)
        self.filter_model = DataTypeProxyModel(self, self.model)

        filter_layout = QHBoxLayout()

        self.search_box = SearchBox()
        self.search_box.filterChanged.connect(self.setSearchString)
        filter_layout.addWidget(self.search_box)

        filter_popup_button = QToolButton()
        filter_popup_button.setIcon(resourceIcon("filter_list.svg"))
        filter_popup_button.clicked.connect(self.showFilterPopup)
        filter_layout.addWidget(filter_popup_button)
        layout.addLayout(filter_layout)

        self.data_type_keys_widget = QListView()
        self.data_type_keys_widget.setModel(self.filter_model)
        self.data_type_keys_widget.selectionModel().selectionChanged.connect(
            self.itemSelected)

        layout.addSpacing(15)
        layout.addWidget(self.data_type_keys_widget, 2)
        layout.addStretch()

        layout.addWidget(
            Legend("Observations available",
                   DataTypeKeysListModel.HAS_OBSERVATIONS))

        self.setLayout(layout)

    def onItemChanged(self, item):
        # self.filter_model.setShowBlockKeys(item["block"])
        for value, visible in item.items():
            self.filter_model.setFilterOnMetadata("data_origin", value,
                                                  visible)

    def itemSelected(self):
        selected_item = self.getSelectedItem()
        if selected_item is not None:
            self.dataTypeKeySelected.emit()

    def getSelectedItem(self):
        """@rtype: str"""
        index = self.data_type_keys_widget.currentIndex()
        source_index = self.filter_model.mapToSource(index)
        item = self.model.itemAt(source_index)
        return item

    def selectDefault(self):
        self.data_type_keys_widget.setCurrentIndex(
            self.filter_model.index(0, 0))

    def setSearchString(self, filter):
        self.filter_model.setFilterFixedString(filter)

    def showFilterPopup(self):
        self.__filter_popup.show()
Пример #11
0
class LibraryLauncher(QWidget):

    def __init__(self, parent):
        super().__init__()
        # set title
        self.setWindowTitle(config.thisTranslation["menu_library"])
        # set up variables
        self.parent = parent
        # setup interface
        self.setupUI()
        self.selectedBook = None

    def setupUI(self):
        mainLayout = QGridLayout()

        leftColumnWidget = QGroupBox(config.thisTranslation["commentaries"])
        commentaryLayout = QVBoxLayout()
        commentaryLayout.addWidget(self.commentaryListView())
        subSubLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(self.openPreviousCommentary)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["activeOnly"])
        button.clicked.connect(self.showActiveOnlyCommentaries)
        subSubLayout.addWidget(button)
        commentaryLayout.addLayout(subSubLayout)

        leftColumnWidget.setLayout(commentaryLayout)

        rightColumnWidget = QGroupBox(config.thisTranslation["menu10_books"])
        bookLayout = QHBoxLayout()
        subLayout = QVBoxLayout()
        subLayout.addWidget(self.bookListView())

        subSubLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["showAll"])
        button.clicked.connect(self.showAllBooks)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["favouriteOnly"])
        button.clicked.connect(self.favouriteBookOnly)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["addFavourite"])
        button.clicked.connect(self.addFavorite)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["removeFavourite"])
        button.clicked.connect(self.removeFavorite)
        subSubLayout.addWidget(button)
        subLayout.addLayout(subSubLayout)
        bookLayout.addLayout(subLayout)

        subLayout = QVBoxLayout()
        subLayout.addWidget(self.chapterListView())
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(self.openPreviousBookChapter)
        subLayout.addWidget(button)
        bookLayout.addLayout(subLayout)
        rightColumnWidget.setLayout(bookLayout)

        mainLayout.addWidget(leftColumnWidget, 0, 0)
        mainLayout.addWidget(rightColumnWidget, 0, 1)
        mainLayout.setColumnStretch(1, 2)
        self.setLayout(mainLayout)

    def testChecked(self, test):
        print(test)

    def commentaryListView(self):
        # https://doc.qt.io/archives/qtforpython-5.12/PySide2/QtCore/QStringListModel.html
        # https://gist.github.com/minoue/9f384cd36339429eb0bf
        # https://www.pythoncentral.io/pyside-pyqt-tutorial-qlistview-and-qstandarditemmodel/
        self.commentaryListView = QListView()
        self.commentaryListView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.reloadCommentariesListModel()
        return self.commentaryListView

    def reloadCommentariesListModel(self, showOnlyActiveCommentaries=False):
        self.commentaryList = []
        activeCommentaries = []
        if showOnlyActiveCommentaries:
            activeCommentaries = [item[1] for item in Commentary().getCommentaryListThatHasBookAndChapter(config.mainB, config.mainC)]
        for index, commentary in enumerate(self.parent.commentaryFullNameList):
            if not showOnlyActiveCommentaries or commentary in activeCommentaries:
                # item = QStandardItem(commentary)
                # item.setToolTip(self.parent.commentaryList[index])
                self.commentaryList.append(commentary)
        model = QStringListModel(self.commentaryList)
        self.commentaryListView.setModel(model)
        if config.commentaryText in self.commentaryList:
            self.commentaryListView.setCurrentIndex(model.index(self.commentaryList.index(config.commentaryText), 0))
        self.commentaryListView.selectionModel().selectionChanged.connect(self.commentarySelected)


    def bookListView(self):
        self.bookList = QListView()
        self.bookList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.reloadBookListModel()
        return self.bookList


    def reloadBookListModel(self, files=None):
        self.dirsAndFiles = self.getSubdirectories()
        if files is None:
            self.dirsAndFiles += BookData().getBooks()
        else:
            books = BookData().getBooks()
            for file in files:
                if file in books:
                    self.dirsAndFiles.append(file)
        self.bookModel = QStringListModel(self.dirsAndFiles)
        self.bookList.setModel(self.bookModel)
        if config.book in self.dirsAndFiles:
            self.bookList.setCurrentIndex(self.bookModel.index(self.dirsAndFiles.index(config.book), 0))
        self.bookList.selectionModel().selectionChanged.connect(self.bookOrFileSelected)

    def getSubdirectories(self):
        return ["../"] + BookData().getDirectories()

    def chapterListView(self):
        self.chapterlist = QListView()
        self.chapterlist.setEditTriggers(QAbstractItemView.NoEditTriggers)
        topicList = self.getBookTopicList()
        self.chapterModel = QStringListModel(topicList)
        self.chapterlist.setModel(self.chapterModel)
        self.scrollChapterList(topicList)
        self.chapterlist.selectionModel().selectionChanged.connect(self.chapterSelected)
        return self.chapterlist

    def getBookTopicList(self):
        return Book(config.book).getTopicList()

    def scrollChapterList(self, topicList):
        self.chapterlist.setCurrentIndex(self.chapterModel.index(topicList.index(config.bookChapter) if topicList and config.bookChapter in topicList else 0, 0))

    def openPreviousCommentary(self):
        command = "COMMENTARY:::{0}:::{1}".format(config.commentaryText, self.parent.bibleTab.getSelectedReference())
        self.parent.runTextCommand(command)

    def openPreviousBookChapter(self):
        if config.bookChapter == "":
            config.bookChapter = self.getBookTopicList()[0]
        command = "BOOK:::{0}:::{1}".format(config.book, config.bookChapter)
        self.parent.runTextCommand(command)

    def commentarySelected(self, selection):
        index = selection[0].indexes()[0].row()
        reverseLookup = {v: k for k, v in Commentary.fileLookup.items()}
        config.commentaryText = reverseLookup[self.commentaryList[index]]
        command = "COMMENTARY:::{0}:::{1}".format(config.commentaryText, self.parent.bibleTab.getSelectedReference())
        self.parent.runTextCommand(command)

    def showActiveOnlyCommentaries(self):
        self.reloadCommentariesListModel(True)

    def showAllBooks(self):
        self.reloadBookListModel()

    def favouriteBookOnly(self):
        self.reloadBookListModel(sorted(config.favouriteBooks))

    def bookOrFileSelected(self, selection):
        self.parent.isRefreshing = True
        self.selectedBook = selection[0].indexes()[0].data()
        if config.book != self.selectedBook:
            if self.selectedBook.endswith("/"):
                config.booksFolder = FileUtil.normalizePath(os.path.join(config.booksFolder, self.selectedBook))
                self.reloadBookListModel()
            else:
                config.book = self.selectedBook
                topicList = self.getBookTopicList()
                self.chapterModel.setStringList(topicList)
                config.bookChapter = topicList[0] if topicList else ""
                self.scrollChapterList(topicList)
                command = "SEARCHBOOK:::{0}:::".format(config.book)
                self.parent.commandField.setText(command)

    def addFavorite(self):
        if self.selectedBook and self.selectedBook not in config.favouriteBooks:
            config.favouriteBooks.append(self.selectedBook)
            self.reloadBookListModel(sorted(config.favouriteBooks))

    def removeFavorite(self):
        if self.selectedBook and self.selectedBook in config.favouriteBooks:
            config.favouriteBooks.remove(self.selectedBook)
            self.reloadBookListModel(sorted(config.favouriteBooks))

    def chapterSelected(self, selection):
        config.bookSearchString = ''
        config.bookChapter = selection[0].indexes()[0].data()
        if self.selectedBook:
            config.book = self.selectedBook
        command = "BOOK:::{0}:::{1}".format(config.book, config.bookChapter)
        if not self.parent.isRefreshing:
            self.parent.runTextCommand(command)
        self.parent.isRefreshing = False
Пример #12
0
class Switcher(QDialog):
    """
    A multi purpose switcher.

    Example
    -------
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherSeparator: [---------------------------------------]
      SwitcherItem:      [title description    <shortcut> section]
      SwitcherItem:      [title description    <shortcut> section]
    """

    # Search/Filter text changes
    sig_text_changed = Signal(TEXT_TYPES[-1])
    # List item selected, mode and cleaned search text
    sig_item_selected = Signal(
        object,
        TEXT_TYPES[-1],
        TEXT_TYPES[-1],
    )
    sig_mode_selected = Signal(TEXT_TYPES[-1])

    _MIN_WIDTH = 500

    def __init__(self,
                 parent,
                 help_text=None,
                 item_styles=ITEM_STYLES,
                 item_separator_styles=ITEM_SEPARATOR_STYLES):
        """Multi purpose switcher."""
        super(Switcher, self).__init__(parent)
        self._visible_rows = 0
        self._modes = {}
        self._mode_on = ''
        self._item_styles = item_styles
        self._item_separator_styles = item_separator_styles

        # Widgets
        self.edit = QLineEdit(self)
        self.list = QListView(self)
        self.model = QStandardItemModel(self.list)
        self.proxy = SwitcherProxyModel(self.list)
        self.filter = KeyPressFilter()

        # Widgets setup
        # self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint)
        self.setWindowOpacity(0.95)
        self.edit.installEventFilter(self.filter)
        self.edit.setPlaceholderText(help_text if help_text else '')
        self.list.setMinimumWidth(self._MIN_WIDTH)
        self.list.setItemDelegate(HTMLDelegate(self))
        self.list.setFocusPolicy(Qt.NoFocus)
        self.list.setSelectionBehavior(self.list.SelectRows)
        self.list.setSelectionMode(self.list.SingleSelection)
        self.proxy.setSourceModel(self.model)
        self.list.setModel(self.proxy)

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.edit)
        layout.addWidget(self.list)
        self.setLayout(layout)

        # Signals
        self.filter.sig_up_key_pressed.connect(self.previous_row)
        self.filter.sig_down_key_pressed.connect(self.next_row)
        self.filter.sig_enter_key_pressed.connect(self.enter)
        self.edit.textChanged.connect(self.setup)
        self.edit.textChanged.connect(self.sig_text_changed)
        self.edit.returnPressed.connect(self.enter)
        self.list.clicked.connect(self.enter)
        self.list.clicked.connect(self.edit.setFocus)

    # --- Helper methods
    def _add_item(self, item):
        """Perform common actions when adding items."""
        item.set_width(self._MIN_WIDTH)
        self.model.appendRow(item)
        self.set_current_row(0)
        self._visible_rows = self.model.rowCount()
        self.setup_sections()

    # --- API
    def clear(self):
        """Remove all items from the list and clear the search text."""
        self.set_placeholder_text('')
        self.model.beginResetModel()
        self.model.clear()
        self.model.endResetModel()

    def set_placeholder_text(self, text):
        """Set the text appearing on the empty line edit."""
        self.edit.setPlaceholderText(text)

    def add_mode(self, token, description):
        """Add mode by token key and description."""
        if len(token) == 1:
            self._modes[token] = description
        else:
            raise Exception('Token must be of length 1!')

    def remove_mode(self, token):
        """Remove mode by token key."""
        if token in self._modes:
            self._modes.pop(token)

    def clear_modes(self):
        """Delete all modes spreviously defined."""
        del self._modes
        self._modes = {}

    def add_item(self,
                 icon=None,
                 title=None,
                 description=None,
                 shortcut=None,
                 section=None,
                 data=None,
                 tool_tip=None,
                 action_item=False):
        """Add switcher list item."""
        item = SwitcherItem(parent=self.list,
                            icon=icon,
                            title=title,
                            description=description,
                            data=data,
                            shortcut=shortcut,
                            section=section,
                            action_item=action_item,
                            tool_tip=tool_tip,
                            styles=self._item_styles)
        self._add_item(item)

    def add_separator(self):
        """Add separator item."""
        item = SwitcherSeparatorItem(parent=self.list,
                                     styles=self._item_separator_styles)
        self._add_item(item)

    def setup(self):
        """Set-up list widget content based on the filtering."""
        # Check exited mode
        mode = self._mode_on
        if mode:
            search_text = self.search_text()[len(mode):]
        else:
            search_text = self.search_text()

        # Check exited mode
        if mode and self.search_text() == '':
            self._mode_on = ''
            self.sig_mode_selected.emit(self._mode_on)
            return

        # Check entered mode
        for key in self._modes:
            if self.search_text().startswith(key) and not mode:
                self._mode_on = key
                self.sig_mode_selected.emit(key)
                return

        # Filter by text
        titles = []
        for row in range(self.model.rowCount()):
            item = self.model.item(row)
            if isinstance(item, SwitcherItem):
                title = item.get_title()
            else:
                title = ''
            titles.append(title)

        search_text = clean_string(search_text)
        scores = get_search_scores(to_text_string(search_text),
                                   titles,
                                   template=u"<b>{0}</b>")

        self._visible_rows = self.model.rowCount()
        for idx, score in enumerate(scores):
            title, rich_title, score_value = score
            item = self.model.item(idx)

            if not self._is_separator(item):
                item.set_rich_title(rich_title)

            item.set_score(score_value)
            proxy_index = self.proxy.mapFromSource(self.model.index(idx, 0))

            if not item.is_action_item():
                self.list.setRowHidden(proxy_index.row(), score_value == -1)

                if score_value == -1:
                    self._visible_rows -= 1

        if self._visible_rows:
            self.set_current_row(0)
        else:
            self.set_current_row(-1)

        self.setup_sections()

    def setup_sections(self):
        """Set-up which sections appear on the item list."""
        mode = self._mode_on
        if mode:
            search_text = self.search_text()[len(mode):]
        else:
            search_text = self.search_text()

        if search_text:
            for row in range(self.model.rowCount()):
                item = self.model.item(row)
                if isinstance(item, SwitcherItem):
                    item.set_section_visible(False)
        else:
            sections = []
            for row in range(self.model.rowCount()):
                item = self.model.item(row)
                if isinstance(item, SwitcherItem):
                    sections.append(item.get_section())
                    item.set_section_visible(bool(search_text))
                else:
                    sections.append('')

                if row != 0:
                    visible = sections[row] != sections[row - 1]
                    if not self._is_separator(item):
                        item.set_section_visible(visible)
                else:
                    item.set_section_visible(True)

        self.proxy.sortBy('_score')

    # --- Qt overrides
    # ------------------------------------------------------------------------
    @Slot()
    @Slot(QListWidgetItem)
    def enter(self, itemClicked=None):
        """Override Qt method."""
        row = self.current_row()
        model_index = self.proxy.mapToSource(self.proxy.index(row, 0))
        item = self.model.item(model_index.row())
        if item:
            mode = self._mode_on
            self.sig_item_selected.emit(item, mode,
                                        self.search_text()[len(mode):])

    def accept(self):
        """Override Qt method."""
        super(Switcher, self).accept()

    def resizeEvent(self, event):
        """Override Qt method."""
        super(Switcher, self).resizeEvent(event)

    # --- Helper methods: Lineedit widget
    def search_text(self):
        """Get the normalized (lowecase) content of the search text."""
        return to_text_string(self.edit.text()).lower()

    def set_search_text(self, string):
        """Set the content of the search text."""
        self.edit.setText(string)

    # --- Helper methods: List widget
    def _is_separator(self, item):
        """Check if item is an separator item (SwitcherSeparatorItem)."""
        return isinstance(item, SwitcherSeparatorItem)

    def _select_row(self, steps):
        """Select row in list widget based on a number of steps with direction.

        Steps can be positive (next rows) or negative (previous rows).
        """
        row = self.current_row() + steps
        if 0 <= row < self.count():
            self.set_current_row(row)

    def count(self):
        """Get the item count in the list widget."""
        return self._visible_rows

    def current_row(self):
        """Return the current selected row in the list widget."""
        return self.list.currentIndex().row()

    def set_current_row(self, row):
        """Set the current selected row in the list widget."""
        index = self.model.index(row, 0)
        selection_model = self.list.selectionModel()

        # https://doc.qt.io/qt-5/qitemselectionmodel.html#SelectionFlag-enum
        selection_model.setCurrentIndex(index, selection_model.ClearAndSelect)

    def previous_row(self):
        """Select previous row in list widget."""
        steps = 1
        prev_row = self.current_row() - steps

        if prev_row == -1:
            self.set_current_row(self.count() - 1)
        else:
            if prev_row >= 0:
                # Need to map the filtered list to the actual model items
                list_index = self.proxy.index(prev_row, 0)
                model_index = self.proxy.mapToSource(list_index)
                item = self.model.item(model_index.row(), 0)
                if self._is_separator(item):
                    steps += 1
            self._select_row(-steps)

    def next_row(self):
        """Select next row in list widget."""
        steps = 1
        next_row = self.current_row() + steps

        # Need to map the filtered list to the actual model items
        list_index = self.proxy.index(next_row, 0)
        model_index = self.proxy.mapToSource(list_index)
        item = self.model.item(model_index.row(), 0)

        if next_row >= self.count():
            self.set_current_row(0)
        else:
            if item:
                if self._is_separator(item):
                    steps += 1
            self._select_row(steps)
Пример #13
0
class LibraryLauncher(QWidget):
    def __init__(self, parent):
        super().__init__()
        # set title
        self.setWindowTitle(config.thisTranslation["menu_library"])
        # set up variables
        self.parent = parent
        # setup interface
        self.setupUI()

    def setupUI(self):
        mainLayout = QGridLayout()

        leftColumnWidget = QGroupBox(config.thisTranslation["commentaries"])
        commentaryLayout = QVBoxLayout()
        commentaryLayout.addWidget(self.commentaryListView())
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(self.openPreviousCommentary)
        commentaryLayout.addWidget(button)
        leftColumnWidget.setLayout(commentaryLayout)

        rightColumnWidget = QGroupBox(config.thisTranslation["menu10_books"])
        bookLayout = QHBoxLayout()
        subLayout = QVBoxLayout()
        subLayout.addWidget(self.bookListView())

        subSubLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["showAll"])
        button.clicked.connect(self.showAllBooks)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["favouriteOnly"])
        button.clicked.connect(self.fvouriteBookOnly)
        subSubLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["addFavourite"])
        button.clicked.connect(self.parent.parent.addFavouriteBookDialog)
        subSubLayout.addWidget(button)
        subLayout.addLayout(subSubLayout)
        bookLayout.addLayout(subLayout)

        subLayout = QVBoxLayout()
        subLayout.addWidget(self.chapterListView())
        button = QPushButton(config.thisTranslation["open"])
        button.clicked.connect(self.openPreviousBookChapter)
        subLayout.addWidget(button)
        bookLayout.addLayout(subLayout)
        rightColumnWidget.setLayout(bookLayout)

        mainLayout.addWidget(leftColumnWidget, 0, 0)
        mainLayout.addWidget(rightColumnWidget, 0, 1)
        mainLayout.setColumnStretch(1, 2)
        self.setLayout(mainLayout)

    def testChecked(self, test):
        print(test)

    def commentaryListView(self):
        # https://doc.qt.io/archives/qtforpython-5.12/PySide2/QtCore/QStringListModel.html
        # https://gist.github.com/minoue/9f384cd36339429eb0bf
        # https://www.pythoncentral.io/pyside-pyqt-tutorial-qlistview-and-qstandarditemmodel/
        list = QListView()
        list.setEditTriggers(QAbstractItemView.NoEditTriggers)
        model = QStandardItemModel(list)
        for index, commentary in enumerate(self.parent.commentaryFullNameList):
            item = QStandardItem(commentary)
            item.setToolTip(self.parent.commentaryList[index])
            #item.setCheckable(True)
            #item.setCheckState(Qt.CheckState.Checked)
            #item.setCheckState(Qt.CheckState.Unchecked)
            #print(item.checkState() is Qt.CheckState.Checked)
            model.appendRow(item)
        #model = QStringListModel(self.parent.commentaryList)
        #model = QStringListModel(self.parent.commentaryFullNameList)
        list.setModel(model)
        if config.commentaryText in self.parent.commentaryList:
            list.setCurrentIndex(
                model.index(
                    self.parent.commentaryList.index(config.commentaryText),
                    0))
        list.selectionModel().selectionChanged.connect(self.commentarySelected)
        return list

    def bookListView(self):
        self.bookList = QListView()
        self.bookList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.bookModel = QStringListModel(self.parent.referenceBookList)
        self.bookList.setModel(self.bookModel)
        if config.book in self.parent.referenceBookList:
            self.bookList.setCurrentIndex(
                self.bookModel.index(
                    self.parent.referenceBookList.index(config.book), 0))
        self.bookList.selectionModel().selectionChanged.connect(
            self.bookSelected)
        return self.bookList

    def chapterListView(self):
        self.chapterlist = QListView()
        self.chapterlist.setEditTriggers(QAbstractItemView.NoEditTriggers)
        topicList = self.getBookTopicList()
        self.chapterModel = QStringListModel(topicList)
        self.chapterlist.setModel(self.chapterModel)
        self.scrollChapterList(topicList)
        self.chapterlist.selectionModel().selectionChanged.connect(
            self.chapterSelected)
        return self.chapterlist

    def getBookTopicList(self):
        return Book(config.book).getTopicList(
        ) if config.book in self.parent.referenceBookList else []

    def scrollChapterList(self, topicList):
        self.chapterlist.setCurrentIndex(
            self.chapterModel.index(
                topicList.index(config.bookChapter)
                if topicList and config.bookChapter in topicList else 0, 0))

    def openPreviousCommentary(self):
        command = "COMMENTARY:::{0}:::{1}".format(
            config.commentaryText, self.parent.bibleTab.getSelectedReference())
        self.parent.runTextCommand(command)

    def openPreviousBookChapter(self):
        command = "BOOK:::{0}:::{1}".format(config.book, config.bookChapter)
        self.parent.runTextCommand(command)

    def commentarySelected(self, selection):
        #config.commentaryText = selection[0].indexes()[0].data()
        index = selection[0].indexes()[0].row()
        config.commentaryText = self.parent.commentaryList[index]
        command = "COMMENTARY:::{0}:::{1}".format(
            config.commentaryText, self.parent.bibleTab.getSelectedReference())
        self.parent.runTextCommand(command)

    def showAllBooks(self):
        self.bookModel.setStringList(self.parent.referenceBookList)
        self.bookList.setCurrentIndex(self.bookModel.index(0, 0))

    def fvouriteBookOnly(self):
        self.bookModel.setStringList(config.favouriteBooks)
        self.bookList.setCurrentIndex(self.bookModel.index(0, 0))

    def bookSelected(self, selection):
        self.parent.isRefreshing = True
        selectedBook = selection[0].indexes()[0].data()
        if config.book != selectedBook:
            config.book = selectedBook
            topicList = self.getBookTopicList()
            self.chapterModel.setStringList(topicList)
            config.bookChapter = topicList[0] if topicList else ""
            self.scrollChapterList(topicList)

    def chapterSelected(self, selection):
        config.bookChapter = selection[0].indexes()[0].data()
        command = "BOOK:::{0}:::{1}".format(config.book, config.bookChapter)
        if not self.parent.isRefreshing:
            self.parent.runTextCommand(command)
        self.parent.isRefreshing = False
Пример #14
0
class ProgressView(QWidget):
    """
    :type batch_manager: CalculationManager
    """
    def __init__(self, parent, batch_manager):
        super().__init__(parent)
        self.task_count = 0
        self.calculation_manager = batch_manager
        self.whole_progress = QProgressBar(self)
        self.whole_progress.setMinimum(0)
        self.whole_progress.setMaximum(1)
        self.whole_progress.setFormat("%v of %m")
        self.whole_progress.setTextVisible(True)
        self.part_progress = QProgressBar(self)
        self.part_progress.setMinimum(0)
        self.part_progress.setMaximum(1)
        self.part_progress.setFormat("%v of %m")
        self.whole_label = QLabel("All batch progress:", self)
        self.part_label = QLabel("Single batch progress:", self)
        self.cancel_remove_btn = QPushButton("Remove task")
        self.cancel_remove_btn.setDisabled(True)
        self.logs = ExceptionList(self)
        self.logs.setToolTip("Logs")
        self.task_view = QListView()
        self.task_que = QStandardItemModel(self)
        self.task_view.setModel(self.task_que)
        self.process_num_timer = QTimer()
        self.process_num_timer.setInterval(1000)
        self.process_num_timer.setSingleShot(True)
        self.process_num_timer.timeout.connect(self.change_number_of_workers)
        self.number_of_process = QSpinBox(self)
        self.number_of_process.setRange(1, multiprocessing.cpu_count())
        self.number_of_process.setValue(1)
        self.number_of_process.setToolTip(
            "Number of process used in batch calculation")
        self.number_of_process.valueChanged.connect(
            self.process_num_timer_start)
        self.progress_item_dict = {}
        layout = QGridLayout()
        layout.addWidget(self.whole_label, 0, 0, Qt.AlignRight)
        layout.addWidget(self.whole_progress, 0, 1, 1, 2)
        layout.addWidget(self.part_label, 1, 0, Qt.AlignRight)
        layout.addWidget(self.part_progress, 1, 1, 1, 2)
        lab = QLabel("Number of process:")
        lab.setToolTip("Number of process used in batch calculation")
        layout.addWidget(lab, 2, 0)
        layout.addWidget(self.number_of_process, 2, 1)
        layout.addWidget(self.logs, 3, 0, 2, 3)
        layout.addWidget(self.task_view, 0, 4, 4, 1)
        layout.addWidget(self.cancel_remove_btn, 4, 4, 1, 1)
        layout.setColumnMinimumWidth(2, 10)
        layout.setColumnStretch(2, 1)
        self.setLayout(layout)
        self.preview_timer = QTimer()
        self.preview_timer.setInterval(1000)
        self.preview_timer.timeout.connect(self.update_info)
        self.task_view.selectionModel().currentChanged.connect(
            self.task_selection_change)
        self.cancel_remove_btn.clicked.connect(self.task_cancel_remove)

    def task_selection_change(self, new, old):
        task: CalculationProcessItem = self.task_que.item(
            new.row(), new.column())
        if task is None:
            self.cancel_remove_btn.setDisabled(True)
            return
        self.cancel_remove_btn.setEnabled(True)
        if task.is_finished():
            self.cancel_remove_btn.setText(f"Remove task {task.num}")
        else:
            self.cancel_remove_btn.setText(f"Cancel task {task.num}")

    def task_cancel_remove(self):
        index = self.task_view.selectionModel().currentIndex()
        task: CalculationProcessItem = self.task_que.item(
            index.row(), index.column())
        if task.is_finished():
            self.calculation_manager.remove_calculation(task.calculation)
            self.task_que.takeRow(index.row())
        else:
            self.calculation_manager.cancel_calculation(task.calculation)
        print(task)

    def new_task(self):
        self.whole_progress.setMaximum(
            self.calculation_manager.calculation_size)
        if not self.preview_timer.isActive():
            self.update_info()
            self.preview_timer.start()

    def update_info(self):
        res = self.calculation_manager.get_results()
        for el in res.errors:
            if el[0]:
                QListWidgetItem(el[0], self.logs)
            ExceptionListItem(el[1], self.logs)
            if (state_store.report_errors and parsed_version.is_devrelease
                    and not isinstance(el[1][0], SegmentationLimitException)
                    and isinstance(el[1][1], tuple)):
                with sentry_sdk.push_scope() as scope:
                    scope.set_tag("auto_report", "true")
                    sentry_sdk.capture_event(el[1][1][0])
        self.whole_progress.setValue(res.global_counter)
        working_search = True
        for uuid, progress in res.jobs_status.items():
            calculation = self.calculation_manager.calculation_dict[uuid]
            total = len(calculation.file_list)
            if uuid in self.progress_item_dict:
                item = self.progress_item_dict[uuid]
                item.update_count(progress)
            else:
                item = CalculationProcessItem(calculation, self.task_count,
                                              progress)
                self.task_count += 1
                self.task_que.appendRow(item)
                self.progress_item_dict[uuid] = item

            if working_search and progress != total:
                self.part_progress.setMaximum(total)
                self.part_progress.setValue(progress)
                working_search = False
        if not self.calculation_manager.has_work:
            self.part_progress.setValue(self.part_progress.maximum())
            self.preview_timer.stop()
            logging.info("Progress stop")

    def process_num_timer_start(self):
        self.process_num_timer.start()

    def update_progress(self, total_progress, part_progress):
        self.whole_progress.setValue(total_progress)
        self.part_progress.setValue(part_progress)

    def set_total_size(self, size):
        self.whole_progress.setMaximum(size)

    def set_part_size(self, size):
        self.part_progress.setMaximum(size)

    def change_number_of_workers(self):
        self.calculation_manager.set_number_of_workers(
            self.number_of_process.value())