コード例 #1
0
    def load(self):
        """Load all fields from the model
        """
        self.clear()
        self._checkable_items.clear()
        self.setColumnCount(2)
        self.setHorizontalHeaderLabels(["name", "description"])

        #  Load fields from variant categories
        self.appendRow(self._load_fields("variants"))
        #  Load fields from annotations categories
        self.appendRow(self._load_fields("annotations"))
        # Create and load fields from samples categories
        samples_items = QStandardItem("samples")
        samples_items.setIcon(FIcon(0xF0B9C))
        font = QFont()

        samples_items.setFont(font)
        for sample in sql.get_samples(self.conn):
            sample_item = self._load_fields("samples",
                                            parent_name=sample["name"])
            sample_item.setText(sample["name"])
            sample_item.setIcon(FIcon(0xF0B9C))
            samples_items.appendRow(sample_item)

        self.appendRow(samples_items)
コード例 #2
0
ファイル: widgets.py プロジェクト: tetedange13/cutevariant
    def load_fields(self, category, parent_name=None):
        root_item = QStandardItem(category)
        root_item.setColumnCount(2)
        root_item.setIcon(FIcon(0xF0256))
        font = QFont()
        root_item.setFont(font)

        type_icons = {
            "int": 0xF03A0,
            "str": 0xF100D,
            "float": 0xF03A0,
            "bool": 0xF023B
        }

        for field in sql.get_field_by_category(self.conn, category):
            field_name = QStandardItem(field["name"])
            descr = QStandardItem(field["description"])
            descr.setToolTip(field["description"])

            field_name.setCheckable(True)

            if field["type"] in type_icons.keys():
                field_name.setIcon(FIcon(type_icons[field["type"]]))

            root_item.appendRow([field_name, descr])
            self.checkable_items.append(field_name)

            if category == "samples":
                field_name.setData(
                    {"name": ("sample", parent_name, field["name"])})
            else:
                field_name.setData(field)

        return root_item
コード例 #3
0
    def __init__(self, conn=None, parent=None):
        super().__init__(parent)

        self.setWindowTitle(self.tr("Columns"))
        self.view = QTreeView()
        self.toolbar = QToolBar()
        # conn is always None here but initialized in on_open_project()
        self.model = FieldsModel(conn)

        # setup proxy ( for search option )
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setRecursiveFilteringEnabled(True)
        # Search is case insensitive
        self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        # Search in all columns
        self.proxy_model.setFilterKeyColumn(-1)

        self.view.setModel(self.proxy_model)
        self.view.setIconSize(QSize(16, 16))
        self.view.header().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.search_edit = QLineEdit()
        # self.view.setIndentation(0)
        self.view.header().setVisible(False)
        layout = QVBoxLayout()

        layout.addWidget(self.toolbar)
        layout.addWidget(self.view)
        layout.addWidget(self.search_edit)

        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)
        self.model.itemChanged.connect(self.on_fields_changed)

        # Setup toolbar
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.addAction(
            FIcon(0xF0615), self.tr("Collapse"), self.view.collapseAll
        )
        self.toolbar.addAction(FIcon(0xF0616), self.tr("Expand"), self.view.expandAll)

        # setup search edit
        search_act = self.toolbar.addAction(
            FIcon(0xF0969), self.tr("Search fields by keywords...")
        )
        search_act.setCheckable(True)
        search_act.toggled.connect(self.on_search_pressed)
        search_act.setShortcut(QKeySequence.Find)
        self.search_edit.setVisible(False)
        self.search_edit.setPlaceholderText(self.tr("Search by keywords... "))

        self.search_edit.textChanged.connect(self.proxy_model.setFilterRegExp)

        self._is_refreshing = (
            False  # Help to avoid loop between on_refresh and on_fields_changed
        )
コード例 #4
0
    def _fill_completer(self):
        """Create Completer with his model

        Fill the model with the SQL keywords and database fields
        """
        # preload samples , selection and wordset
        samples = [i["name"] for i in sql.get_samples(self.conn)]
        selections = [i["name"] for i in sql.get_selections(self.conn)]
        wordsets = [i["name"] for i in sql.get_wordsets(self.conn)]

        # keywords = []
        self.text_edit.completer.model.clear()
        self.text_edit.completer.model.beginResetModel()

        # register keywords
        for keyword in self.text_edit.syntax.sql_keywords:
            self.text_edit.completer.model.add_item(keyword, "VQL keywords",
                                                    FIcon(0xF0169), "#f6ecf0")

        for selection in selections:
            self.text_edit.completer.model.add_item(selection, "Source table",
                                                    FIcon(0xF04EB), "#f6ecf0")

        for wordset in wordsets:
            self.text_edit.completer.model.add_item(f"WORDSET['{wordset}']",
                                                    "WORDSET", FIcon(0xF04EB),
                                                    "#f6ecf0")

        for field in sql.get_fields(self.conn):
            name = field["name"]
            description = "<b>{}</b> ({}) from {} <br/><br/> {}".format(
                field["name"], field["type"], field["category"],
                field["description"])
            color = style.FIELD_TYPE.get(field["type"], "str")["color"]
            icon = FIcon(
                style.FIELD_TYPE.get(field["type"], "str")["icon"], "white")

            if field["category"] == "variants" or field[
                    "category"] == "annotations":
                self.text_edit.completer.model.add_item(
                    name, description, icon, color)

            if field["category"] == "samples":
                # Overwrite name
                for sample in samples:
                    name = "sample['{}'].{}".format(sample, field["name"])
                    description = "<b>{}</b> ({}) from {} {} <br/><br/> {}".format(
                        field["name"],
                        field["type"],
                        field["category"],
                        sample,
                        field["description"],
                    )
                    self.text_edit.completer.model.add_item(
                        name, description, icon, color)

        self.text_edit.completer.model.endResetModel()
コード例 #5
0
ファイル: widgets.py プロジェクト: tetedange13/cutevariant
    def data(self, index: QModelIndex(), role=Qt.DisplayRole):
        """Return the data stored under the given role for the item referred
        to by the index (row, col)
        Overrided from QAbstractTableModel
        :param index:
        :param role:
        :type index:
        :type role:
        :return: None if no valid index
        :rtype:
        """

        if not index.isValid():
            return None

        if role == Qt.DisplayRole:
            if index.column() == 0:
                return self.records[index.row()]["name"]

            if index.column() == 1:
                return self.records[index.row()]["count"]

        if role == Qt.DecorationRole:
            if index.column() == 0:
                return QIcon(FIcon(0xF04F1))

        return None
コード例 #6
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr("VQL Editor"))

        # Top toolbar
        self.top_bar = QToolBar()
        self.top_bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.run_action = self.top_bar.addAction(FIcon(0xF040A),
                                                 self.tr("Run"), self.run_vql)
        self.run_action.setShortcuts(
            [Qt.CTRL + Qt.Key_R, QKeySequence.Refresh])
        self.run_action.setToolTip(
            self.tr("Run VQL query (%s)" %
                    self.run_action.shortcut().toString()))

        # Syntax highlighter and autocompletion
        self.text_edit = CodeEdit()
        # Error handling
        self.log_edit = QLabel()
        self.log_edit.setMinimumHeight(40)
        self.log_edit.setStyleSheet(
            "QWidget{{background-color:'{}'; color:'{}'}}".format(
                style.WARNING_BACKGROUND_COLOR, style.WARNING_TEXT_COLOR))
        self.log_edit.hide()
        self.log_edit.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.top_bar)
        main_layout.addWidget(self.text_edit)
        main_layout.addWidget(self.log_edit)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        self.setLayout(main_layout)
コード例 #7
0
 def add_list_widget_item(self, db_name: str, url: str):
     """Add an item to the QListWidget of the current view"""
     # Key is the name of the database, value is its url
     item = QListWidgetItem(db_name)
     item.setIcon(FIcon(0xF0866))
     item.setData(Qt.UserRole, str(url))
     item.setToolTip(str(url))
     self.view.addItem(item)
コード例 #8
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle(self.tr("Memory"))
        self.setWindowIcon(FIcon(0xF070F))

        layout = QFormLayout()
        self.spinbox = QSpinBox()
        self.spinbox.setRange(0, 100000)
        layout.addRow(self.tr("Cache size"), self.spinbox)
コード例 #9
0
ファイル: widgets.py プロジェクト: tetedange13/cutevariant
    def __init__(self, parent=None, conn=None):
        """
        Args:
            parent (QMainWindow): Mainwindow of Cutevariant, passed during
                plugin initialization.
            conn (sqlite3.connexion): Sqlite3 connexion
        """
        super().__init__(parent)

        self.setWindowTitle(self.tr("Source editor"))
        # conn is always None here but initialized in on_open_project()
        self.model = SourceModel(conn)
        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.horizontalHeader().show()
        self.view.horizontalHeader().setStretchLastSection(False)
        self.view.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self.view.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.view.horizontalHeader().hide()

        self.toolbar = QToolBar()
        self.toolbar.setIconSize(QSize(16, 16))

        self.view.verticalHeader().hide()
        self.view.verticalHeader().setDefaultSectionSize(26)
        self.view.setShowGrid(False)
        self.view.setAlternatingRowColors(True)

        layout = QVBoxLayout()
        layout.addWidget(self.view)
        layout.addWidget(self.toolbar)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        self.setLayout(layout)

        # Used to block signals during the insertions (if set to True)
        self.is_loading = False

        # Map the operations of context menu with an internal id not visible
        # from the user
        # This id is used by _create_set_operation_menu
        # Keys: user text; values: set operators
        # See menu_setup()
        self.set_operations_mapping = dict()

        # call on_current_row_changed when item selection changed
        self.view.selectionModel().currentRowChanged.connect(
            self.on_current_row_changed)
        self.toolbar.addAction(FIcon(0xF0453), self.tr("Reload"), self.load)
コード例 #10
0
    def load(self):
        """Load all columns avaible into the model"""
        self.clear()
        self.checkable_items.clear()

        self.appendRow(self.load_fields("variants"))
        self.appendRow(self.load_fields("annotations"))

        samples_items = QStandardItem("samples")
        samples_items.setIcon(FIcon(0xF0B9C))
        font = QFont()

        samples_items.setFont(font)

        for sample in sql.get_samples(self.conn):
            sample_item = self.load_fields("samples", parent_name=sample["name"])
            sample_item.setText(sample["name"])
            sample_item.setIcon(FIcon(0xF0B9C))
            samples_items.appendRow(sample_item)

        self.appendRow(samples_items)
コード例 #11
0
ファイル: widgets.py プロジェクト: tetedange13/cutevariant
    def menu_setup(self, locked_selection=False):
        """Setup popup menu
        :key locked_selection: Allow to mask edit/remove actions (default False)
            Used on special selections like the default one (named variants).
        :type locked_selection: <boolean>
        """
        menu = QMenu()

        if not locked_selection:
            menu.addAction(FIcon(0xF0900), self.tr("Edit"),
                           self.edit_selection)

        #  Create action for bed
        menu.addAction(
            FIcon(0xF0219),
            self.tr("Intersect with BED file ..."),
            self.create_selection_from_bed,
        )

        # Set operations on selections: create mapping and actions
        set_icons_ids = (0xF0779, 0xF077C, 0xF0778)
        set_texts = (self.tr("Intersect"), self.tr("Difference"),
                     self.tr("Union"))
        set_internal_ids = ("&", "-", "|")
        # Map the operations with an internal id not visible for the user
        # This id is used by _create_set_operation_menu
        # Keys: user text; values: internal ids
        self.set_operations_mapping = dict(zip(set_texts, set_internal_ids))

        # Create actions
        [
            menu.addMenu(self._create_set_operation_menu(FIcon(icon_id), text))
            for icon_id, text in zip(set_icons_ids, set_texts)
        ]

        if not locked_selection:
            menu.addSeparator()
            menu.addAction(FIcon(0xF0A7A), self.tr("Remove"),
                           self.remove_selection)
        return menu
コード例 #12
0
    def _load_fields(self,
                     category: str,
                     parent_name: str = None) -> QStandardItem:
        """Load fields from database and create a QStandardItem
        
        Args:
            category (str): category name : eg. variants / annotations / samples
            parent_name (str, optional): name of the parent item 
        
        Returns:
            QStandardItem
        """
        root_item = QStandardItem(category)
        root_item.setColumnCount(2)
        root_item.setIcon(FIcon(0xF0256))
        font = QFont()
        root_item.setFont(font)

        for field in sql.get_field_by_category(self.conn, category):
            field_name = QStandardItem(field["name"])
            descr = QStandardItem(field["description"])
            descr.setToolTip(field["description"])

            field_name.setCheckable(True)

            field_type = style.FIELD_TYPE.get(field["type"])
            field_name.setIcon(
                FIcon(field_type["icon"], "white", field_type["color"]))

            root_item.appendRow([field_name, descr])
            self._checkable_items.append(field_name)

            if category == "samples":
                field_name.setData(
                    {"name": ("sample", parent_name, field["name"])})
            else:
                field_name.setData(field)

        return root_item
コード例 #13
0
    def on_group_changed(self):
        """Set group by fields when group by button is clicked"""
        is_checked = self.groupby_action.isChecked()
        is_grouped = self._is_grouped()
        if is_checked and not is_grouped:
            # Group it
            self.groupby_action.setIcon(FIcon(0xF14E1))
            self.groupby_action.setToolTip(self.tr("Ungroup variants"))
            # Recall previous/default group
            self._set_groups(self.last_group)
        else:
            # Ungroup it
            self.groupby_action.setIcon(FIcon(0xF14E0))
            self.groupby_action.setToolTip(
                self.tr("Group variants according to choosen columns"))
            # Save current group
            self.last_group = self.groupby_left_pane.group_by
        if not is_checked:
            # Reset to default group (chr set in _show_group_dialog)
            self._set_groups([])

        self.load()
        self._refresh_vql_editor()
コード例 #14
0
    def set_message(self, message: str):
        """Show message error at the bottom of the view

        Args:
            message (str): Error message
        """
        if self.log_edit.isHidden():
            self.log_edit.show()

        icon_64 = FIcon(0xF0027, style.WARNING_TEXT_COLOR).to_base64(18, 18)

        self.log_edit.setText("""<div height=100%>
            <img src="data:image/png;base64,{}" align="left"/>
             <span> {} </span>
            </div>""".format(icon_64, message))
コード例 #15
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle(self.tr("Cross databases links"))
        self.setWindowIcon(FIcon(0xF070F))

        help_label = QLabel(
            self.
            tr("Allow to set predefined masks for urls pointing to various databases of variants.\n"
               "Shortcuts will be visible from contextual menu over current variant.\n"
               "Set a link as default makes possible to open alink by double clicking on the view."
               ))

        self.view = QListWidget()
        self.add_button = QPushButton(self.tr("Add"))
        self.edit_button = QPushButton(self.tr("Edit"))
        self.set_default_button = QPushButton(self.tr("Set as default"))
        self.set_default_button.setToolTip(
            self.tr("Double click will open this link"))
        self.remove_button = QPushButton(self.tr("Remove"))

        v_layout = QVBoxLayout()
        v_layout.addWidget(self.add_button)
        v_layout.addWidget(self.edit_button)
        v_layout.addStretch()
        v_layout.addWidget(self.set_default_button)
        v_layout.addWidget(self.remove_button)

        h_layout = QHBoxLayout()
        h_layout.addWidget(self.view)
        h_layout.addLayout(v_layout)

        main_layout = QVBoxLayout()
        main_layout.addWidget(help_label)
        main_layout.addLayout(h_layout)
        self.setLayout(main_layout)

        # Signals
        self.add_button.clicked.connect(self.add_url)
        self.edit_button.clicked.connect(self.edit_item)
        self.view.itemDoubleClicked.connect(self.add_url)
        self.set_default_button.clicked.connect(self.set_default_link)
        self.remove_button.clicked.connect(self.remove_item)
コード例 #16
0
    def add_list_widget_item(self,
                             db_name: str,
                             url: str,
                             is_default=False,
                             is_browser=False):
        """Add an item to the QListWidget of the current view"""
        # Key is the name of the database, value is its url
        item = QListWidgetItem(db_name)
        item.setIcon(FIcon(0xF0866))
        item.setData(Qt.UserRole, str(url))  #  UserRole = Link
        item.setData(Qt.UserRole + 1,
                     bool(is_default))  # UserRole+1 = is default link
        item.setData(Qt.UserRole + 2,
                     bool(is_browser))  # UserRole+1 = is default link
        item.setToolTip(str(url))

        font = item.font()
        font.setBold(is_default)
        item.setFont(font)

        self.view.addItem(item)
コード例 #17
0
    def add_available_formatters(self):
        """Populate the formatters

        Also recall previously selected formatters via config file.
        Default formatter is "SeqoneFormatter".
        """
        # Get previously selected formatter
        formatter_name = self.settings.value("ui/formatter",
                                             "CutestyleFormatter")

        # Add formatters to combobox, a click on it will instantiate the class
        selected_formatter_index = 0
        for index, obj in enumerate(formatter.find_formatters()):
            self.formatter_combo.addItem(FIcon(0xF03D8), obj.DISPLAY_NAME, obj)
            if obj.__name__ == formatter_name:
                selected_formatter_index = index

        self.top_bar.addWidget(self.formatter_combo)
        self.formatter_combo.currentTextChanged.connect(
            self.on_formatter_changed)
        self.formatter_combo.setToolTip(self.tr("Change current style"))

        # Set the previously used/default formatter
        self.formatter_combo.setCurrentIndex(selected_formatter_index)
コード例 #18
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle(self.tr("Info variants"))

        # Current variant => set by on_refresh and on_open_project
        self.current_variant = None

        self.view = QTabWidget()
        self.toolbar = QToolBar()
        self.toolbar.setIconSize(QSize(16, 16))

        # Build comments tab
        self.edit_panel = EditPanel()
        self.edit_panel.saved.connect(self.on_save_variant)
        self.view.addTab(self.edit_panel, self.tr("User"))

        # Build variant tab
        self.variant_view = DictWidget()
        self.variant_view.set_header_visible(True)

        self.view.addTab(self.variant_view, self.tr("Variant"))

        # Build transcript tab
        self.transcript_combo = QComboBox()
        self.transcript_view = DictWidget()
        self.transcript_view.set_header_visible(True)
        tx_layout = QVBoxLayout()
        tx_layout.addWidget(self.transcript_combo)
        tx_layout.addWidget(self.transcript_view)
        tx_widget = QWidget()
        tx_widget.setLayout(tx_layout)
        self.view.addTab(tx_widget, self.tr("Transcripts"))
        self.transcript_combo.currentIndexChanged.connect(self.on_transcript_changed)

        # Build Samples tab
        self.sample_combo = QComboBox()
        self.sample_view = DictWidget()
        self.sample_view.set_header_visible(True)

        tx_layout = QVBoxLayout()
        tx_layout.addWidget(self.sample_combo)
        tx_layout.addWidget(self.sample_view)
        tx_widget = QWidget()
        tx_widget.setLayout(tx_layout)
        self.view.addTab(tx_widget, self.tr("Samples"))
        self.sample_combo.currentIndexChanged.connect(self.on_sample_changed)

        # Build genotype tab
        self.genotype_view = QListWidget()
        self.genotype_view.setIconSize(QSize(20, 20))
        self.view.addTab(self.genotype_view, self.tr("Genotypes"))

        v_layout = QVBoxLayout()
        v_layout.setContentsMargins(0, 0, 0, 0)
        v_layout.addWidget(self.view)
        self.setLayout(v_layout)

        # # Create menu
        # TODO: restore this
        # self.context_menu = VariantPopupMenu()
        # # Ability to trigger the menu
        # self.view.setContextMenuPolicy(Qt.CustomContextMenu)
        # self.view.customContextMenuRequested.connect(self.show_menu)
        # self.add_tab("variants")

        # Cache all database fields and their descriptions for tooltips
        # Field names as keys, descriptions as values
        self.fields_descriptions = None

        # Cache genotype icons
        # Values in gt field as keys (str), FIcon as values
        self.genotype_icons = {
            key: FIcon(val) for key, val in cm.GENOTYPE_ICONS.items()
        }
コード例 #19
0
 def __init__(self, parent=None):
     super().__init__(parent)
     self.setWindowIcon(FIcon(0xF035C))
     self.setWindowTitle("Variant view")
     self.add_settings_widget(LinkSettings())
コード例 #20
0
    def __init__(self, parent=None):
        super().__init__(parent)

        # Create 2 Panes
        self.splitter = QSplitter(Qt.Horizontal)
        self.main_right_pane = VariantView(parent=self)

        # No popup menu on this one
        self.groupby_left_pane = VariantView(parent=self,
                                             show_popup_menu=False)
        self.groupby_left_pane.hide()
        # Force selection of first item after refresh
        self.groupby_left_pane.row_to_be_selected = 0

        self.splitter.addWidget(self.groupby_left_pane)
        self.splitter.addWidget(self.main_right_pane)

        # Make resizable TODO : ugly ... Make it nicer
        # def _resize1_section(l, o, n):
        #     self.groupby_left_pane.view.horizontalHeader().resizeSection(l, n)

        # def _resize2_section(l, o, n):
        #     self.main_right_pane.view.horizontalHeader().resizeSection(l, n)

        # self.main_right_pane.view.horizontalHeader().sectionResized.connect(_resize1_section)
        # self.groupby_left_pane.view.horizontalHeader().sectionResized.connect(
        #     _resize2_section
        # )

        # self.groupby_left_pane.view.setHorizontalHeader(self.main_right_pane.view.horizontalHeader())

        # Top toolbar
        self.top_bar = QToolBar()
        # PS: Actions with QAction::LowPriority will not show the text labels
        self.top_bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        # checkable group action
        self.groupby_action = self.top_bar.addAction(FIcon(0xF14E0),
                                                     self.tr("Group by"),
                                                     self.on_group_changed)
        self.groupby_action.setToolTip(
            self.tr("Group variants according to choosen columns"))
        self.groupby_action.setCheckable(True)
        self.groupby_action.setChecked(False)

        # groupbylist
        self.groupbylist_action = self.top_bar.addAction("chr,pos,ref")
        self.groupbylist_action.setVisible(False)
        self.groupbylist_action.triggered.connect(self._show_group_dialog)

        self.top_bar.addSeparator()
        # Save selection
        self.save_action = self.top_bar.addAction(FIcon(0xF0F87),
                                                  self.tr("Save selection"),
                                                  self.on_save_selection)
        self.save_action.setToolTip(
            self.tr("Save the current variants into a new selection"))
        # self.save_action.setPriority(QAction.LowPriority)

        # Refresh UI button
        action = self.top_bar.addAction(FIcon(0xF0450), self.tr("Refresh"),
                                        self.on_refresh)
        action.setToolTip(self.tr("Refresh the current list of variants"))
        # action.setPriority(QAction.LowPriority)

        # Formatter tools
        self.top_bar.addSeparator()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.top_bar.addWidget(spacer)

        # Add formatters to combobox
        self.formatter_combo = QComboBox()
        self.settings = QSettings()
        self.add_available_formatters()

        # Error handling
        self.log_edit = QLabel()
        self.log_edit.setMaximumHeight(30)
        self.log_edit.setStyleSheet(
            "QWidget{{background-color:'{}'; color:'{}'}}".format(
                style.WARNING_BACKGROUND_COLOR, style.WARNING_TEXT_COLOR))
        self.log_edit.hide()
        self.log_edit.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)

        # Setup layout
        main_layout = QVBoxLayout()
        main_layout.addWidget(self.top_bar)
        main_layout.addWidget(self.splitter)
        main_layout.addWidget(self.log_edit)

        self.setLayout(main_layout)

        # Make connection
        self.main_right_pane.view.selectionModel().currentRowChanged.connect(
            lambda x, _: self.on_variant_clicked(x))

        self.groupby_left_pane.view.selectionModel().currentRowChanged.connect(
            lambda x, _: self.on_variant_clicked(x))
        self.groupby_left_pane.no_variant.connect(self.on_no_variant)
        # Connect errors from async runnables
        self.main_right_pane.runnable_exception.connect(self.set_message)
        self.groupby_left_pane.runnable_exception.connect(self.set_message)

        # Default group
        self.last_group = ["chr"]

        # Save fields between group/ungroup
        self.save_fields = list()
        self.save_filters = list()
コード例 #21
0
    def contextMenuEvent(self, event: QContextMenuEvent):
        """Override: Show contextual menu over the current variant"""
        if not self.show_popup_menu:
            return

        menu = QMenu(self)
        pos = self.view.viewport().mapFromGlobal(event.globalPos())
        current_index = self.view.indexAt(pos)

        if not current_index.isValid():
            return

        current_variant = self.model.variant(current_index.row())
        full_variant = sql.get_one_variant(self.conn, current_variant["id"])
        # Update variant with currently displayed fields (not in variants table)
        full_variant.update(current_variant)

        # Copy action: Copy the variant reference ID in to the clipboard
        formatted_variant = "{chr}:{pos}-{ref}-{alt}".format(**full_variant)
        menu.addAction(
            FIcon(0xF014C),
            formatted_variant,
            functools.partial(QApplication.instance().clipboard().setText,
                              formatted_variant),
        )

        # Create favorite action
        fav_action = menu.addAction(
            self.tr("&Unmark favorite") if bool(full_variant["favorite"]) else
            self.tr("&Mark as favorite"))
        fav_action.setCheckable(True)
        fav_action.setChecked(bool(full_variant["favorite"]))
        fav_action.toggled.connect(self.update_favorites)

        # Create classication action
        class_menu = menu.addMenu(self.tr("Classification"))
        for key, value in cm.CLASSIFICATION.items():

            action = class_menu.addAction(FIcon(cm.CLASSIFICATION_ICONS[key]),
                                          value)
            action.setData(key)
            on_click = functools.partial(self.update_classification,
                                         current_index, key)
            action.triggered.connect(on_click)

        # Create external links
        links_menu = menu.addMenu(self.tr("External links"))
        self.settings.beginGroup("plugins/variant_view/links")
        # Display only external links with placeholders that can be mapped
        for key in self.settings.childKeys():
            format_string = self.settings.value(key)
            # Get placeholders
            field_names = {
                name
                for text, name, spec, conv in string.Formatter().parse(
                    format_string)
            }
            if field_names & full_variant.keys():
                # Full or partial mapping => accepted link
                links_menu.addAction(
                    key,
                    functools.partial(
                        QDesktopServices.openUrl,
                        QUrl(format_string.format(**full_variant),
                             QUrl.TolerantMode),
                    ),
                )
        self.settings.endGroup()

        # Comment action
        on_edit = functools.partial(self.edit_comment, current_index)
        menu.addAction(self.tr("&Edit comment ..."), on_edit)

        # Edit menu
        menu.addSeparator()
        menu.addAction(FIcon(0xF018F), self.tr("&Copy"),
                       self.copy_to_clipboard, QKeySequence.Copy)
        menu.addAction(
            FIcon(0xF0486),
            self.tr("&Select all"),
            self.select_all,
            QKeySequence.SelectAll,
        )

        # Display
        menu.exec_(event.globalPos())
コード例 #22
0
    def __init__(self, parent=None, show_popup_menu=True):
        """
        Args:
            parent: parent widget
            show_popup_menu (boolean, optional: If False, disable the context menu
                over variants. For example the group pane should be disabled
                in order to avoid partial/false informations to be displayed
                in this menu.
                Hacky Note: also used to rename variants to groups in the page box...
        """
        super().__init__(parent)

        self.parent = parent
        self.show_popup_menu = show_popup_menu
        self.view = LoadingTableView()
        self.bottom_bar = QToolBar()

        self.settings = QSettings()

        # self.view.setFrameStyle(QFrame.NoFrame)
        self.view.setAlternatingRowColors(True)
        self.view.horizontalHeader().setStretchLastSection(True)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.verticalHeader().hide()

        self.view.setSortingEnabled(True)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        ## self.view.setIndentation(0)
        self.view.setIconSize(QSize(22, 22))
        self.view.horizontalHeader().setSectionsMovable(True)

        # Setup model
        self.model = VariantModel()
        self.view.setModel(self.model)

        # Setup delegate
        self.delegate = VariantDelegate()
        self.view.setItemDelegate(self.delegate)

        # setup toolbar
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        self.page_box = QLineEdit()
        self.page_box.setValidator(QIntValidator())
        self.page_box.setFixedWidth(50)
        self.page_box.setValidator(QIntValidator())

        if LOGGER.getEffectiveLevel() == DEBUG:
            # Display SQL query on debug mode only
            self.bottom_bar.addAction(FIcon(0xF0866),
                                      self.tr("Show SQL query"),
                                      self.on_show_sql)
        # Display nb of variants/groups and pages
        self.info_label = QLabel()
        self.bottom_bar.addWidget(self.info_label)
        self.bottom_bar.addWidget(spacer)
        self.bottom_bar.setIconSize(QSize(16, 16))
        self.bottom_bar.setMaximumHeight(30)
        self.bottom_bar.setContentsMargins(0, 0, 0, 0)

        self.pagging_actions = []
        self.pagging_actions.append(
            self.bottom_bar.addAction(FIcon(0xF0600), "<<",
                                      self.on_page_clicked))
        self.pagging_actions.append(
            self.bottom_bar.addAction(FIcon(0xF0141), "<",
                                      self.on_page_clicked))
        self.bottom_bar.addWidget(self.page_box)
        self.pagging_actions.append(
            self.bottom_bar.addAction(FIcon(0xF0142), ">",
                                      self.on_page_clicked))
        self.pagging_actions.append(
            self.bottom_bar.addAction(FIcon(0xF0601), ">>",
                                      self.on_page_clicked))
        self.page_box.returnPressed.connect(self.on_page_changed)

        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addWidget(self.view)
        main_layout.addWidget(self.bottom_bar)
        self.setLayout(main_layout)

        # Async stuff
        # broadcast focus signal
        self.row_to_be_selected = None
        # Get the status of async load: started/finished
        self.model.loading.connect(self._set_loading)
        # Queries are finished (yes its redundant with loading signal...)
        self.model.load_finished.connect(self.loaded)
        # Connect errors from async runnables
        self.model.runnable_exception.connect(self.runnable_exception)
コード例 #23
0
class CutestyleFormatter(Formatter):

    DISPLAY_NAME = "Cute style"

    BASE_COLOR = {"A": "green", "C": "red", "T": "red"}

    SO_COLOR = {
        # https://natsukis.livejournal.com/2048.html
        "missense_variant": "#bb96ff",
        "synonymous_variant": "#67eebd",
        "stop_gained": "#ed6d79",
        "stop_lost": "#ed6d79",
        "frameshift_variant": "#ff89b5",
    }

    ACMG_ICON = {
        "0": FIcon(0xF03A1, "lightgray"),
        "1": FIcon(0xF03A4, "#71e096"),
        "2": FIcon(0xF03A7, "#71e096"),
        "3": FIcon(0xF03AA, "#f5a26f"),
        "4": FIcon(0xF03AD, "#ed6d79"),
        "5": FIcon(0xF03B1, "#ed6d79"),
    }

    IMPACT_COLOR = {
        "HIGH": "#ff4b5c",
        "LOW": "#056674",
        "MODERATE": "#ecad7d",
        "MODIFIER": "#ecad7d",
    }

    FAV_ICON = {0: FIcon(0xF00C3), 1: FIcon(0xF00C0)}

    # Cache genotype icons
    # Values in gt field as keys (str), FIcon as values
    GENOTYPE_ICONS = {
        key: FIcon(val)
        for key, val in cm.GENOTYPE_ICONS.items()
    }

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

    def paint(self, painter: QPainter, option: QStyleOptionViewItem,
              index: QModelIndex):
        """Apply graphical formatting to each item in each displayed column in the view"""
        brush = QBrush()
        pen = QPen()
        font = QFont()

        if option.state & QStyle.State_Selected:
            text_color = option.palette.color(QPalette.Normal,
                                              QPalette.BrightText)
        else:
            text_color = option.palette.color(QPalette.Normal, QPalette.Text)

        is_selected = option.state & QStyle.State_Selected

        # Default theme color
        pen.setColor(text_color)

        field_name = self.field_name(index).lower()
        value = self.value(index)

        # Colour bases (default color is the one of the current theme)
        if (field_name == "ref"
                or field_name == "alt") and (value in ("A", "C", "G", "T")
                                             and not is_selected):
            pen.setColor(
                self.BASE_COLOR.get(value,
                                    option.palette.color(QPalette.WindowText)))

        if field_name == "impact" and not is_selected:
            font.setBold(True)
            pen.setColor(
                self.IMPACT_COLOR.get(value, self.IMPACT_COLOR["MODIFIER"]))

        if field_name == "gene" and not is_selected:
            pen.setColor("#6a9fca")

        if field_name == "classification":
            icon = self.ACMG_ICON.get(str(value), self.ACMG_ICON["0"])
            self.draw_icon(painter, option.rect, icon)
            return

        if field_name == "favorite":
            icon = self.FAV_ICON.get(int(value), self.FAV_ICON[0])
            self.draw_icon(painter, option.rect, icon)
            return

        if field_name == "hgvs_c":
            font.setBold(True)
            m = re.search(r"([cnm]\..+)", str(value))
            if m:
                value = m.group(1)

        if field_name == "hgvs_p":
            font.setBold(True)
            m = re.search(r"(p\..+)", str(value))
            if m:
                value = m.group(1)

        if re.match(r"sample\[.+\]\.gt", field_name):
            icon = self.GENOTYPE_ICONS.get(int(value), self.GENOTYPE_ICONS[-1])
            self.draw_icon(painter, option.rect, icon)
            return

        if field_name == "consequence":
            values = str(self.value(index)).split("&")
            metrics = QFontMetrics(font)
            x = option.rect.x() + 5
            # y = option.rect.center().y()
            for value in values:
                width = metrics.width(value)
                height = metrics.height()
                rect = QRect(x, 0, width + 15, height + 10)
                rect.moveCenter(option.rect.center())
                rect.moveLeft(x)
                painter.setFont(font)
                painter.setClipRect(option.rect, Qt.IntersectClip)
                painter.setBrush(
                    QBrush(QColor(self.SO_COLOR.get(value, "#90d4f7"))))
                painter.setPen(Qt.NoPen)
                painter.drawRoundedRect(rect, 3, 3)
                painter.setPen(QPen(QColor("white")))
                painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, value)
                x += width + 20
                painter.setClipping(False)

            return

        if field_name == "rsid":
            self.draw_url(painter, option.rect, value,
                          QUrl("http://www.google.fr"), index)
            return

        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setFont(font)
        painter.drawText(option.rect, option.displayAlignment, value)
コード例 #24
0
    def __init__(self, parent=None):
        super().__init__(parent)

        # Create fav button
        self.fav_button = QToolButton()
        self.fav_button.setCheckable(True)
        self.fav_button.setAutoRaise(True)
        self.fav_button.clicked.connect(self._form_changed)
        icon = QIcon()
        icon.addPixmap(FIcon(0xF00C3).pixmap(32, 32), QIcon.Normal, QIcon.Off)
        icon.addPixmap(FIcon(0xF00C0).pixmap(32, 32), QIcon.Normal, QIcon.On)
        self.fav_button.setIcon(icon)

        # Create classification combobox
        self.class_edit = QComboBox()
        self.class_edit.setFrame(False)
        self.class_edit.currentIndexChanged.connect(self._form_changed)

        for key in style.CLASSIFICATION:
            self.class_edit.addItem(
                FIcon(
                    style.CLASSIFICATION[key]["icon"],
                    style.CLASSIFICATION[key]["color"],
                ),
                style.CLASSIFICATION[key]["name"],
            )

        # Create comment form . This is a stack widget with a PlainText editor
        # and a Markdown preview as QTextBrowser

        self.comment_edit = QPlainTextEdit()
        self.comment_edit.setPlaceholderText("Write a comment in markdown ...")
        self.comment_edit.textChanged.connect(self._form_changed)

        self.comment_preview = QTextBrowser()
        self.comment_preview.setPlaceholderText("Press edit to add a comment ...")
        self.comment_preview.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self.comment_preview.setOpenExternalLinks(True)
        self.comment_preview.setFrameStyle(QFrame.NoFrame)

        # Create stacked
        self.stack = QStackedWidget()
        self.stack.addWidget(self.comment_edit)
        self.stack.addWidget(self.comment_preview)
        self.stack.setCurrentIndex(1)

        # Build layout
        self.setFrameShape(QFrame.StyledPanel)

        # header  layout
        title_layout = QHBoxLayout()
        title_layout.addWidget(self.class_edit)
        title_layout.addWidget(self.fav_button)

        # Button layout
        self.switch_button = QPushButton(self.tr("Edit comment..."))
        self.switch_button.setFlat(True)
        self.save_button = QPushButton(self.tr("Save"))
        self.save_button.setFlat(True)
        bar_layout = QHBoxLayout()
        bar_layout.addWidget(self.switch_button)
        bar_layout.addStretch()
        bar_layout.addWidget(self.save_button)

        # Main layout
        v_layout = QVBoxLayout()
        v_layout.addLayout(title_layout)
        v_layout.addWidget(self.stack)
        v_layout.addLayout(bar_layout)
        self.setLayout(v_layout)

        # Create connection
        self.switch_button.clicked.connect(self.switch_mode)
        self.save_button.clicked.connect(self._on_save)
        self._form_changed.connect(lambda: self.save_button.setEnabled(True))