Пример #1
0
    def __init__(self, plotted_lines, *args, **kwargs):
        super().__init__(None, *args, **kwargs)

        self.plotted_lines = plotted_lines

        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetMaximumSize)
        self.setLayout(layout)

        table_model = LineListTableModel(plotted_lines)
        if table_model.rowCount() > 0:
            table_view = QTableView()

            # disabling sorting will significantly speed up theWidget
            # plot. This is because the table view must be re-built
            # every time a new set of markers is drawn on the plot
            # surface. Alternate approaches are worth examining. It
            # remains to be seen what would be the approach users
            # will favor.

            table_view.setSortingEnabled(False)
            proxy = SortModel(table_model.get_name())
            proxy.setSourceModel(table_model)
            table_view.setModel(proxy)
            table_view.setSortingEnabled(True)

            table_view.setSelectionMode(QAbstractItemView.NoSelection)
            table_view.horizontalHeader().setStretchLastSection(True)
            table_view.resizeColumnsToContents()

            layout.addWidget(table_view)
Пример #2
0
    def __init__(self, plotted_lines, *args, **kwargs):
        super().__init__(None, *args, **kwargs)

        self.plotted_lines = plotted_lines

        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetMaximumSize)
        self.setLayout(layout)

        table_model = LineListTableModel(plotted_lines)
        if table_model.rowCount() > 0:
            table_view = QTableView()

            # disabling sorting will significantly speed up the
            # plot. This is because the table view must be re-built
            # every time a new set of markers is drawn on the plot
            # surface. Alternate approaches are worth examining. It
            # remains to be seen what would be the approach users
            # will favor.

            table_view.setSortingEnabled(False)
            proxy = SortModel(table_model.getName())
            proxy.setSourceModel(table_model)
            table_view.setModel(proxy)
            table_view.setSortingEnabled(True)

            table_view.setSelectionMode(QAbstractItemView.NoSelection)
            table_view.horizontalHeader().setStretchLastSection(True)
            table_view.resizeColumnsToContents()

            layout.addWidget(table_view)
Пример #3
0
    def __init__(self, fileName, parent=None):
        QObject.__init__(self)
        sweepCollection = IvSweepCollection(str(fileName))
        self.sweepCollection = sweepCollection

        tableModel = SweepTableModel(sweepCollection)

        tableView = QTableView()
        tableView.setModel(tableModel)
        tableView.setItemDelegateForColumn(0,
                                           CheckBoxDelegate(parent=tableView))
        tableView.setItemDelegateForColumn(1,
                                           CheckBoxDelegate(parent=tableView))
        self.tableModel = tableModel
        tableView.resizeColumnsToContents()
        tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        sm = tableView.selectionModel()
        sm.currentRowChanged.connect(self.selectedRowChanged)
        self.tableView = tableView

        dockWidget = QDockWidget('Sweeps')
        dockWidget.setWidget(tableView)
        self.sweepTableDock = dockWidget

        hkDock = HkDockWidget(sweepCollection.hk)
        hkDock.setWindowTitle('HK - %s' % str(fileName))
        self.hkDock = hkDock

        ivGraphWidget = IvGraphWidget(sweepCollection)

        tableModel.plotToggled.connect(ivGraphWidget.showSweep)
        #tableModel.badToggled.connect(self.toggleBad)

        self.ivGraphWidget = ivGraphWidget
Пример #4
0
class DisplayShortcutsWindow(QDialog):
    def __init__(self, name, shortcuts):
        super(DisplayShortcutsWindow, self).__init__()

        self.name = name
        self.setWindowTitle(name)
        self.setMinimumWidth(360)
        self.setMinimumHeight(500)
        self.layout = QVBoxLayout()

        self.filterEntry = QLineEdit()
        self.filterEntry.textChanged.connect(self.filterChanged)
        self.layout.addWidget(self.filterEntry)

        self.table = QTableView()
        self.model = DisplayShortcutsModel(self, shortcuts)
        self.table.setModel(self.model)
        self.table.resizeColumnsToContents()
        self.table.setSortingEnabled(True)
        if self.name not in ShortcutUtil.data.keys():
            self.table.doubleClicked.connect(self.clickedRow)
        self.layout.addWidget(self.table)

        if name in ShortcutUtil.data.keys():
            buttons = QDialogButtonBox.Ok
        else:
            buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(buttons)
        self.buttonBox.accepted.connect(self.saveShortcut)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.rejected.connect(self.canceled)
        self.layout.addWidget(self.buttonBox)
        self.setLayout(self.layout)

    def clickedRow(self, index):
        row = self.model.getRow(index.row())
        (action, key) = row
        newKey, ok = QInputDialog.getText(self, 'Shortcut', action,
                                          QLineEdit.Normal, key)
        if ok:
            self.model.list[index.row()] = (action, newKey)
            for item in self.model.fullList:
                if item[0] == action:
                    item[1] = newKey

    def saveShortcut(self):
        if self.name not in ShortcutUtil.data.keys():
            ShortcutUtil.createShortcutFile(self.name, self.model.fullList)

    def canceled(self):
        if self.name not in ShortcutUtil.data.keys():
            ShortcutUtil.loadShortcutFile(self.name)

    def filterChanged(self, text):
        self.model.filter(text)
Пример #5
0
class DataFrameWidget(QWidget):
    ''' a simple widget for using DataFrames in a gui '''
    def __init__(self, dataFrame, parent=None):
        super(DataFrameWidget, self).__init__(parent)

        self.dataModel = DataFrameModel()
        self.dataTable = QTableView()
        self.dataTable.setModel(self.dataModel)

        layout = QVBoxLayout()
        layout.addWidget(self.dataTable)
        self.setLayout(layout)
        # Set DataFrame
        self.setDataFrame(dataFrame)

    def setDataFrame(self, dataFrame):
        self.dataModel.setDataFrame(dataFrame)
        self.dataModel.signalUpdate()
        self.dataTable.resizeColumnsToContents()
Пример #6
0
    def buildViews(self, plot_window):

        # Table views must be preserved in the instance so they can be
        # passed to whoever is going to do the actual line list plotting.
        # The plotting code must know which lines (table rows) are selected
        # in each line list.
        self._table_views = []

        for linelist in plot_window.linelists:

            table_model = LineListTableModel(linelist)
            proxy = SortModel(table_model.getName())
            proxy.setSourceModel(table_model)

            if table_model.rowCount() > 0:
                table_view = QTableView()
                table_view.setModel(proxy)

                # setting this to False will significantly speed up
                # the loading of very large line lists. However, these
                # lists are often jumbled in wavelength, and consequently
                # difficult to read and use. It remains to be seen what
                # would be the approach users will favor.
                table_view.setSortingEnabled(True)

                table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
                table_view.horizontalHeader().setStretchLastSection(True)
                table_view.resizeColumnsToContents()
                comments = linelist.meta['comments']

                # this preserves the original sorting state
                # of the list. Use zero to sort by wavelength
                # on load. Doesn't seem to affect performance
                # by much tough.
                proxy.sort(-1, Qt.AscendingOrder)

                pane = self._buildLinelistPane(table_view, comments)

                self.tabWidget.addTab(pane, table_model.getName())

                self._table_views.append(table_view)
Пример #7
0
def _create_line_list_pane(linelist, table_model, caller):

    table_view = QTableView()

    # disabling sorting will significantly speed up the rendering,
    # in particular of large line lists. These lists are often jumbled
    # in wavelength, and consequently difficult to read and use, so
    # having a sorting option is useful indeed. It remains to be seen
    # what would be the approach users will favor. We might add a toggle
    # that users can set/reset depending on their preferences.
    table_view.setSortingEnabled(False)
    sort_proxy = SortModel(table_model.get_name())
    sort_proxy.setSourceModel(table_model)

    table_view.setModel(sort_proxy)
    table_view.setSortingEnabled(True)
    table_view.horizontalHeader().setStretchLastSection(True)

    # playing with these doesn't speed up the sorting, regardless of whatever
    # you may read on the net.
    #
    # table_view.horizontalHeader().setResizeMode(QHeaderView.Fixed)
    # table_view.verticalHeader().setResizeMode(QHeaderView.Fixed)
    # table_view.horizontalHeader().setStretchLastSection(False)
    # table_view.verticalHeader().setStretchLastSection(False)
    table_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
    table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
    table_view.resizeColumnsToContents()

    # this preserves the original sorting state of the list. Use zero
    # to sort by wavelength on load. Doesn't seem to affect performance
    # by much tough.
    sort_proxy.sort(-1, Qt.AscendingOrder)

    # table selections will change the total count of lines selected.
    pane = LineListPane(table_view, linelist, sort_proxy, caller)

    return pane, table_view
Пример #8
0
def _createLineListPane(linelist, table_model, caller):

    table_view = QTableView()

    # disabling sorting will significantly speed up the rendering,
    # in particular of large line lists. These lists are often jumbled
    # in wavelength, and consequently difficult to read and use, so
    # having a sorting option is useful indeed. It remains to be seen
    # what would be the approach users will favor. We might add a toggle
    # that users can set/reset depending on their preferences.
    table_view.setSortingEnabled(False)
    sort_proxy = SortModel(table_model.getName())
    sort_proxy.setSourceModel(table_model)

    table_view.setModel(sort_proxy)
    table_view.setSortingEnabled(True)
    table_view.horizontalHeader().setStretchLastSection(True)

    # playing with these doesn't speed up the sorting, regardless of whatever
    # you may read on the net.
    #
    # table_view.horizontalHeader().setResizeMode(QHeaderView.Fixed)
    # table_view.verticalHeader().setResizeMode(QHeaderView.Fixed)
    # table_view.horizontalHeader().setStretchLastSection(False)
    # table_view.verticalHeader().setStretchLastSection(False)
    table_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
    table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
    table_view.resizeColumnsToContents()

    # this preserves the original sorting state of the list. Use zero
    # to sort by wavelength on load. Doesn't seem to affect performance
    # by much tough.
    sort_proxy.sort(-1, Qt.AscendingOrder)

    # table selections will change the total count of lines selected.
    pane = LineListPane(table_view, linelist, sort_proxy, caller)

    return pane, table_view
Пример #9
0
class ConfigurationManager(SiriusMainWindow):
    """."""

    NAME_COL = None
    CONFIG_TYPE_COL = None

    def __init__(self, model, parent=None):
        """Constructor."""
        super().__init__(parent)
        self._model = model
        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.INFO)
        self._setup_ui()
        self.setWindowTitle("Configuration Manager")

    def _setup_ui(self):
        # self.setGeometry(0, 0, 1600, 900)
        self.main_widget = QFrame()
        self.main_widget.setObjectName('ServConf')
        self.setCentralWidget(self.main_widget)
        self.layout = QGridLayout()
        self.main_widget.setLayout(self.layout)

        # Basic widgets
        self.editor = QTableView()
        self.delete_button = QPushButton('Delete', self)
        self.delete_button.setObjectName('DeleteButton')
        self.rename_button = QPushButton('Rename', self)
        self.rename_button.setObjectName('RenameButton')
        self.d_editor = QTableView()
        self.retrieve_button = QPushButton('Retrieve', self)
        self.retrieve_button.setObjectName('RetrieveButton')
        self.tree = QTreeView(self)
        self.config_type = QComboBox(parent=self)
        self.config_type.setModel(
                ConfigTypeModel(self._model, self.config_type))

        # Tab widgets
        self.tab1 = QWidget()
        self.tab1.layout = QVBoxLayout(self.tab1)
        self.tab2 = QWidget()
        self.tab2.layout = QVBoxLayout(self.tab2)
        self.tab1.layout.addWidget(self.editor)
        hlay = QHBoxLayout()
        hlay.addWidget(self.rename_button)
        hlay.addWidget(self.delete_button)
        self.tab1.layout.addLayout(hlay)
        self.tab2.layout.addWidget(self.d_editor)
        self.tab2.layout.addWidget(self.retrieve_button)

        self.editor_tab = QTabWidget(self)
        self.editor_tab.addTab(self.tab1, 'Configurations')
        self.editor_tab.addTab(self.tab2, 'Discarded Configurations')
        self.config_viewer = QWidget(self)
        self.config_viewer.layout = QVBoxLayout(self.config_viewer)
        self.config_viewer.layout.addWidget(self.editor_tab)
        self.config_viewer.layout.addWidget(self.tree)

        # Header widget
        self.header = QFrame(self)
        self.header.setObjectName('Header')
        self.header.layout = QHBoxLayout(self.header)
        self.header.layout.addStretch()
        self.header.layout.addWidget(
            QLabel('Configuration Database Manager', self.header))
        self.header.layout.addStretch()

        # Sub header with database genral information
        self.sub_header = QFrame(self)
        self.sub_header.setObjectName('SubHeader')
        self.sub_header.layout = QVBoxLayout(self.sub_header)

        self.server_layout = QHBoxLayout()
        self.server_layout.addWidget(QLabel('<b>Server:</b>', self.sub_header))
        self.server_layout.addWidget(QLabel(self._model.url, self.sub_header))
        self.server_layout.addStretch()

        self.size_layout = QHBoxLayout()
        self.size_layout.addWidget(QLabel('<b>DB Size:</b>', self.sub_header))
        try:
            dbsize = self._model.get_dbsize()
            dbsize = '{:.2f} MB'.format(dbsize/(1024*1024))
        except ConfigDBException:
            dbsize = 'Failed to retrieve information'
        self.size_layout.addWidget(QLabel(dbsize, self.sub_header))
        self.size_layout.addStretch()

        self.sub_header.layout.addLayout(self.server_layout)
        self.sub_header.layout.addLayout(self.size_layout)

        # Query form
        self.query_form = QFrame()
        self.query_form.setObjectName("QueryForm")
        self.query_form.layout = QVBoxLayout()
        self.query_form.setLayout(self.query_form.layout)

        self.configs_layout = QGridLayout()
        self.configs_layout.addWidget(QLabel('Configurations:', self), 0, 0)
        self.nr_configs = QLabel(self)
        self.configs_layout.addWidget(self.nr_configs, 0, 1)
        self.configs_layout.addWidget(QLabel('Discarded:', self), 0, 2)
        self.nr_discarded = QLabel(self)
        self.configs_layout.addWidget(self.nr_discarded, 0, 3)

        self.query_form.layout.addWidget(self.config_type)
        self.query_form.layout.addLayout(self.configs_layout)

        # Main widget layout setup
        self.layout.addWidget(self.header, 0, 0, 1, 3)
        self.layout.addWidget(self.sub_header, 1, 0, 1, 2)
        self.layout.addWidget(self.query_form, 2, 0, 1, 2)
        self.layout.addWidget(self.config_viewer, 3, 0, 1, 2)
        self.layout.addWidget(self.tree, 1, 2, 4, 1)
        # self.layout.addWidget(self.delete_button, 4, 0, 1, 2)
        self.layout.setColumnStretch(0, 1)
        self.layout.setColumnStretch(1, 2)
        self.layout.setColumnStretch(2, 2)

        # Set table models and options
        self.editor_model = ConfigDbTableModel('notexist', self._model)
        self.d_editor_model = ConfigDbTableModel('notexist', self._model, True)
        self.editor.setModel(self.editor_model)
        self.editor.setSelectionBehavior(self.editor.SelectRows)
        self.editor.setSortingEnabled(True)
        self.editor.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        self.d_editor.setModel(self.d_editor_model)
        self.d_editor.setSelectionBehavior(self.editor.SelectRows)
        self.d_editor.setSortingEnabled(True)
        self.d_editor.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        self.d_editor.setSelectionMode(self.d_editor.SingleSelection)
        # Set tree model and options
        self.tree_model = JsonTreeModel(None, None, self._model)
        self.tree.setModel(self.tree_model)
        # Delete button
        self.delete_button.setEnabled(False)
        self.rename_button.setEnabled(True)
        self.retrieve_button.setEnabled(False)

        # Signals and slots

        # Tab
        self.editor_tab.currentChanged.connect(self._tab_changed)
        # Fill tables when configuration is selected
        self.config_type.currentTextChanged.connect(self._fill_table)
        # Fill tree when a configuration is selected
        self.editor.selectionModel().selectionChanged.connect(
            lambda x, y: self._fill_tree())
        self.d_editor.selectionModel().selectionChanged.connect(
            lambda x, y: self._fill_tree())
        # Connect database error to slot that show messages
        self.editor_model.connectionError.connect(self._database_error)
        self.d_editor_model.connectionError.connect(self._database_error)
        # Makes tree column extend automatically to show content
        self.tree.expanded.connect(
            lambda idx: self.tree.resizeColumnToContents(idx.column()))
        # Button action
        self.delete_button.pressed.connect(self._remove_configuration)
        self.rename_button.pressed.connect(self._rename_configuration)
        self.retrieve_button.pressed.connect(self._retrieve_configuration)
        # Set constants
        ConfigurationManager.NAME_COL = \
            self.editor_model.horizontalHeader.index('name')
        ConfigurationManager.CONFIG_TYPE_COL = \
            self.editor_model.horizontalHeader.index('config_type')

        self.editor.resizeColumnsToContents()
        self.d_editor.resizeColumnsToContents()

    @Slot(str)
    def _fill_table(self, config_type):
        """Fill table with configuration of `config_type`."""
        leng = len(self._model.find_configs(
            config_type=config_type, discarded=False))
        self.nr_configs.setText(str(leng))
        leng = len(self._model.find_configs(
            config_type=config_type, discarded=True))
        self.nr_discarded.setText(str(leng))

        self.editor_model.setupModelData(config_type)
        self.d_editor_model.setupModelData(config_type)
        self.editor.resizeColumnsToContents()
        self.d_editor.resizeColumnsToContents()
        self.editor_model.sort(2, Qt.DescendingOrder)
        self.d_editor_model.sort(2, Qt.DescendingOrder)

    @Slot()
    def _fill_tree(self):
        if self.editor_tab.currentIndex() == 0:
            configs = list()
            rows = self._get_selected_rows(self.editor)
            # Get selected rows
            for row in rows:
                # Get name and configuration type
                configs.append(self._type_name(row, self.editor_model))
            # Set tree data
            self.tree_model.setupModelData(configs)
            if len(configs) == 1:
                self.delete_button.setEnabled(True)
                self.delete_button.setText(
                    'Delete {} ({})'.format(configs[0][1], configs[0][0]))
                self.rename_button.setEnabled(True)
                self.rename_button.setText(
                    'Rename {} ({})'.format(configs[0][1], configs[0][0]))

            elif len(configs) > 1:
                self.rename_button.setEnabled(False)
                self.rename_button.setText('Rename')
                self.delete_button.setEnabled(True)
                self.delete_button.setText(
                    'Delete {} configurations'.format(len(configs)))
            else:
                self.rename_button.setEnabled(False)
                self.rename_button.setText('Rename')
                self.delete_button.setEnabled(False)
            self.delete_button.style().polish(self.delete_button)
            self.rename_button.style().polish(self.rename_button)
        else:
            try:
                row = self._get_selected_rows(self.d_editor).pop()
            except KeyError:
                self.retrieve_button.setEnabled(False)
                self.retrieve_button.style().polish(self.retrieve_button)
            else:
                config_type, name = self._type_name(row, self.d_editor_model)
                self.tree_model.setupModelData([(config_type, name)])
                self.retrieve_button.setEnabled(True)
                self.retrieve_button.style().polish(self.retrieve_button)
        # self.tree.resizeColumnsToContents()

    @Slot()
    def _remove_configuration(self):
        type = QMessageBox.Question
        title = 'Remove configuration?'
        buttons = QMessageBox.Ok | QMessageBox.Cancel

        # self.editor.selectRow(index.row())
        rows = list(self._get_selected_rows(self.editor))
        message = 'Remove configurations:\n'
        for row in rows:
            config_type = self.editor_model.createIndex(row, 0).data()
            name = self.editor_model.createIndex(row, 1).data()
            message += '- {} ({})\n'.format(name, config_type)

        msg = QMessageBox(type, title, message, buttons).exec_()
        if msg == QMessageBox.Ok:
            rows.sort(reverse=True)
            for row in rows:
                self.editor_model.removeRows(row)

        self.editor.selectionModel().clearSelection()
        self._fill_table(self.config_type.currentText())

    @Slot()
    def _rename_configuration(self):
        # self.editor.selectRow(index.row())
        rows = list(self._get_selected_rows(self.editor))
        if not rows:
            return
        config_type = self.editor_model.createIndex(rows[0], 0).data()
        name = self.editor_model.createIndex(rows[0], 1).data()

        wid = RenameConfigDialog(config_type, self)
        wid.setWindowTitle('Rename: {}'.format(name))
        wid.search_le.setText(name)
        newname, status = wid.exec_()
        if not newname or not status:
            return
        self._model.rename_config(
            name, newname, config_type=config_type)

        self.editor.selectionModel().clearSelection()
        self._fill_table(self.config_type.currentText())

    @Slot()
    def _retrieve_configuration(self):
        type = QMessageBox.Question
        title = 'Retrieve configuration?'
        buttons = QMessageBox.Ok | QMessageBox.Cancel

        try:
            row = self._get_selected_rows(self.d_editor).pop()
        except KeyError:
            pass
        else:
            config_type, name = self._type_name(row, self.d_editor_model)
            name = name[:-37]
            message = \
                'Retrieve configuration {} ({})?'.format(config_type, name)
            msg = QMessageBox(type, title, message, buttons).exec_()
            if msg == QMessageBox.Ok:
                try:
                    self.d_editor_model.removeRows(row)
                except TypeError:
                    self._database_error(
                        'Exception',
                        'Configuration no longer is in the correct format',
                        'retrieve configuration')

        self.editor.selectionModel().clearSelection()
        self._fill_table(self.config_type.currentText())

    @Slot(int)
    def _tab_changed(self, index):
        if index == 0:
            self.editor.selectionModel().clearSelection()
            self.delete_button.setText('Delete')
            self.delete_button.setEnabled(False)
            self.delete_button.style().polish(self.delete_button)
            self.rename_button.setText('Rename')
            self.rename_button.setEnabled(False)
            self.rename_button.style().polish(self.rename_button)
        else:
            self.d_editor.selectionModel().clearSelection()
            self.retrieve_button.setEnabled(False)
            self.retrieve_button.style().polish(self.retrieve_button)
        self.tree_model.setupModelData([])

    @Slot(int, str, str)
    def _database_error(self, code, message, operation):
        type = QMessageBox.Warning
        title = 'Something went wrong'
        msg = '{}: {}, while trying to {}'.format(code, message, operation)
        QMessageBox(type, title, msg).exec_()

    def _get_selected_rows(self, table):
        index_list = table.selectionModel().selectedIndexes()
        return {idx.row() for idx in index_list}

    def _type_name(self, row, model):
        # Return config_type and name given a row and a table model
        return (model.createIndex(row, self.CONFIG_TYPE_COL).data(),
                model.createIndex(row, self.NAME_COL).data())
Пример #10
0
class MxDataWidget(QWidget):
    """
    Dialog for displaying and editing DataFrame and related objects.

    Based on the gtabview project (ExtTableView).
    For more information please see:
    https://github.com/wavexx/gtabview/blob/master/gtabview/viewer.py

    Signals
    -------
    sig_option_changed(str, object): Raised if an option is changed.
       Arguments are name of option and its new value.
    """
    sig_option_changed = Signal(str, object)

    def __init__(self, parent=None, data=DataFrame()):
        QWidget.__init__(self, parent)
        # Destroying the C++ object right after closing the dialog box,
        # otherwise it may be garbage-collected in another QThread
        # (e.g. the editor's analysis thread in Spyder), thus leading to
        # a segmentation fault on UNIX or an application crash on Windows
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.is_series = False
        self.layout = None
        self.setup_and_check(data)

    def setup_and_check(self, data, title=''):
        """
        Setup DataFrameEditor:
        return False if data is not supported, True otherwise.
        Supported types for data are DataFrame, Series and Index.
        """
        self._selection_rec = False
        self._model = None

        self.layout = QGridLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        self.setWindowIcon(ima.icon('arredit'))
        if title:
            title = to_text_string(title) + " - %s" % data.__class__.__name__
        else:
            title = _("%s editor") % data.__class__.__name__
        if isinstance(data, Series):
            self.is_series = True
            data = data.to_frame()
        elif isinstance(data, Index):
            data = DataFrame(data)

        self.setWindowTitle(title)
        # self.resize(600, 500)

        self.hscroll = QScrollBar(Qt.Horizontal)
        self.vscroll = QScrollBar(Qt.Vertical)

        # Create the view for the level
        self.create_table_level()

        # Create the view for the horizontal header
        self.create_table_header()

        # Create the view for the vertical index
        self.create_table_index()

        # Create the model and view of the data
        self.dataModel = MxDataModel(data, parent=self)
        # self.dataModel.dataChanged.connect(self.save_and_close_enable)
        self.create_data_table()

        self.layout.addWidget(self.hscroll, 2, 0, 1, 2)
        self.layout.addWidget(self.vscroll, 0, 2, 2, 1)

        # autosize columns on-demand
        self._autosized_cols = set()
        self._max_autosize_ms = None
        self.dataTable.installEventFilter(self)

        avg_width = self.fontMetrics().averageCharWidth()
        self.min_trunc = avg_width * 8  # Minimum size for columns
        self.max_width = avg_width * 64  # Maximum size for columns

        self.setLayout(self.layout)
        # Make the dialog act as a window
        # self.setWindowFlags(Qt.Window)

        self.setModel(self.dataModel)
        self.resizeColumnsToContents()

        return True

    def create_table_level(self):
        """Create the QTableView that will hold the level model."""
        self.table_level = QTableView()
        self.table_level.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_level.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_level.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_level.setFrameStyle(QFrame.Plain)
        self.table_level.horizontalHeader().sectionResized.connect(
            self._index_resized)
        self.table_level.verticalHeader().sectionResized.connect(
            self._header_resized)
        # self.table_level.setItemDelegate(QItemDelegate())
        self.layout.addWidget(self.table_level, 0, 0)
        self.table_level.setContentsMargins(0, 0, 0, 0)
        self.table_level.horizontalHeader().sectionClicked.connect(
            self.sortByIndex)

    def create_table_header(self):
        """Create the QTableView that will hold the header model."""
        self.table_header = QTableView()
        self.table_header.verticalHeader().hide()
        self.table_header.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_header.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_header.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_header.setHorizontalScrollMode(QTableView.ScrollPerPixel)
        self.table_header.setHorizontalScrollBar(self.hscroll)
        self.table_header.setFrameStyle(QFrame.Plain)
        self.table_header.horizontalHeader().sectionResized.connect(
            self._column_resized)
        # self.table_header.setItemDelegate(QItemDelegate())
        self.layout.addWidget(self.table_header, 0, 1)

    def create_table_index(self):
        """Create the QTableView that will hold the index model."""
        self.table_index = QTableView()
        self.table_index.horizontalHeader().hide()
        self.table_index.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_index.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_index.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_index.setVerticalScrollMode(QTableView.ScrollPerPixel)
        self.table_index.setVerticalScrollBar(self.vscroll)
        self.table_index.setFrameStyle(QFrame.Plain)
        self.table_index.verticalHeader().sectionResized.connect(
            self._row_resized)
        # self.table_index.setItemDelegate(QItemDelegate())
        self.layout.addWidget(self.table_index, 1, 0)
        self.table_index.setContentsMargins(0, 0, 0, 0)

    def create_data_table(self):
        """Create the QTableView that will hold the data model."""
        self.dataTable = MxDataTable(self, self.dataModel,
                                     self.table_header.horizontalHeader(),
                                     self.hscroll, self.vscroll)
        self.dataTable.verticalHeader().hide()
        self.dataTable.horizontalHeader().hide()
        self.dataTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.dataTable.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.dataTable.setHorizontalScrollMode(QTableView.ScrollPerPixel)
        self.dataTable.setVerticalScrollMode(QTableView.ScrollPerPixel)
        self.dataTable.setFrameStyle(QFrame.Plain)
        # self.dataTable.setItemDelegate(QItemDelegate())
        self.layout.addWidget(self.dataTable, 1, 1)
        self.setFocusProxy(self.dataTable)
        self.dataTable.sig_sort_by_column.connect(self._sort_update)
        self.dataTable.sig_fetch_more_columns.connect(self._fetch_more_columns)
        self.dataTable.sig_fetch_more_rows.connect(self._fetch_more_rows)

    def sortByIndex(self, index):
        """Implement a Index sort."""
        self.table_level.horizontalHeader().setSortIndicatorShown(True)
        sort_order = self.table_level.horizontalHeader().sortIndicatorOrder()
        self.table_index.model().sort(index, sort_order)
        self._sort_update()

    def model(self):
        """Get the model of the dataframe."""
        return self._model

    def _column_resized(self, col, old_width, new_width):
        """Update the column width."""
        self.dataTable.setColumnWidth(col, new_width)
        self._update_layout()

    def _row_resized(self, row, old_height, new_height):
        """Update the row height."""
        self.dataTable.setRowHeight(row, new_height)
        self._update_layout()

    def _index_resized(self, col, old_width, new_width):
        """Resize the corresponding column of the index section selected."""
        self.table_index.setColumnWidth(col, new_width)
        self._update_layout()

    def _header_resized(self, row, old_height, new_height):
        """Resize the corresponding row of the header section selected."""
        self.table_header.setRowHeight(row, new_height)
        self._update_layout()

    def _update_layout(self):
        """Set the width and height of the QTableViews and hide rows."""
        h_width = max(self.table_level.verticalHeader().sizeHint().width(),
                      self.table_index.verticalHeader().sizeHint().width())
        self.table_level.verticalHeader().setFixedWidth(h_width)
        self.table_index.verticalHeader().setFixedWidth(h_width)

        last_row = self._model.header_shape[0] - 1
        if last_row < 0:
            hdr_height = self.table_level.horizontalHeader().height()
        else:

            # Check if the header shape has only one row (which display the
            # same info than the horizontal header).
            if last_row == 0:
                self.table_level.setRowHidden(0, True)
                self.table_header.setRowHidden(0, True)
            else:
                self.table_level.setRowHidden(0, False)
                self.table_header.setRowHidden(0, False)

            hdr_height = self.table_level.rowViewportPosition(last_row) + \
                         self.table_level.rowHeight(last_row) + \
                         self.table_level.horizontalHeader().height()

        self.table_header.setFixedHeight(hdr_height)
        self.table_level.setFixedHeight(hdr_height)

        last_col = self._model.header_shape[1] - 1
        if last_col < 0:
            idx_width = self.table_level.verticalHeader().width()
        else:
            idx_width = self.table_level.columnViewportPosition(last_col) + \
                        self.table_level.columnWidth(last_col) + \
                        self.table_level.verticalHeader().width()
        self.table_index.setFixedWidth(idx_width)
        self.table_level.setFixedWidth(idx_width)
        self._resizeVisibleColumnsToContents()

    def _reset_model(self, table, model):
        """Set the model in the given table."""
        old_sel_model = table.selectionModel()
        table.setModel(model)
        if old_sel_model:
            del old_sel_model

    def setAutosizeLimit(self, limit_ms):
        """Set maximum size for columns."""
        self._max_autosize_ms = limit_ms

    def setModel(self, model, relayout=True):
        """Set the model for the data, header/index and level views."""
        self._model = model
        # sel_model = self.dataTable.selectionModel()
        # sel_model.currentColumnChanged.connect(
        #     self._resizeCurrentColumnToContents)

        self._reset_model(self.dataTable, model)

        # Asociate the models (level, vertical index and horizontal header)
        # with its corresponding view.
        self._reset_model(
            self.table_level,
            DataFrameLevelModel(model, self.palette(), self.font()))
        self._reset_model(self.table_header,
                          DataFrameHeaderModel(model, 0, self.palette()))
        self._reset_model(self.table_index,
                          DataFrameHeaderModel(model, 1, self.palette()))

        # Needs to be called after setting all table models
        if relayout:
            self._update_layout()

    def setCurrentIndex(self, y, x):
        """Set current selection."""
        self.dataTable.selectionModel().setCurrentIndex(
            self.dataTable.model().index(y, x),
            QItemSelectionModel.ClearAndSelect)

    def _sizeHintForColumn(self, table, col, limit_ms=None):
        """Get the size hint for a given column in a table."""
        max_row = table.model().rowCount()
        lm_start = time.perf_counter()
        lm_row = 64 if limit_ms else max_row
        max_width = 0
        for row in range(max_row):
            v = table.sizeHintForIndex(table.model().index(row, col))
            max_width = max(max_width, v.width())
            if row > lm_row:
                lm_now = time.perf_counter()
                lm_elapsed = (lm_now - lm_start) * 1000
                if lm_elapsed >= limit_ms:
                    break
                lm_row = int((row / lm_elapsed) * limit_ms)
        return max_width

    def _resizeColumnToContents(self, header, data, col, limit_ms):
        """Resize a column by its contents."""
        hdr_width = self._sizeHintForColumn(header, col, limit_ms)
        data_width = self._sizeHintForColumn(data, col, limit_ms)
        if data_width > hdr_width:
            width = min(self.max_width, data_width)
        elif hdr_width > data_width * 2:
            width = max(min(hdr_width, self.min_trunc),
                        min(self.max_width, data_width))
        else:
            width = min(self.max_width, hdr_width)
        header.setColumnWidth(col, width)

    def _resizeColumnsToContents(self, header, data, limit_ms):
        """Resize all the colummns to its contents."""
        max_col = data.model().columnCount()
        if limit_ms is None:
            max_col_ms = None
        else:
            max_col_ms = limit_ms / max(1, max_col)
        for col in range(max_col):
            self._resizeColumnToContents(header, data, col, max_col_ms)

    def eventFilter(self, obj, event):
        """Override eventFilter to catch resize event."""
        if obj == self.dataTable and event.type() == QEvent.Resize:
            self._resizeVisibleColumnsToContents()
        return False

    def _resizeVisibleColumnsToContents(self):
        """Resize the columns that are in the view."""
        index_column = self.dataTable.rect().topLeft().x()
        start = col = self.dataTable.columnAt(index_column)
        width = self._model.shape[1]
        end = self.dataTable.columnAt(self.dataTable.rect().bottomRight().x())
        end = width if end == -1 else end + 1
        if self._max_autosize_ms is None:
            max_col_ms = None
        else:
            max_col_ms = self._max_autosize_ms / max(1, end - start)
        while col < end:
            resized = False
            if col not in self._autosized_cols:
                self._autosized_cols.add(col)
                resized = True
                self._resizeColumnToContents(self.table_header, self.dataTable,
                                             col, max_col_ms)
            col += 1
            if resized:
                # As we resize columns, the boundary will change
                index_column = self.dataTable.rect().bottomRight().x()
                end = self.dataTable.columnAt(index_column)
                end = width if end == -1 else end + 1
                if max_col_ms is not None:
                    max_col_ms = self._max_autosize_ms / max(1, end - start)

    def _resizeCurrentColumnToContents(self, new_index, old_index):
        """Resize the current column to its contents."""
        if new_index.column() not in self._autosized_cols:
            # Ensure the requested column is fully into view after resizing
            self._resizeVisibleColumnsToContents()
            self.dataTable.scrollTo(new_index)

    def resizeColumnsToContents(self):
        """Resize the columns to its contents."""
        self._autosized_cols = set()
        self._resizeColumnsToContents(self.table_level, self.table_index,
                                      self._max_autosize_ms)
        self._update_layout()
        self.table_level.resizeColumnsToContents()

    def change_format(self):
        """
        Ask user for display format for floats and use it.

        This function also checks whether the format is valid and emits
        `sig_option_changed`.
        """
        format, valid = QInputDialog.getText(self, _('Format'),
                                             _("Float formatting"),
                                             QLineEdit.Normal,
                                             self.dataModel.get_format())
        if valid:
            format = str(format)
            try:
                format % 1.1
            except:
                msg = _("Format ({}) is incorrect").format(format)
                QMessageBox.critical(self, _("Error"), msg)
                return
            if not format.startswith('%'):
                msg = _("Format ({}) should start with '%'").format(format)
                QMessageBox.critical(self, _("Error"), msg)
                return
            self.dataModel.set_format(format)
            self.sig_option_changed.emit('dataframe_format', format)

    def get_value(self):
        """Return modified Dataframe -- this is *not* a copy"""
        # It is import to avoid accessing Qt C++ object as it has probably
        # already been destroyed, due to the Qt.WA_DeleteOnClose attribute
        df = self.dataModel.get_data()
        if self.is_series:
            return df.iloc[:, 0]
        else:
            return df

    def _update_header_size(self):
        """Update the column width of the header."""
        column_count = self.table_header.model().columnCount()
        for index in range(0, column_count):
            if index < column_count:
                column_width = self.dataTable.columnWidth(index)
                self.table_header.setColumnWidth(index, column_width)
            else:
                break

    def _sort_update(self):
        """
        Update the model for all the QTableView objects.

        Uses the model of the dataTable as the base.
        """
        self.setModel(self.dataTable.model())

    def _fetch_more_columns(self):
        """Fetch more data for the header (columns)."""
        self.table_header.model().fetch_more()

    def _fetch_more_rows(self):
        """Fetch more data for the index (rows)."""
        self.table_index.model().fetch_more()

    def resize_to_contents(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        self.dataTable.resizeColumnsToContents()
        self.dataModel.fetch_more(columns=True)
        self.dataTable.resizeColumnsToContents()
        self._update_header_size()
        QApplication.restoreOverrideCursor()

    # --- mx specific ---
    def process_remote_view(self, data):

        if data is None:
            data = DataFrame()  # Empty DataFrame

        self.setModel(MxDataModel(data, parent=self))
Пример #11
0
class InterlinearDataWindow(QWidget):

    translation = (
        "Interlinear Data",
        "Enter a reference:",
        "No bible verse reference is found!",
        "Export to Spreadsheet",
        "Close",
    )

    def __init__(self, parent, initialVerse=""):
        super().__init__()
        self.parent = parent
        # set title
        self.setWindowTitle(self.translation[0])
        self.setMinimumSize(830, 500)
        # set variables
        self.setupVariables()
        # setup interface
        self.setupUI(initialVerse)

    def setupVariables(self):
        import os, sqlite3
        # connect bibles.sqlite
        self.database = os.path.join(config.marvelData, "morphology.sqlite")
        self.connection = sqlite3.connect(self.database)
        self.cursor = self.connection.cursor()
        # Spreadsheet headers
        self.headers = ("WordID", "ClauseID", "Book", "Chapter", "Verse",
                        "Word", "LexicalEntry", "MorphologyCode", "Morphology",
                        "Lexeme", "Transliteration", "Pronunciation",
                        "Interlinear", "Translation", "Gloss")

    def __del__(self):
        self.connection.close()

    def setupUI(self, initialVerse=""):
        from qtpy.QtGui import QStandardItemModel
        from qtpy.QtWidgets import (QPushButton, QLabel, QTableView,
                                    QHBoxLayout, QVBoxLayout, QLineEdit)
        #from qtpy.QtWidgets import QAbstractItemView

        mainLayout = QVBoxLayout()

        mainLayout.addWidget(QLabel(self.translation[0]))

        layout = QHBoxLayout()
        layout.addWidget(QLabel(self.translation[1]))
        self.searchEntry = QLineEdit()
        # Set initial entry
        self.searchEntry.setText(initialVerse if initialVerse else "John 3:16")
        self.searchEntry.returnPressed.connect(self.resetItems)
        layout.addWidget(self.searchEntry)
        mainLayout.addLayout(layout)

        self.dataView = QTableView()
        # Allow editing so that users can select text and copy
        #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()
        button = QPushButton(self.translation[4])
        button.clicked.connect(self.close)
        buttonLayout.addWidget(button)
        button = QPushButton(self.translation[3])
        button.clicked.connect(self.exportSpreadsheet)
        buttonLayout.addWidget(button)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

    def resetItems(self):
        from util.BibleVerseParser import BibleVerseParser
        from qtpy.QtGui import QStandardItem

        # Empty the model before reset
        self.dataViewModel.clear()
        # Reset
        # Parse entered reference
        reference = self.searchEntry.text().strip()
        verses = BibleVerseParser(
            config.parserStandarisation).extractAllReferences(
                reference, False)
        if verses:
            # Search morphology database
            bcv = verses[0][0:3]
            query = "SELECT * FROM morphology WHERE Book = ? AND Chapter = ? AND Verse = ?"
            self.cursor.execute(query, bcv)
            self.results = self.cursor.fetchall()
            # Display data
            # TABLE morphology (WordID INT, ClauseID INT, Book INT, Chapter INT, Verse INT, Word TEXT, LexicalEntry TEXT, MorphologyCode TEXT, Morphology TEXT, Lexeme TEXT, Transliteration TEXT, Pronunciation TEXT, Interlinear TEXT, Translation TEXT, Gloss TEXT)
            #for wordID, clauseID, b, c, v, textWord, lexicalEntry, morphologyCode, morphology, lexeme, transliteration, pronuciation, interlinear, translation, gloss in self.results:
            for row, result in enumerate(self.results):
                for column in range(0, len(result)):
                    text = str(
                        result[column]) if column < 5 else result[column]
                    item = QStandardItem(text)
                    self.dataViewModel.setItem(row, column, item)
            self.dataViewModel.setHorizontalHeaderLabels([
                "WordID", "ClauseID", "Book", "Chapter", "Verse", "Word",
                "LexicalEntry", "MorphologyCode", "Morphology", "Lexeme",
                "Transliteration", "Pronunciation", "Interlinear",
                "Translation", "Gloss"
            ])
        else:
            self.results = []
            self.displayMessage(self.translation[2])
        self.dataView.resizeColumnsToContents()

    def displayMessage(self, message):
        from qtpy.QtWidgets import QMessageBox
        QMessageBox.information(self, self.translation[0], message)

    def exportSpreadsheet(self):
        import sys
        from install.module import installmodule

        module = "openpyxl"

        # Check if essential module is installed
        try:
            from openpyxl import Workbook
            moduleInstalled = True
        except:
            moduleInstalled = False

        # Install essential module if it is absent
        if not moduleInstalled:
            installmodule(module)
        if not module in sys.modules:
            try:
                from openpyxl import Workbook
                self.runExportSpreadsheet()
            except:
                #self.displayMessage("Package '{0}' is required but not installed!\nRun 'pip3 install {0}' to install it first.".format(module))
                # openpyxl requires pyton version 3.6+, try alternative 'xlsxwriter'
                self.exportSpreadsheet2()
        else:
            self.runExportSpreadsheet()

    def runExportSpreadsheet(self):
        from openpyxl import Workbook
        from openpyxl.styles import Font

        # Specify excel file path
        #filePath = os.path.join(os.getcwd(), "plugins", "menu", "Interlinear_Data.xlsx")
        filePath = self.getFilePath()
        if filePath:

            # Documentation on openpyxl: https://openpyxl.readthedocs.io/en/stable/
            wb = Workbook()
            # grab the active worksheet
            ws = wb.active
            ws.title = "UniqueBible.app"
            # Append rows
            ws.append(self.headers)
            font = Font(bold=True)
            for i in range(0, len(self.headers)):
                # row and column number starts from 1 when calling ws.cell
                ws.cell(row=1, column=i + 1).font = font
            if self.results:
                for result in self.results:
                    ws.append(result)
                # Apply style
                # Documentation: https://openpyxl.readthedocs.io/en/stable/styles.html
                font = Font(
                    name="Calibri") if self.results[0][2] >= 40 else Font(
                        name="Ezra SIL")
                for column in ("F", "J"):
                    for row in range(0, len(self.results)):
                        ws["{0}{1}".format(column, row + 2)].font = font
                font = Font(name="Calibri")
                for column in ("K", "L"):
                    for row in range(0, len(self.results)):
                        ws["{0}{1}".format(column, row + 2)].font = font

            # Save and open the file
            wb.save(filePath)
            self.openFile(filePath)

    # Use 'xlsxwriter' to export excel file if 'openpyxl' is not installed.
    def exportSpreadsheet2(self):
        import sys
        from install.module import installmodule

        module = "xlsxwriter"

        # Check if essential module is installed
        try:
            import xlsxwriter
            moduleInstalled = True
        except:
            moduleInstalled = False

        # Install essential module if it is absent
        if not moduleInstalled:
            installmodule(module)
        if not module in sys.modules:
            try:
                import xlsxwriter
                self.runExportSpreadsheet2()
            except:
                #self.displayMessage("Package '{0}' is required but not installed!\nRun 'pip3 install {0}' to install it first.".format(module))
                self.exportSpreadsheet3()
        else:
            self.runExportSpreadsheet2()

    def runExportSpreadsheet2(self):
        import xlsxwriter

        # Specify excel file path
        #filePath = os.path.join(os.getcwd(), "plugins", "menu", "Interlinear_Data.xlsx")
        filePath = self.getFilePath()
        if filePath:

            # Create an new Excel file and add a worksheet.
            # Documentation on xlsxwriter: https://pypi.org/project/XlsxWriter/
            workbook = xlsxwriter.Workbook(filePath)
            worksheet = workbook.add_worksheet("UniqueBible.app")

            # Add formats to cells.
            bold = workbook.add_format({'bold': True})
            format_right_to_left = workbook.add_format({'reading_order': 2})

            # Text with formatting.
            for index, header in enumerate(self.headers):
                worksheet.write(0, index, header, bold)

            if self.results:
                for row, result in enumerate(self.results):
                    for column, item in enumerate(result):
                        if column in (5, 9) and self.results[0][2] < 40:
                            worksheet.write(row + 1, column, item,
                                            format_right_to_left)
                        else:
                            worksheet.write(row + 1, column, item)

            workbook.close()

            # Open the saved file
            self.openFile(filePath)

    # export to csv when users cannot install either openpyxl or xlsxwriter for some reasons
    def exportSpreadsheet3(self):
        # Define a file path
        #filePath = os.path.join(os.getcwd(), "plugins", "menu", "Interlinear_Data.csv")
        filePath = self.getFilePath("csv")
        if filePath:

            # Format data
            fileContent = '"{0}"'.format('","'.join(self.headers))
            if self.results:
                for result in self.results:
                    row = [
                        str(item) if index < 5 else item
                        for index, item in enumerate(result)
                    ]
                    fileContent += '\n"{0}"'.format('","'.join(row))
            # Write data into file
            with open(filePath, "w") as fileObj:
                fileObj.write(fileContent)
            self.openFile(filePath)

    def getFilePath(self, fileExtension="xlsx"):
        from qtpy.QtWidgets import QFileDialog

        defaultName = "Interlinear_Data.{0}".format(fileExtension)
        options = QFileDialog.Options()
        filePath, *_ = QFileDialog.getSaveFileName(
            self, config.thisTranslation["note_saveAs"], defaultName,
            "Spreadsheet File (*.{0})".format(fileExtension), "", options)
        if filePath:
            filePath = filePath.replace(" ", "_")
            if not filePath.endswith(".{0}".format(fileExtension)):
                filePath = "{0}.{1}".format(filePath, fileExtension)
            return filePath
        else:
            return ""

    def openFile(self, filePath):
        import platform, subprocess, os

        if platform.system() == "Linux":
            subprocess.Popen([config.open, filePath])
        elif platform.system() == "Windows":
            try:
                subprocess("excel.exe {0}".format(filePath), shell=True)
            except:
                try:
                    subprocess("start {0}".format(filePath), shell=True)
                except:
                    pass
        else:
            os.system("{0} {1}".format(config.open, filePath))
Пример #12
0
class EditGuiLanguageFileDialog(QDialog):
    def __init__(self, parent, language):
        super(EditGuiLanguageFileDialog, self).__init__()

        self.parent = parent
        self.language = language
        self.reference = LanguageUtil.loadTranslation(
            config.referenceTranslation)
        targetLanguage = LanguageUtil.loadTranslation(language)
        self.languages = []
        self.toolTips = []
        # Cannot use the following two lines directly because target language file and reference file are most likely in different order
        #self.languages = [(key, value.replace("\n", "\\n")) for key, value in targetLanguage.items()]
        #self.toolTips = [(value.replace("\n", "\\n"), value.replace("\n", "\\n")) for value in self.reference.values()]
        for key in self.reference:
            if key in targetLanguage:
                self.languages.append(
                    [key, targetLanguage[key].replace("\n", "\\n")])
                self.toolTips.append([
                    self.reference[key].replace("\n", "\\n"),
                    self.reference[key].replace("\n", "\\n")
                ])

        self.setWindowTitle("Edit GUI Language File")
        self.setMinimumWidth(1000)
        self.setMinimumHeight(600)
        self.layout = QVBoxLayout()

        row = QHBoxLayout()
        self.filterEntry1 = QLineEdit()
        self.filterEntry1.textChanged.connect(self.filterChanged1)
        row.addWidget(self.filterEntry1)
        self.filterEntry2 = QLineEdit()
        self.filterEntry2.textChanged.connect(self.filterChanged2)
        row.addWidget(self.filterEntry2)
        self.layout.addLayout(row)

        self.table = QTableView()
        self.model = DisplayLanguagesModel(self, self.languages, self.toolTips)
        self.table.setModel(self.model)
        self.table.resizeColumnsToContents()
        self.table.setSortingEnabled(True)
        self.table.doubleClicked.connect(self.clickedRow)
        self.layout.addWidget(self.table)

        buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(buttons)
        self.buttonBox.accepted.connect(self.save)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.layout.addWidget(self.buttonBox)
        self.setLayout(self.layout)

    def clickedRow(self, index):
        row = self.model.getRow(index.row())
        (key, value) = row
        width = len(value)
        keyDisplay = key + '\n\n' + self.reference[key] + "\n"
        newValue, ok = QInputDialog.getText(self, 'Translation', keyDisplay,
                                            QLineEdit.Normal, value)
        if ok:
            self.model.list[index.row()] = (key, newValue)
            for item in self.model.fullList:
                if item[0] == key:
                    item[1] = newValue
                    break

    def save(self):
        LanguageUtil.saveLanguageFile(self.language, self.model.fullList)
        if self.language == config.displayLanguage:
            if self.parent is not None:
                for item in self.model.fullList:
                    key = item[0]
                    newValue = item[1]
                    config.thisTranslation[key] = newValue
                self.parent.setupMenuLayout(config.menuLayout)
                self.parent.reloadControlPanel(False)

    def filterChanged1(self, text):
        self.model.filter(0, text)
        self.filterEntry2.setText("")

    def filterChanged2(self, text):
        self.model.filter(1, text)
        self.filterEntry1.setText("")
Пример #13
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, name = '', isMD=False, noExp = 0):
        super(SampleLogsView, self).__init__(parent)

        self.presenter = presenter

        self.setWindowTitle("{} sample logs".format(name))
        self.setWindowFlags(Qt.Window)

        # Create sample log table
        self.table = QTableView()
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.clicked.connect(self.presenter.clicked)
        self.table.doubleClicked.connect(self.presenter.doubleClicked)
        self.table.contextMenuEvent = self.tableMenu
        self.addWidget(self.table)

        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)

        self.full_time = QCheckBox("Relative Time")
        self.full_time.setChecked(True)
        self.full_time.stateChanged.connect(self.presenter.plot_logs)
        layout_options.addWidget(self.full_time)
        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('Mean:', self.stats_widgets["mean"])
        layout_stats.addRow('Median:', self.stats_widgets["median"])
        layout_stats.addRow('Std Dev:', self.stats_widgets["standard_deviation"])
        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('Duration:', self.stats_widgets["duration"])
        layout_right.addLayout(layout_stats)
        frame_right.setLayout(layout_right)

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

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

    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)

    def plot_selected_logs(self, ws, exp, rows):
        """Update the plot with the selected rows"""
        self.ax.clear()
        self.create_ax_by_rows(self.ax, ws, exp, rows)
        self.fig.canvas.draw()

    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,
                    marker='.',
                    FullTime=not self.full_time.isChecked(),
                    ExperimentInfo=exp)

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

    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()
Пример #14
0
class ConfigManagerWindow(SiriusMainWindow):
    """Window to manage offline configuration of BO and SI devices.

    This window allows the user to create new configurations as well as
    interpolate or apply a tune or chromaticity delta to a configuration.
    """

    NEW_CONFIGURATION = 0

    def __init__(self, config_type, parent=None):
        """Init UI."""
        super(ConfigManagerWindow, self).__init__(parent)

        self._config_type = config_type
        self._model = ConfigModel(self._config_type)
        self._delegate = ConfigDelegate()

        self._setup_ui()

        self.ld_cur_state_btn.clicked.connect(self._loadCurrentConfiguration)
        self.ld_config_btn.clicked.connect(self._addConfiguration)
        self.delete_config_btn.clicked.connect(self._removeConfiguration)

        self.setGeometry(100, 100, 1600, 900)
        self.setWindowTitle("Configuration Manager")
        self.show()

    def _setup_ui(self):
        self.central_widget = QWidget()
        self.central_widget.layout = QHBoxLayout()

        self.button_box = QVBoxLayout()
        self.ld_cur_state_btn = QPushButton("Load Current State")
        self.ld_config_btn = QPushButton("Load Configuration")
        self.ld_config_btn.setShortcut(QKeySequence.New)
        self.delete_config_btn = QPushButton("Delete Configuration")
        self.button_box.addWidget(self.delete_config_btn)
        self.button_box.addWidget(self.ld_config_btn)
        self.button_box.addWidget(self.ld_cur_state_btn)
        self.button_box.addStretch()

        # TableView
        self.table = QTableView(self)
        self.table.setModel(self._model)
        self.table.setItemDelegate(self._delegate)
        # self.table.setSelectionBehavior(QAbstractItemView.SelectColumns)
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self._showHeaderMenu)
        self.table.resizeColumnsToContents()
        self.table.resizeRowsToContents()

        # TableView Headers
        self.headers = self.table.horizontalHeader()
        self.headers.setContextMenuPolicy(Qt.CustomContextMenu)
        self.headers.customContextMenuRequested.connect(self._showHeaderMenu)

        self.central_widget.layout.addLayout(self.button_box)
        self.central_widget.layout.addWidget(self.table)
        self.central_widget.setLayout(self.central_widget.layout)

        # Set widget
        self.setCentralWidget(self.central_widget)

    def closeEvent(self, event):
        """Close window.

        The user is warned if there are any unsaved changes.
        """
        columns = list(range(len(self._model.configurations)))
        columns.sort(reverse=True)
        if not self._closeConfigurations(columns):
            event.ignore()

    def keyPressEvent(self, event):
        """Override keyPressEvent.

        Ctrl+S - Save changes
        Ctrl+W - Close configuration on focus
        F2 - Rename configuration on focus
        Ctrl+Z - Undo
        Ctrl+R - Redo
        """
        if event.key() == Qt.Key_S:
            self._saveChanges()
            return
        if event.key() == Qt.Key_W:
            self._closeConfigurationOnFocus()
            return
        if event.key() == Qt.Key_F2:
            self._renameOnFocus()
            return
        if event.key() == Qt.Key_Z:
            print(self._model._undo)
            if len(self._model._undo) > 0:
                self._model._undo.pop()[1]()
            return
        if event.key() == Qt.Key_R:
            if len(self._model._redo) > 0:
                self._model._redo.pop()[1]()
            return

    @Slot(QPoint)
    def _showHeaderMenu(self, point):
        column = self.headers.logicalIndexAt(point.x())
        if column == -1:
            return
        menu = QMenu(self)
        # Actions
        cols = self.table.selectionModel().selectedColumns()
        if len(cols) != 2 or column not in [col.column() for col in cols]:
            self.table.selectColumn(column)
            menu.aboutToHide.connect(lambda: self.table.clearSelection())

            save = QAction("Save", menu)
            save.triggered.connect(lambda: self._saveConfiguration(column))
            save_all = QAction("Save all", menu)
            save_all.triggered.connect(lambda: self._saveChanges())
            save_all.setShortcut(QKeySequence.Save)
            rename = QAction("Rename", menu)
            rename.triggered.connect(lambda: self._renameConfiguration(column))
            close = QAction("Close", menu)
            close.triggered.connect(lambda: self._closeConfiguration(column))
            close.setShortcut(QKeySequence.Close)
            close_right = QAction("Close to the right", menu)
            close_right.triggered.connect(
                lambda: self._closeConfigurationsToTheRight(column))
            close_others = QAction("Close other", menu)
            close_others.triggered.connect(
                lambda: self._closeOtherConfigurations(column))
            close_all = QAction("Close all", menu)
            close_all.triggered.connect(lambda: self._closeAllConfigurations())
            tune = QAction("Tune", menu)
            tune.triggered.connect(lambda: self._tuneConfiguration(column))

            menu.addActions([save, save_all])
            menu.addSeparator()
            menu.addActions([rename])
            menu.addSeparator()
            menu.addActions([close, close_right, close_others, close_all])
            menu.addSeparator()
            menu.addActions([tune])
        else:
            bar = QAction("Interpolate", menu)
            bar.triggered.connect(lambda: self._barConfiguration(cols))

            menu.addAction(bar)

        vheader_offset = self.table.verticalHeader().width()
        point.setX(point.x() + vheader_offset)
        menu.popup(self.mapToGlobal(point))

    # ContextMenu Actions
    @Slot(int)
    def _saveConfiguration(self, column):
        try:
            self._model.saveConfiguration(column)
            return True
        except Exception as e:
            QMessageBox(QMessageBox.Warning, "Failed to save data",
                        "{}, {}".format(e, type(e))).exec_()
        return False

    @Slot(int)
    def _renameConfiguration(self, column):
        new_name, ok = QInputDialog.getText(self, "New name", "Rename to:")
        if ok and new_name:
            return self._model.renameConfiguration(column, new_name)

    @Slot(int)
    def _closeConfiguration(self, column):
        self._closeConfigurations([column])

    @Slot(int)
    def _closeConfigurationsToTheRight(self, column):
        columns = list()
        i = len(self._model.configurations) - 1
        while i > column:
            columns.append(i)
            i -= 1

        self._closeConfigurations(columns)

    @Slot(int)
    def _closeOtherConfigurations(self, column):
        columns = list()
        i = len(self._model.configurations) - 1
        while i >= 0:
            if i == column:
                i -= 1
                continue
            columns.append(i)
            i -= 1

        self._closeConfigurations(columns)

    @Slot()
    def _closeAllConfigurations(self):
        columns = list()
        i = len(self._model.configurations) - 1
        while i >= 0:
            columns.append(i)
            i -= 1

        self._closeConfigurations(columns)

    def _closeConfigurations(self, columns):
        save = self._maybeSaveChanges(columns)

        if save == QMessageBox.Discard:
            for column in columns:
                self._model.cleanUndo(column)
                self._model.closeConfiguration(column)
            return True
        elif save == QMessageBox.Save:
            for column in columns:
                if self._saveConfiguration(column):
                    self._model.cleanUndo(column)
                    self._model.closeConfiguration(column)
                else:
                    return False
            return True
        else:
            return False

    @Slot(int)
    def _tuneConfiguration(self, column):
        dlg = TuneDlg(self)
        ok1 = dlg.exec_()
        if ok1:
            # Get Matrix Calculate deltaK and show to user
            tune = [dlg.tune_x.value(), dlg.tune_y.value()]
            try:
                inv_matrix = self._model.getTuneMatrix()
            except Exception as e:
                self._showWarningBox("{}".format(e),
                                     "Failed to retrieve tune matrix")
            else:
                delta_f = tune[0] * inv_matrix[0][0] + tune[1] * inv_matrix[0][
                    1]
                delta_d = tune[0] * inv_matrix[1][0] + tune[1] * inv_matrix[1][
                    1]
                # config_name, ok2 = QInputDialog.getText(
                #   self, "Select value", "New Configuration Name:")
                # if ok2:
                #    if not config_name:
                proceed = QMessageBox(QMessageBox.Question, "Delta K",
                                      ("\u0394K<sub>d</sub> = {:1.3f}<br>"
                                       "\u0394K<sub>f</sub> = {:1.3f}<br>"
                                       "Proceed?").format(delta_d, delta_f),
                                      QMessageBox.Ok | QMessageBox.Cancel,
                                      self).exec_()
                if proceed == QMessageBox.Ok:
                    config_name = self._getNextName()
                    self._model.deriveConfiguration(config_name, column,
                                                    ConfigModel.TUNE,
                                                    [delta_d, delta_f])

    @Slot(int)
    def _barConfiguration(self, cols):
        if len(cols) != 2:
            raise SystemError("Must interpolate 2 columns")
        new_name, ok = QInputDialog.getText(self, "New name", "Rename to:")
        if ok:
            if not new_name:
                new_name = self._getNextName()

            self._model.interpolateConfiguration(new_name, cols[0].column(),
                                                 cols[1].column())

    # Window menu slots
    @Slot()
    def _addConfiguration(self):
        try:
            configs = self._model.getConfigurations()
        except Exception as e:
            self._showWarningBox(e, "Failed to retrieve configurations")
        else:
            if configs:
                options = [item["name"] for item in configs]
                config_name, ok = QInputDialog.getItem(
                    self, "Available Configurations",
                    "Select a configuration:", options, 0, False)
                if ok and config_name:
                    if not self._isConfigurationLoaded(config_name):
                        self._model.loadConfiguration(name=config_name)
                    else:
                        QMessageBox(
                            QMessageBox.Information,
                            "Configuration already loaded",
                            "Configuration is already loaded.").exec_()
                    # Highlight new column; or the one that is already loaded
                    col = self._model.getConfigurationColumn(config_name)
                    self.table.selectColumn(col)
            else:
                self._showMessageBox("No configuration found")
        return

    @Slot()
    def _removeConfiguration(self):
        try:
            configs = self._model.getConfigurations()
        except Exception as e:
            self._showWarningBox(e, "Failed to retrieve configurations")
        else:
            if configs:
                # Show configs available
                options = [item["name"] for item in configs]
                config, ok = QInputDialog.getItem(self,
                                                  "Available Configurations",
                                                  "Select a configuration:",
                                                  options, 0, False)
                if ok and config:
                    # Ask for confirmation
                    if self._isConfigurationLoaded(config):
                        msg = ("Configuration is currenty loaded."
                               "Delete it anyway?")
                    else:
                        msg = ("This will permanently delete configuration {}."
                               "Proceed?").format(config)

                    if self._showDialogBox(msg) == QMessageBox.Cancel:
                        return
                    # Delete configuration
                    config = configs[options.index(config)]
                    try:
                        self._model.deleteConfiguration(config)
                    except Exception as e:
                        self._showWarningBox(e)
                    else:
                        self._showMessageBox(
                            "Configuration {} was deleted.".format(
                                config['name']))
            else:
                self._showMessageBox("No configuration found")
        return

    @Slot()
    def _loadCurrentConfiguration(self):
        try:
            t = LoadingThread(self._getNextName(),
                              self._model._vertical_header, self)
            dlg = \
                LoadingDialog("Loading", len(self._model._vertical_header), self)
            t.taskUpdated.connect(dlg.update)
            t.taskFinished.connect(dlg.done)
            t.start()
            dlg.exec_()
        except Exception as e:
            self._showWarningBox("{}".format(e))

    # Actions binded with keys
    def _saveChanges(self):
        for column in range(len(self._model.configurations)):
            self._saveConfiguration(column)

    def _closeConfigurationOnFocus(self):
        cols = self.table.selectionModel().selectedColumns()
        columns = list()
        for col in cols:
            columns.append(col.column())
        columns.sort(reverse=True)
        self._closeConfigurations(columns)

    def _renameOnFocus(self):
        cols = self.table.selectionModel().selectedColumns()
        if len(cols) == 1:
            self._renameConfiguration(cols[0].column())

    # Helpers
    def _isConfigurationLoaded(self, config_name):
        ret = self._model.getConfigurationColumn(config_name)

        if ret == -1:
            return False

        return True

    def _getNextName(self):
        # Treat if there already exist saved configuration with this name
        configs = self._model.getConfigurations(deleted=None)
        configs = [item["name"] for item in configs]
        configs.extend([item.name for item in self._model.configurations])
        new_name = 'config-{}'.format(self.NEW_CONFIGURATION)
        while new_name in configs:
            self.NEW_CONFIGURATION += 1
            new_name = 'config-{}'.format(self.NEW_CONFIGURATION)
        return new_name

    def _maybeSaveChanges(self, columns):
        ask_to_save = False
        for column in columns:
            if self._model.configurations[column].dirty:
                ask_to_save = True
                break
        # If nothing to save, will close all columns
        if not ask_to_save:
            return QMessageBox.Discard
        # Ask if user wants to save changes
        msg_box = QMessageBox(
            QMessageBox.Question, "There are unsaved changes", "Keep changes?",
            QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard, self)

        return msg_box.exec_()

    def _showWarningBox(self, message, title="Warning"):
        QMessageBox(QMessageBox.Warning, title, '{}'.format(message)).exec_()

    def _showMessageBox(self, message, title="Message"):
        return QMessageBox(QMessageBox.Information, title, message).exec_()

    def _showDialogBox(self, message, title="Dialog"):
        return QMessageBox(QMessageBox.Information, title, message,
                           QMessageBox.Ok | QMessageBox.Cancel).exec_()
Пример #15
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()
Пример #16
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, name = '', isMD=False, noExp = 0):
        super(SampleLogsView, self).__init__(parent)

        self.presenter = presenter

        self.setWindowTitle("{} sample logs".format(name))
        self.setWindowFlags(Qt.Window)
        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 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()
Пример #17
0
class LiveFilterDialog(QDialog):

    JS_HIDE = """
            count = 0;
            searchResultCount = document.getElementById("searchResultCount");
            divs = document.querySelectorAll("div");
            for (var i = 0, len = divs.length; i < len; i++) {{
                div = divs[i];
                div.hidden = {0};
                count++;
            }};
            if (searchResultCount) {{
                searchResultCount.innerHTML = count;
            }}
            """

    JS_SHOW = """
            wordSets = [{0}];
            count = 0;
            searchResultCount = document.getElementById("searchResultCount");
            divs = document.querySelectorAll("div");
            for (var i=0, len=divs.length; i < len; i++) {{
                div = divs[i];
                var found = true;
                for (var j=0, len2=wordSets.length; j < len2; j++) {{
                    wordSet = wordSets[j];
                    var regex;
                    if (wordSet.startsWith("'")) {{
                        wordSet = wordSet.replace("'", "");
                        wordSet = wordSet.replace("'", "");
                        regex = new RegExp(wordSet);
                    }} else {{
                        regex = new RegExp(wordSet, "i");
                    }}
                    found &= regex.test(div.innerHTML);
                }}
                if (found) {{
                    div.hidden = false;
                    count++;
                }}
            }};
            if (searchResultCount) {{
                searchResultCount.innerHTML = count;
            }}
            """

    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.setWindowTitle(config.thisTranslation["liveFilter"])
        self.setMinimumSize(400, 400)
        self.selectedFilter = None
        self.selectedPattern = None
        self.settingBibles = False
        self.db = LiveFilterSqlite()
        self.filters = None
        self.saveReadFormattedBibles = config.readFormattedBibles
        if config.readFormattedBibles:
            self.parent.disableBiblesInParagraphs()
        self.setupUI()

    def setupUI(self):
        mainLayout = QVBoxLayout()

        title = QLabel(config.thisTranslation["liveFilter"])
        mainLayout.addWidget(title)

        self.filtersTable = QTableView()
        self.filtersTable.setEnabled(True)
        self.filtersTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.filtersTable.setSortingEnabled(True)
        self.dataViewModel = QStandardItemModel(self.filtersTable)
        self.filtersTable.setModel(self.dataViewModel)
        self.dataViewModel.itemChanged.connect(self.filterSelectionChanged)
        self.selectionModel = self.filtersTable.selectionModel()
        self.selectionModel.selectionChanged.connect(self.handleSelection)
        mainLayout.addWidget(self.filtersTable)
        self.reloadFilters()

        buttonsLayout = QHBoxLayout()
        addButton = QPushButton(config.thisTranslation["add"])
        addButton.clicked.connect(self.addNewFilter)
        buttonsLayout.addWidget(addButton)
        removeButton = QPushButton(config.thisTranslation["remove"])
        removeButton.clicked.connect(self.removeFilter)
        buttonsLayout.addWidget(removeButton)
        editButton = QPushButton(config.thisTranslation["edit"])
        editButton.clicked.connect(self.editFilter)
        buttonsLayout.addWidget(editButton)
        importButton = QPushButton(config.thisTranslation["import"])
        importButton.clicked.connect(self.importFile)
        buttonsLayout.addWidget(importButton)
        buttonsLayout.addStretch()
        mainLayout.addLayout(buttonsLayout)

        buttons = QDialogButtonBox.Ok
        self.buttonBox = QDialogButtonBox(buttons)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.accepted.connect(self.close)
        self.buttonBox.rejected.connect(self.reject)
        mainLayout.addWidget(self.buttonBox)

        self.setLayout(mainLayout)

    def close(self):
        pass

    def reloadFilters(self):
        self.filters = self.db.getAll()
        self.dataViewModel.clear()
        rowCount = 0
        for bible, description in self.filters:
            item = QStandardItem(bible)
            item.setToolTip(bible)
            item.setCheckable(True)
            self.dataViewModel.setItem(rowCount, 0, item)
            item = QStandardItem(description)
            self.dataViewModel.setItem(rowCount, 1, item)
            rowCount += 1
        self.dataViewModel.setHorizontalHeaderLabels([
            config.thisTranslation["filter2"],
            config.thisTranslation["pattern"]
        ])
        self.filtersTable.resizeColumnsToContents()

    def handleSelection(self, selected, deselected):
        for item in selected:
            row = item.indexes()[0].row()
            filter = self.dataViewModel.item(row, 0)
            self.selectedFilter = filter.text()
            pattern = self.dataViewModel.item(row, 1)
            self.selectedPattern = pattern.text()

    def filterSelectionChanged(self, item):
        try:
            numChecked = 0
            for index in range(self.dataViewModel.rowCount()):
                item = self.dataViewModel.item(index)
                if item.checkState() == Qt.Checked:
                    numChecked += 1
            if numChecked == 0:
                config.mainWindow.studyPage.runJavaScript(
                    self.JS_HIDE.format("false"))
            else:
                sets = []
                config.mainWindow.studyPage.runJavaScript(
                    self.JS_HIDE.format("true"))
                for index in range(self.dataViewModel.rowCount()):
                    item = self.dataViewModel.item(index)
                    if item.checkState() == Qt.Checked:
                        sets.append('"{0}"'.format(self.filters[index][1]))
                wordSets = ",".join(sets)
                js = self.JS_SHOW.format(wordSets)
                config.mainWindow.studyPage.runJavaScript(js)
        except Exception as e:
            print(str(e))

    def addNewFilter(self):
        fields = [(config.thisTranslation["filter2"], ""),
                  (config.thisTranslation["pattern"], "")]
        dialog = MultiLineInputDialog("New Filter", fields)
        if dialog.exec():
            data = dialog.getInputs()
            self.db.insert(data[0], data[1])
            self.reloadFilters()

    def removeFilter(self):
        reply = QMessageBox.question(
            self, "Delete",
            'Delete {0} {1}'.format(self.selectedFilter,
                                    config.thisTranslation["filter2"]),
            QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.db.delete(self.selectedFilter)
            self.reloadFilters()

    def editFilter(self):
        fields = [(config.thisTranslation["filter2"], self.selectedFilter),
                  (config.thisTranslation["pattern"], self.selectedPattern)]
        dialog = MultiLineInputDialog("Edit Filter", fields)
        if dialog.exec():
            data = dialog.getInputs()
            self.db.delete(self.selectedFilter)
            self.db.insert(data[0], data[1])
            self.reloadFilters()

    def importFile(self):
        options = QFileDialog.Options()
        filename, filtr = QFileDialog.getOpenFileName(
            self, config.thisTranslation["import"],
            config.thisTranslation["liveFilter"], "File (*.*)", "", options)
        if filename:
            try:
                with open(filename, errors='ignore') as f:
                    for line in f:
                        data = line.split(":::")
                        filter = data[0].strip()
                        pattern = data[1].strip()
                        if self.db.checkFilterExists(filter):
                            self.db.delete(filter)
                        self.db.insert(filter, pattern)
            except Exception as e:
                print(e)
            self.reloadFilters()
Пример #18
0
class ConfigFlagsWindow(QDialog):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        # set title
        self.setWindowTitle(config.thisTranslation["menu_config_flags"])
        self.setMinimumSize(830, 500)
        # set variables
        self.setupVariables()
        # setup interface
        self.setupUI()

    def setupVariables(self):
        self.isUpdating = False

    def setupUI(self):
        mainLayout = QVBoxLayout()

        title = QLabel(config.thisTranslation["menu_config_flags"])
        title.mouseReleaseEvent = self.openWiki
        mainLayout.addWidget(title)

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

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

        buttonLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["close"])
        button.clicked.connect(self.close)
        buttonLayout.addWidget(button)
        button = QPushButton(config.thisTranslation["restoreAllDefaults"])
        button.clicked.connect(self.restoreAllDefaults)
        buttonLayout.addWidget(button)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

    def getOptions(self):
        options = [
            ("showControlPanelOnStartup", config.showControlPanelOnStartup,
             self.showControlPanelOnStartupChanged, False,
             config.thisTranslation["showControlPanelOnStartup"]),
            ("preferControlPanelForCommandLineEntry",
             config.preferControlPanelForCommandLineEntry,
             self.preferControlPanelForCommandLineEntryChanged, False,
             config.thisTranslation["preferControlPanelForCommandLineEntry"]),
            ("closeControlPanelAfterRunningCommand",
             config.closeControlPanelAfterRunningCommand,
             self.closeControlPanelAfterRunningCommandChanged, True,
             config.thisTranslation["closeControlPanelAfterRunningCommand"]),
            ("restrictControlPanelWidth", config.restrictControlPanelWidth,
             self.restrictControlPanelWidthChanged, False,
             config.thisTranslation["restrictControlPanelWidth"]),
            ("clearCommandEntry", config.clearCommandEntry,
             self.clearCommandEntryChanged, False,
             config.thisTranslation["clearCommandEntry"]),
            ("openBibleWindowContentOnNextTab",
             config.openBibleWindowContentOnNextTab,
             self.openBibleWindowContentOnNextTabChanged, False,
             config.thisTranslation["openBibleWindowContentOnNextTab"]),
            ("openStudyWindowContentOnNextTab",
             config.openStudyWindowContentOnNextTab,
             self.openStudyWindowContentOnNextTabChanged, True,
             config.thisTranslation["openStudyWindowContentOnNextTab"]),
            ("populateTabsOnStartup", config.populateTabsOnStartup,
             self.populateTabsOnStartupChanged, False,
             config.thisTranslation["populateTabsOnStartup"]),
            ("qtMaterial", config.qtMaterial, self.qtMaterialChanged, False,
             config.thisTranslation["qtMaterial"]),
            ("addBreakAfterTheFirstToolBar",
             config.addBreakAfterTheFirstToolBar,
             self.addBreakAfterTheFirstToolBarChanged, True,
             config.thisTranslation["addBreakAfterTheFirstToolBar"]),
            ("addBreakBeforeTheLastToolBar",
             config.addBreakBeforeTheLastToolBar,
             self.addBreakBeforeTheLastToolBarChanged, False,
             config.thisTranslation["addBreakBeforeTheLastToolBar"]),
            ("parserStandarisation", (config.parserStandarisation == "YES"),
             self.parserStandarisationChanged, False,
             config.thisTranslation["parserStandarisation"]),
            ("useLiteVerseParsing", config.useLiteVerseParsing,
             self.useLiteVerseParsingChanged, False,
             config.thisTranslation["useLiteVerseParsing"]),
            ("parseEnglishBooksOnly", config.parseEnglishBooksOnly,
             self.parseEnglishBooksOnlyChanged, False,
             config.thisTranslation["parseEnglishBooksOnly"]),
            ("parseWordDocument", config.parseWordDocument,
             self.parseWordDocumentChanged, True,
             config.thisTranslation["parseWordDocument"]),
            ("convertChapterVerseDotSeparator",
             config.convertChapterVerseDotSeparator,
             self.convertChapterVerseDotSeparatorChanged, True,
             config.thisTranslation["convertChapterVerseDotSeparator"]),
            ("parseBookChapterWithoutSpace",
             config.parseBookChapterWithoutSpace,
             self.parseBookChapterWithoutSpaceChanged, True,
             config.thisTranslation["parseBookChapterWithoutSpace"]),
            ("parseBooklessReferences", config.parseBooklessReferences,
             self.parseBooklessReferencesChanged, True,
             config.thisTranslation["parseBooklessReferences"]),
            ("searchBibleIfCommandNotFound",
             config.searchBibleIfCommandNotFound,
             self.searchBibleIfCommandNotFoundChanged, True,
             config.thisTranslation["searchBibleIfCommandNotFound"]),
            ("regexSearchBibleIfCommandNotFound",
             config.regexSearchBibleIfCommandNotFound,
             self.regexSearchBibleIfCommandNotFoundChanged, False,
             config.thisTranslation["regexSearchBibleIfCommandNotFound"]),
            ("preferHtmlMenu", config.preferHtmlMenu,
             self.preferHtmlMenuChanged, False,
             config.thisTranslation["preferHtmlMenu"]),
            ("showVerseNumbersInRange", config.showVerseNumbersInRange,
             self.showVerseNumbersInRangeChanged, True,
             config.thisTranslation["showVerseNumbersInRange"]),
            ("addFavouriteToMultiRef", config.addFavouriteToMultiRef,
             self.addFavouriteToMultiRefChanged, False,
             config.thisTranslation["addFavouriteToMultiRef"]),
            ("enableVerseHighlighting", config.enableVerseHighlighting,
             self.enableVerseHighlightingChanged, True,
             config.thisTranslation["enableVerseHighlighting"]),
            ("regexCaseSensitive", config.regexCaseSensitive,
             self.regexCaseSensitiveChanged, False,
             config.thisTranslation["regexCaseSensitive"]),
            ("alwaysDisplayStaticMaps", config.alwaysDisplayStaticMaps,
             self.alwaysDisplayStaticMapsChanged, False,
             config.thisTranslation["alwaysDisplayStaticMaps"]),
            ("exportEmbeddedImages", config.exportEmbeddedImages,
             self.exportEmbeddedImagesChanged, True,
             config.thisTranslation["exportEmbeddedImages"]),
            ("clickToOpenImage", config.clickToOpenImage,
             self.clickToOpenImageChanged, True,
             config.thisTranslation["clickToOpenImage"]),
            ("showNoteIndicatorOnBibleChapter",
             config.showNoteIndicatorOnBibleChapter,
             self.parent.enableNoteIndicatorButtonClicked, True,
             config.thisTranslation["showNoteIndicatorOnBibleChapter"]),
            ("openBibleNoteAfterSave", config.openBibleNoteAfterSave,
             self.openBibleNoteAfterSaveChanged, False,
             config.thisTranslation["openBibleNoteAfterSave"]),
            ("openBibleNoteAfterEditorClosed",
             config.openBibleNoteAfterEditorClosed,
             self.openBibleNoteAfterEditorClosedChanged, False,
             config.thisTranslation["openBibleNoteAfterEditorClosed"]),
            ("hideNoteEditorStyleToolbar", config.hideNoteEditorStyleToolbar,
             self.hideNoteEditorStyleToolbarChanged, False,
             config.thisTranslation["hideNoteEditorStyleToolbar"]),
            ("hideNoteEditorTextUtility", config.hideNoteEditorTextUtility,
             self.hideNoteEditorTextUtilityChanged, True,
             config.thisTranslation["hideNoteEditorTextUtility"]),
            ("overwriteNoteFont", config.overwriteNoteFont,
             self.overwriteNoteFontChanged, True,
             config.thisTranslation["overwriteNoteFont"]),
            ("overwriteNoteFontSize", config.overwriteNoteFontSize,
             self.overwriteNoteFontSizeChanged, True,
             config.thisTranslation["overwriteNoteFontSize"]),
            ("overwriteBookFont", config.overwriteBookFont,
             self.overwriteBookFontChanged, True,
             config.thisTranslation["overwriteBookFont"]),
            ("overwriteBookFontSize", config.overwriteBookFontSize,
             self.overwriteBookFontSizeChanged, True,
             config.thisTranslation["overwriteBookFontSize"]),
            ("openBookInNewWindow", config.openBookInNewWindow,
             self.openBookInNewWindowChanged, False,
             config.thisTranslation["openBookInNewWindow"]),
            ("openPdfViewerInNewWindow", config.openPdfViewerInNewWindow,
             self.openPdfViewerInNewWindowChanged, False,
             config.thisTranslation["openPdfViewerInNewWindow"]),
            ("virtualKeyboard", config.virtualKeyboard,
             self.virtualKeyboardChanged, False,
             config.thisTranslation["virtualKeyboard"]),
            ("useWebbrowser", config.useWebbrowser, self.useWebbrowserChanged,
             True, config.thisTranslation["useWebbrowser"]),
            ("removeHighlightOnExit", config.removeHighlightOnExit,
             self.removeHighlightOnExitChanged, False,
             config.thisTranslation["removeHighlightOnExit"]),
            ("disableModulesUpdateCheck", config.disableModulesUpdateCheck,
             self.disableModulesUpdateCheckChanged, True,
             config.thisTranslation["disableModulesUpdateCheck"]),
            ("updateWithGitPull", config.updateWithGitPull,
             self.updateWithGitPullChanged, False,
             config.thisTranslation["updateWithGitPull"]),
            ("enableGist", config.enableGist, self.enableGistChanged, False,
             config.thisTranslation["enableGist"]),
            ("enableMacros", config.enableMacros, self.enableMacrosChanged,
             False, config.thisTranslation["enableMacros"]),
            ("enablePlugins", config.enablePlugins, self.enablePluginsChanged,
             True, config.thisTranslation["enablePlugins"]),
            ("hideBlankVerseCompare", config.hideBlankVerseCompare,
             self.hideBlankVerseCompareChanged, False,
             config.thisTranslation["hideBlankVerseCompare"]),
            ("enforceCompareParallel", config.enforceCompareParallel,
             self.parent.enforceCompareParallelButtonClicked, False,
             config.thisTranslation["enforceCompareParallel"]),
            ("enableMenuUnderline", config.enableMenuUnderline,
             self.enableMenuUnderlineChanged, True,
             config.thisTranslation["enableMenuUnderline"]),
            ("openBibleInMainViewOnly", config.openBibleInMainViewOnly,
             self.parent.enableStudyBibleButtonClicked, False,
             config.thisTranslation["openBibleInMainViewOnly"]),
            ("addOHGBiToMorphologySearch", config.addOHGBiToMorphologySearch,
             self.addOHGBiToMorphologySearchChanged, True,
             config.thisTranslation["addOHGBiToMorphologySearch"]),
            ("includeStrictDocTypeInNote", config.includeStrictDocTypeInNote,
             self.includeStrictDocTypeInNoteChanged, False,
             config.thisTranslation["includeStrictDocTypeInNote"]),
            ("parseTextConvertNotesToBook", config.parseTextConvertNotesToBook,
             self.parseTextConvertNotesToBookChanged, False,
             config.thisTranslation["parseTextConvertNotesToBook"]),
            ("parseTextConvertHTMLToBook", config.parseTextConvertHTMLToBook,
             self.parseTextConvertHTMLToBookChanged, False,
             config.thisTranslation["parseTextConvertHTMLToBook"]),
            ("displayCmdOutput", config.displayCmdOutput,
             self.displayCmdOutputChanged, False,
             config.thisTranslation["displayCmdOutput"]),
            ("disableLoadLastOpenFilesOnStartup",
             config.disableLoadLastOpenFilesOnStartup,
             self.disableLoadLastOpenFilesOnStartupChanged, False,
             config.thisTranslation["disableLoadLastOpenFilesOnStartup"]),
            ("disableOpenPopupWindowOnStartup",
             config.disableOpenPopupWindowOnStartup,
             self.disableOpenPopupWindowOnStartupChanged, True,
             config.thisTranslation["disableOpenPopupWindowOnStartup"]),
            ("showMiniKeyboardInMiniControl",
             config.showMiniKeyboardInMiniControl,
             self.showMiniKeyboardInMiniControlChanged, False,
             config.thisTranslation["showMiniKeyboardInMiniControl"]),
        ]
        if config.isTtsInstalled:
            options += [
                ("useLangDetectOnTts", config.useLangDetectOnTts,
                 self.useLangDetectOnTtsChanged, False,
                 config.thisTranslation["useLangDetectOnTts"]),
                ("ttsEnglishAlwaysUS", config.ttsEnglishAlwaysUS,
                 self.ttsEnglishAlwaysUSChanged, False,
                 config.thisTranslation["ttsEnglishAlwaysUS"]),
                ("ttsEnglishAlwaysUK", config.ttsEnglishAlwaysUK,
                 self.ttsEnglishAlwaysUKChanged, False,
                 config.thisTranslation["ttsEnglishAlwaysUK"]),
                ("ttsChineseAlwaysMandarin", config.ttsChineseAlwaysMandarin,
                 self.ttsChineseAlwaysMandarinChanged, False,
                 config.thisTranslation["ttsChineseAlwaysMandarin"]),
                ("ttsChineseAlwaysCantonese", config.ttsChineseAlwaysCantonese,
                 self.ttsChineseAlwaysCantoneseChanged, False,
                 config.thisTranslation["ttsChineseAlwaysCantonese"]),
            ]
        if platform.system() == "Linux":
            options += [
                ("linuxStartFullScreen", config.linuxStartFullScreen,
                 self.linuxStartFullScreenChanged, False,
                 config.thisTranslation["linuxStartFullScreen"]),
                ("fcitx", config.fcitx, self.fcitxChanged, False,
                 config.thisTranslation["fcitx"]),
                ("ibus", config.ibus, self.ibusChanged, False,
                 config.thisTranslation["ibus"]),
                ("espeak", config.espeak, self.espeakChanged, False,
                 config.thisTranslation["espeak"]),
            ]
        if config.developer:
            options += [
                ("forceGenerateHtml", config.forceGenerateHtml,
                 self.forceGenerateHtmlChanged, False,
                 config.thisTranslation["forceGenerateHtml"]),
                ("enableLogging", config.enableLogging,
                 self.enableLoggingChanged, False,
                 config.thisTranslation["enableLogging"]),
                ("logCommands", config.logCommands, self.logCommandsChanged,
                 False, config.thisTranslation["logCommands"]),
            ]
        data = {}
        for flag, configValue, action, default, tooltip in options:
            data[flag] = [configValue, default, tooltip, action]
        return data

    def restoreAllDefaults(self):
        for key, value in self.data.items():
            code = "config.{0} = {1}".format(key, value[1])
            exec(code)
        self.resetItems()
        self.displayMessage(config.thisTranslation["message_restart"])

    def itemChanged(self, standardItem):
        flag = standardItem.text()
        if flag in self.data and not self.isUpdating:
            self.data[flag][-1]()

    def resetItems(self):
        self.isUpdating = True
        # Empty the model before reset
        self.dataViewModel.clear()
        # Reset
        self.data = self.getOptions()
        filterEntry = self.filterEntry.text().lower()
        rowCount = 0
        for flag, value in self.data.items():
            configValue, default, tooltip, *_ = value
            if filterEntry == "" or (filterEntry != "" and
                                     (filterEntry in flag.lower()
                                      or filterEntry in tooltip.lower())):
                # 1st column
                item = QStandardItem(flag)
                item.setToolTip(tooltip)
                item.setCheckable(True)
                item.setCheckState(Qt.CheckState.Checked
                                   if configValue else Qt.CheckState.Unchecked)
                self.dataViewModel.setItem(rowCount, 0, item)
                # 2nd column
                item = QStandardItem(str(default))
                self.dataViewModel.setItem(rowCount, 1, item)
                # 3rd column
                tooltip = tooltip.replace("\n", " ")
                item = QStandardItem(tooltip)
                item.setToolTip(tooltip)
                self.dataViewModel.setItem(rowCount, 2, item)
                # add row count
                rowCount += 1
        self.dataViewModel.setHorizontalHeaderLabels([
            config.thisTranslation["flag"], config.thisTranslation["default"],
            config.thisTranslation["description"]
        ])
        self.dataView.resizeColumnsToContents()
        self.isUpdating = False

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

    def openWiki(self, event):
        wikiLink = "https://github.com/eliranwong/UniqueBible/wiki/Config-file-reference"
        webbrowser.open(wikiLink)

    def ibusChanged(self):
        config.ibus = not config.ibus
        if config.fcitx and config.ibus:
            config.fcitx = not config.fcitx
        if config.virtualKeyboard and config.ibus:
            config.virtualKeyboard = not config.virtualKeyboard
        self.displayMessage(config.thisTranslation["message_restart"])

    def fcitxChanged(self):
        config.fcitx = not config.fcitx
        if config.fcitx and config.ibus:
            config.ibus = not config.ibus
        if config.fcitx and config.virtualKeyboard:
            config.virtualKeyboard = not config.virtualKeyboard
        self.displayMessage(config.thisTranslation["message_restart"])

    def virtualKeyboardChanged(self):
        config.virtualKeyboard = not config.virtualKeyboard
        if config.fcitx and config.virtualKeyboard:
            config.fcitx = not config.fcitx
        if config.virtualKeyboard and config.ibus:
            config.ibus = not config.ibus
        self.displayMessage(config.thisTranslation["message_restart"])

    def parseWordDocumentChanged(self):
        config.parseWordDocument = not config.parseWordDocument

    def useLangDetectOnTtsChanged(self):
        config.useLangDetectOnTts = not config.useLangDetectOnTts

    def ttsEnglishAlwaysUSChanged(self):
        config.ttsEnglishAlwaysUS = not config.ttsEnglishAlwaysUS
        if config.ttsEnglishAlwaysUK and config.ttsEnglishAlwaysUS:
            config.ttsEnglishAlwaysUK = not config.ttsEnglishAlwaysUK

    def ttsEnglishAlwaysUKChanged(self):
        config.ttsEnglishAlwaysUK = not config.ttsEnglishAlwaysUK
        if config.ttsEnglishAlwaysUK and config.ttsEnglishAlwaysUS:
            config.ttsEnglishAlwaysUS = not config.ttsEnglishAlwaysUS

    def ttsChineseAlwaysMandarinChanged(self):
        config.ttsChineseAlwaysMandarin = not config.ttsChineseAlwaysMandarin
        if config.ttsChineseAlwaysMandarin and config.ttsChineseAlwaysCantonese:
            config.ttsChineseAlwaysCantonese = not config.ttsChineseAlwaysCantonese

    def ttsChineseAlwaysCantoneseChanged(self):
        config.ttsChineseAlwaysCantonese = not config.ttsChineseAlwaysCantonese
        if config.ttsChineseAlwaysMandarin and config.ttsChineseAlwaysCantonese:
            config.ttsChineseAlwaysMandarin = not config.ttsChineseAlwaysMandarin

    def showVerseNumbersInRangeChanged(self):
        config.showVerseNumbersInRange = not config.showVerseNumbersInRange

    #def customPythonOnStartupChanged(self):
    #    config.customPythonOnStartup = not config.customPythonOnStartup

    def openBibleWindowContentOnNextTabChanged(self):
        config.openBibleWindowContentOnNextTab = not config.openBibleWindowContentOnNextTab
        self.newTabException = False

    def showControlPanelOnStartupChanged(self):
        config.showControlPanelOnStartup = not config.showControlPanelOnStartup
        self.displayMessage(config.thisTranslation["message_restart"])

    def preferControlPanelForCommandLineEntryChanged(self):
        config.preferControlPanelForCommandLineEntry = not config.preferControlPanelForCommandLineEntry
        self.displayMessage(config.thisTranslation["message_restart"])

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

    def restrictControlPanelWidthChanged(self):
        config.restrictControlPanelWidth = not config.restrictControlPanelWidth
        self.parent.reloadControlPanel(False)

    def regexCaseSensitiveChanged(self):
        config.regexCaseSensitive = not config.regexCaseSensitive

    def openStudyWindowContentOnNextTabChanged(self):
        config.openStudyWindowContentOnNextTab = not config.openStudyWindowContentOnNextTab
        self.newTabException = False

    def addFavouriteToMultiRefChanged(self):
        config.addFavouriteToMultiRef = not config.addFavouriteToMultiRef

    def addOHGBiToMorphologySearchChanged(self):
        config.addOHGBiToMorphologySearch = not config.addOHGBiToMorphologySearch

    def exportEmbeddedImagesChanged(self):
        config.exportEmbeddedImages = not config.exportEmbeddedImages

    def clickToOpenImageChanged(self):
        config.clickToOpenImage = not config.clickToOpenImage

    def openBibleNoteAfterEditorClosedChanged(self):
        config.openBibleNoteAfterEditorClosed = not config.openBibleNoteAfterEditorClosed

    def preferHtmlMenuChanged(self):
        config.preferHtmlMenu = not config.preferHtmlMenu

    def hideNoteEditorStyleToolbarChanged(self):
        config.hideNoteEditorStyleToolbar = not config.hideNoteEditorStyleToolbar

    def hideNoteEditorTextUtilityChanged(self):
        config.hideNoteEditorTextUtility = not config.hideNoteEditorTextUtility

    def populateTabsOnStartupChanged(self):
        config.populateTabsOnStartup = not config.populateTabsOnStartup

    def openBookInNewWindowChanged(self):
        config.openBookInNewWindow = not config.openBookInNewWindow

    def convertChapterVerseDotSeparatorChanged(self):
        config.convertChapterVerseDotSeparator = not config.convertChapterVerseDotSeparator

    def updateWithGitPullChanged(self):
        config.updateWithGitPull = not config.updateWithGitPull
        if config.updateWithGitPull and not os.path.isdir(".git"):
            config.updateWithGitPull = False

    def parseBookChapterWithoutSpaceChanged(self):
        config.parseBookChapterWithoutSpace = not config.parseBookChapterWithoutSpace

    def parseBooklessReferencesChanged(self):
        config.parseBooklessReferences = not config.parseBooklessReferences

    def openPdfViewerInNewWindowChanged(self):
        config.openPdfViewerInNewWindow = not config.openPdfViewerInNewWindow

    def searchBibleIfCommandNotFoundChanged(self):
        config.searchBibleIfCommandNotFound = not config.searchBibleIfCommandNotFound

    def regexSearchBibleIfCommandNotFoundChanged(self):
        config.regexSearchBibleIfCommandNotFound = not config.regexSearchBibleIfCommandNotFound
        if config.regexSearchBibleIfCommandNotFound and not config.searchBibleIfCommandNotFound:
            config.searchBibleIfCommandNotFound = True

    def overwriteNoteFontChanged(self):
        config.overwriteNoteFont = not config.overwriteNoteFont

    def overwriteNoteFontSizeChanged(self):
        config.overwriteNoteFontSize = not config.overwriteNoteFontSize

    def overwriteBookFontChanged(self):
        config.overwriteBookFont = not config.overwriteBookFont

    def useWebbrowserChanged(self):
        config.useWebbrowser = not config.useWebbrowser

    def removeHighlightOnExitChanged(self):
        config.removeHighlightOnExit = not config.removeHighlightOnExit

    def overwriteBookFontSizeChanged(self):
        config.overwriteBookFontSize = not config.overwriteBookFontSize

    def alwaysDisplayStaticMapsChanged(self):
        config.alwaysDisplayStaticMaps = not config.alwaysDisplayStaticMaps

    def openBibleNoteAfterSaveChanged(self):
        config.openBibleNoteAfterSave = not config.openBibleNoteAfterSave

    def addBreakAfterTheFirstToolBarChanged(self):
        config.addBreakAfterTheFirstToolBar = not config.addBreakAfterTheFirstToolBar
        self.displayMessage(config.thisTranslation["message_restart"])

    def addBreakBeforeTheLastToolBarChanged(self):
        config.addBreakBeforeTheLastToolBar = not config.addBreakBeforeTheLastToolBar
        self.displayMessage(config.thisTranslation["message_restart"])

    def disableModulesUpdateCheckChanged(self):
        config.disableModulesUpdateCheck = not config.disableModulesUpdateCheck

    def forceGenerateHtmlChanged(self):
        config.forceGenerateHtml = not config.forceGenerateHtml

    def parserStandarisationChanged(self):
        if config.parserStandarisation == "YES":
            config.parserStandarisation = "NO"
        else:
            config.parserStandarisation = "YES"

    def linuxStartFullScreenChanged(self):
        config.linuxStartFullScreen = not config.linuxStartFullScreen
        self.displayMessage(config.thisTranslation["message_restart"])

    def espeakChanged(self):
        config.espeak = not config.espeak
        self.displayMessage(config.thisTranslation["message_restart"])

    def enableLoggingChanged(self):
        config.enableLogging = not config.enableLogging
        self.displayMessage(config.thisTranslation["message_restart"])

    def logCommandsChanged(self):
        config.logCommands = not config.logCommands

    def enableVerseHighlightingChanged(self):
        config.enableVerseHighlighting = not config.enableVerseHighlighting
        self.displayMessage(config.thisTranslation["message_restart"])

    def useLiteVerseParsingChanged(self):
        config.useLiteVerseParsing = not config.useLiteVerseParsing

    def parseEnglishBooksOnlyChanged(self):
        config.parseEnglishBooksOnly = not config.parseEnglishBooksOnly

    def enableMacrosChanged(self):
        config.enableMacros = not config.enableMacros
        self.displayMessage(config.thisTranslation["message_restart"])

    def enablePluginsChanged(self):
        config.enablePlugins = not config.enablePlugins
        self.parent.setMenuLayout(config.menuLayout)

    def clearCommandEntryChanged(self):
        config.clearCommandEntry = not config.clearCommandEntry

    def qtMaterialChanged(self):
        if not config.qtMaterial:
            self.parent.enableQtMaterial(True)
        else:
            self.parent.enableQtMaterial(False)

    def enableGistChanged(self):
        if not config.enableGist and config.isPygithubInstalled:
            config.enableGist = True
            self.displayMessage(config.thisTranslation["message_restart"])
        elif config.enableGist:
            config.enableGist = not config.enableGist
            self.displayMessage(config.thisTranslation["message_restart"])
        else:
            self.displayMessage(config.thisTranslation["message_noSupport"])

    def hideBlankVerseCompareChanged(self):
        config.hideBlankVerseCompare = not config.hideBlankVerseCompare

    def enableMenuUnderlineChanged(self):
        config.enableMenuUnderline = not config.enableMenuUnderline
        if config.enableMenuUnderline:
            config.menuUnderline = "&"
        else:
            config.menuUnderline = ""
        self.parent.setMenuLayout(config.menuLayout)

    def includeStrictDocTypeInNoteChanged(self):
        config.includeStrictDocTypeInNote = not config.includeStrictDocTypeInNote

    def parseTextConvertNotesToBookChanged(self):
        config.parseTextConvertNotesToBook = not config.parseTextConvertNotesToBook

    def parseTextConvertHTMLToBookChanged(self):
        config.parseTextConvertHTMLToBook = not config.parseTextConvertHTMLToBook

    def displayCmdOutputChanged(self):
        config.displayCmdOutput = not config.displayCmdOutput

    def disableLoadLastOpenFilesOnStartupChanged(self):
        config.disableLoadLastOpenFilesOnStartup = not config.disableLoadLastOpenFilesOnStartup

    def disableOpenPopupWindowOnStartupChanged(self):
        config.disableOpenPopupWindowOnStartup = not config.disableOpenPopupWindowOnStartup

    def showMiniKeyboardInMiniControlChanged(self):
        config.showMiniKeyboardInMiniControl = not config.showMiniKeyboardInMiniControl
Пример #19
0
class BibleCollectionDialog(QDialog):
    def __init__(self, parent):
        super().__init__()
        self.setWindowTitle(config.thisTranslation["bibleCollections"])
        self.setMinimumSize(680, 500)
        self.selectedCollection = None
        self.settingBibles = False
        self.bibles = self.getBibles()
        self.setupUI()
        self.parent = parent

    def setupUI(self):
        mainLayout = QVBoxLayout()

        title = QLabel(config.thisTranslation["bibleCollections"])
        mainLayout.addWidget(title)

        self.collectionsLayout = QVBoxLayout()
        self.collectionsList = QListWidget()
        self.collectionsList.setMaximumHeight(90)
        self.collectionsLayout.addWidget(self.collectionsList)
        mainLayout.addLayout(self.collectionsLayout)
        self.showListOfCollections()

        buttonsLayout = QHBoxLayout()
        addButton = QPushButton(config.thisTranslation["add"])
        addButton.clicked.connect(self.addNewCollection)
        buttonsLayout.addWidget(addButton)
        removeButton = QPushButton(config.thisTranslation["remove"])
        removeButton.clicked.connect(self.removeCollection)
        buttonsLayout.addWidget(removeButton)
        renameButton = QPushButton(config.thisTranslation["rename"])
        renameButton.clicked.connect(self.renameCollection)
        buttonsLayout.addWidget(renameButton)
        buttonsLayout.addStretch()
        mainLayout.addLayout(buttonsLayout)

        self.biblesTable = QTableView()
        self.biblesTable.setEnabled(False)
        self.biblesTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.biblesTable.setSortingEnabled(True)
        self.dataViewModel = QStandardItemModel(self.biblesTable)
        self.biblesTable.setModel(self.dataViewModel)
        self.loadBibleSelection()
        self.dataViewModel.itemChanged.connect(self.bibleSelectionChanged)
        mainLayout.addWidget(self.biblesTable)

        buttonLayout = QHBoxLayout()
        button = QPushButton(config.thisTranslation["close"])
        button.clicked.connect(self.reloadControlPanel)
        button.clicked.connect(self.close)
        buttonLayout.addWidget(button)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

    def showListOfCollections(self):
        self.collectionsList.clear()
        if len(config.bibleCollections) > 0:
            for collection in sorted(config.bibleCollections.keys()):
                showBibleSelection = QRadioButton()
                showBibleSelection.setChecked(False)
                self.collectionsList.itemClicked.connect(self.selectCollection)
                self.collectionsList.addItem(collection)
        else:
            self.collectionsList.addItem("[No collection defined]")

    def addNewCollection(self):
        name, ok = QInputDialog.getText(self, 'Collection', 'Collection name:')
        if ok and len(name) > 0 and name != "All":
            config.bibleCollections[name] = {}
            self.showListOfCollections()
            self.biblesTable.setEnabled(False)

    def removeCollection(self):
        config.bibleCollections.pop(self.selectedCollection, None)
        self.showListOfCollections()
        self.biblesTable.setEnabled(False)

    def renameCollection(self):
        name, ok = QInputDialog.getText(self,
                                        'Collection',
                                        'Collection name:',
                                        text=self.selectedCollection)
        if ok and len(name) > 0 and name != "All":
            biblesInCollection = config.bibleCollections[
                self.selectedCollection]
            config.bibleCollections.pop(self.selectedCollection, None)
            self.selectedCollection = name
            config.bibleCollections[name] = biblesInCollection
            self.showListOfCollections()
            self.biblesTable.setEnabled(False)

    def getBibles(self):
        from db.BiblesSqlite import BiblesSqlite
        from db.BiblesSqlite import Bible

        bibles = BiblesSqlite().getBibleList()
        bibleInfo = []
        for bible in bibles:
            description = Bible(bible).bibleInfo()
            bibleInfo.append((bible, description))
        return bibleInfo

    def selectCollection(self, item):
        self.selectedCollection = item.text()
        self.biblesTable.setEnabled(True)
        self.loadBibleSelection()

    def bibleSelectionChanged(self, item):
        if not self.settingBibles:
            if self.selectedCollection is not None:
                text = item.text()
                biblesInCollection = config.bibleCollections[
                    self.selectedCollection]
                if len(biblesInCollection) == 0:
                    biblesInCollection = []
                if text in biblesInCollection:
                    biblesInCollection.remove(text)
                else:
                    biblesInCollection.append(text)
                config.bibleCollections[
                    self.selectedCollection] = biblesInCollection

    def loadBibleSelection(self):
        self.settingBibles = True
        self.dataViewModel.clear()
        biblesInCollection = []
        if self.selectedCollection is not None:
            biblesInCollection = config.bibleCollections[
                self.selectedCollection]
        rowCount = 0
        for bible, description in self.bibles:
            item = QStandardItem(bible)
            item.setToolTip(bible)
            item.setCheckable(True)
            if bible in biblesInCollection:
                item.setCheckState(Qt.Checked)
            self.dataViewModel.setItem(rowCount, 0, item)
            item = QStandardItem(description)
            self.dataViewModel.setItem(rowCount, 1, item)
            rowCount += 1
        self.dataViewModel.setHorizontalHeaderLabels([
            config.thisTranslation["bible"],
            config.thisTranslation["description"]
        ])
        self.biblesTable.resizeColumnsToContents()
        self.settingBibles = False

    def reloadControlPanel(self):
        self.parent.reloadControlPanel(False)