Пример #1
0
class LeapFlow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.controller = Controller()
        self.listener = LeapListener(self)
        self.controller.add_listener(self.listener)

        self.mode = "gallery"
        self.scroll = False
        self.direction = ""
        self.direction_x = 0
        self.scroll_velocity = 0
        self.current_index = 0

        # List containing images for the gallery
        self.list_view = QListWidget()
        self.list_view.setFlow(0)
        self.list_view.setHorizontalScrollMode(1)
        self.list_view.setMouseTracking(True)
        self.list_view.itemClicked.connect(self.show_image)

        # Setting the style of the ListView, background, item selected, etc
        self.list_view.setStyleSheet(
            """
				QListWidget::item:hover {background: transparent;}
				QListWidget::item:disabled:hover {background: transparent;}
				QListWidget::item:hover:!active {background: transparent;}
				QListWidget::item:selected:active {background: transparent;}
	            QListWidget::item:selected:!active {background: transparent;}
	            QListWidget::item:selected:disabled {background: transparent;}
	            QListWidget::item:selected:!disabled {background: transparent;}
	            QListWidget {background: #2C3539}
			"""
        )

        # Image viewer
        self.scene = QGraphicsScene()
        self.viewer = QGraphicsView(self.scene)

        self.stackedWidget = QStackedWidget()
        self.stackedWidget.addWidget(self.list_view)
        self.stackedWidget.addWidget(self.viewer)

        self.setCentralWidget(self.stackedWidget)
        self.resize(500, 400)
        self.showMaximized()

        scan = ScanLibrary("/home/chris/Example")
        threads.append(scan)
        self.connect(scan, SIGNAL(scan.signal), self.add_images_to_list)
        scan.start()

        self.connect(self, SIGNAL("scrollChanged(bool)"), self.scroll_view)

    def setScroll(self, scroll):
        """Emit signal to scroll the view"""
        if self.scroll != scroll:
            self.scroll = scroll
            self.emit(SIGNAL("scrollChanged(bool)"), scroll)

    def scroll_view(self):
        """Scroll the view based on scroll velocity and direction"""

        x = self.direction_x * self.scroll_velocity / 100
        bar_x = self.list_view.horizontalScrollBar().value()
        self.list_view.horizontalScrollBar().setValue(bar_x + x)

    def add_images_to_list(self):
        """To add a widget to the listview you must add a QListWidgetItem
		and replace with your widget"""

        for image in library:
            item = QListWidgetItem()
            pixmap = QPixmap.fromImage(QImage(library[image]))
            label = QLabel()
            label.setPixmap(pixmap.scaled(600, 400))
            item.setSizeHint(label.sizeHint())
            item.setData(0, library[image])
            self.list_view.addItem(item)
            self.list_view.setItemWidget(item, label)

    def show_image(self, item):
        """"Display the selected image"""

        self.current_index = self.list_view.indexFromItem(item).row()
        self.scene.addPixmap((QPixmap.fromImage(QImage(item.text()))).scaled(self.viewer.size()))

        self.stackedWidget.setCurrentIndex(1)
        self.mode = "viewer"

    def previous_image(self):
        """Load previous image"""

        if self.current_index - 1 >= 0:
            self.current_index -= 1
            self.load_image()

    def next_image(self):
        """Load next image"""

        if self.current_index + 1 <= len(library.keys()) - 1:
            self.current_index += 1
            self.load_image()

    def load_image(self):
        """Load the image in self.current_index"""

        self.scene.addPixmap(QPixmap.fromImage(QImage(library[library.keys()[self.current_index]])))
Пример #2
0
class OWMoleculeVisualizer(OWWidget):
    settingsList = ["colorFragmets", "showFragments"]

    contextHandlers = {
        "":
        DomainContextHandler("", [
            ContextField("selected_title_indices"),
            ContextField("moleculeTitleAttributeList",
                         (DomainContextHandler.List +
                          DomainContextHandler.SelectedRequired +
                          DomainContextHandler.IncludeMetaAttributes),
                         selected="selectedMoleculeTitleAttrs"),
            ContextField(
                "smiles_var", DomainContextHandler.Required +
                DomainContextHandler.IncludeMetaAttributes)
        ],
                             maxAttributesToPickle=1000)
    }

    def __init__(self,
                 parent=None,
                 signalManager=None,
                 title="Molecule visualizer"):
        super(OWMoleculeVisualizer, self).__init__(parent, signalManager,
                                                   title)

        self.colorFragments = 1
        self.showFragments = 0
        self.selectedFragment = ""
        self.moleculeSmiles = []
        self.fragmentSmiles = []
        self.defFragmentSmiles = []
        self.smiles_var = 0
        self.moleculeTitleAttr = 0
        self.moleculeTitleAttributeList = []
        self.selectedMoleculeTitleAttrs = []
        self.fragmentSmilesAttr = 0
        self.imageSize = 200
        self.numColumns = 4
        self.commitOnChange = 0

        ## GUI
        box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True)
        self.infoLabel = OWGUI.label(box, self, "Chemicals:")
        box = OWGUI.radioButtonsInBox(self.controlArea,
                                      self,
                                      "showFragments",
                                      ["Show molecules", "Show fragments"],
                                      "Show",
                                      callback=self.updateitems)

        self.showFragmentsRadioButton = box.buttons[-1]
        self.markFragmentsCheckBox = OWGUI.checkBox(box,
                                                    self,
                                                    "colorFragments",
                                                    "Mark fragments",
                                                    callback=self._update)
        box.setSizePolicy(QSizePolicy(QSizePolicy.Minimum,
                                      QSizePolicy.Maximum))
        OWGUI.separator(self.controlArea)

        self.moleculeSmilesCombo = OWGUI.comboBox(self.controlArea,
                                                  self,
                                                  "smiles_var",
                                                  "Molecule SMILES Attribute",
                                                  callback=self.updateitems)
        self.moleculeSmilesCombo.box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum))
        self.smiles_var_model = VariableListModel(parent=self)
        self.moleculeSmilesCombo.setModel(self.smiles_var_model)

        OWGUI.separator(self.controlArea)
        box = OWGUI.widgetBox(self.controlArea,
                              "Molecule Title Attributes",
                              addSpace=True)

        self.title_var_view = QListView(
            selectionMode=QListView.ExtendedSelection)
        self.title_var_model = VariableListModel(parent=self)
        self.title_var_view.setModel(self.title_var_model)
        self.title_var_view.selectionModel().selectionChanged.connect(
            self._title_selection_changed)
        box.layout().addWidget(self.title_var_view)

        OWGUI.separator(self.controlArea)
        self.fragmentSmilesCombo = OWGUI.comboBox(
            self.controlArea,
            self,
            "fragmentSmilesAttr",
            "Fragment SMILES Attribute",
            callback=self.updateFragmentsListBox)

        self.fragmentSmilesCombo.setModel(VariableListModel(parent=self))
        self.fragmentSmilesCombo.box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum))
        OWGUI.separator(self.controlArea)
        box = OWGUI.spin(self.controlArea,
                         self,
                         "imageSize",
                         50,
                         500,
                         10,
                         box="Image Size",
                         callback=self._image_size_changed)

        box.setSizePolicy(QSizePolicy(QSizePolicy.Minimum,
                                      QSizePolicy.Maximum))

        OWGUI.separator(self.controlArea)
        box = OWGUI.widgetBox(self.controlArea, "Selection", addSpace=True)
        OWGUI.checkBox(box, self, "commitOnChange", "Commit on change")

        self.selectMarkedMoleculesButton = OWGUI.button(
            box, self, "Select &matched molecules", self.select_marked)
        OWGUI.button(box, self, "&Commit", callback=self.commit, default=True)
        OWGUI.separator(self.controlArea)
        OWGUI.rubber(self.controlArea)

        spliter = QSplitter(Qt.Vertical)
        self.scrollArea = ScrollArea(spliter)

        self.grid = GridWidget()
        self.grid.selectionChanged.connect(self._on_selection_changed)

        self.scrollArea.setWidget(self.grid)
        self.scrollArea.setWidgetResizable(True)
        self.mainArea.layout().addWidget(spliter)

        if pybel:
            self.listBox = QListWidget(spliter)
        else:
            self.listBox = QListWidget(None)
            self.listBox.setHidden(True)

        self.listBox.itemClicked.connect(self.fragmentSelection)

        self.fragmentSmilesCombo.box.setDisabled(not pybel)

        self.data = None
        self.data_subset = []
        self.fragment_data = None
        self.resize(800, 600)
        self.listBox.setMaximumHeight(150)
        self.fragmentSmilesCombo.setDisabled(True)
        self.selectMarkedMoleculesButton.setDisabled(True)
        self.markFragmentsCheckBox.setDisabled(True)
        self.showFragmentsRadioButton.setDisabled(True)

        self.loadSettings()

        if not pybel:
            self.showFragments = 0
            self.warning(
                10, "Pybel module not installed. To view molecule fragments\n"
                "please install openbabel python extension.")

        self.__loop = None

    def setMoleculeTable(self, data):
        self.closeContext()
        self.clear()

        self.data = data
        if data is not None:
            all_vars = data.domain.variables + data.domain.get_metas().values()
            text_vars = filter(
                lambda v: isinstance(v, (Orange.feature.Discrete, Orange.
                                         feature.String)), all_vars)
            var_scored = score_smiles_variables(data, text_vars)
            self.smiles_var_model[:] = [var for var, _ in var_scored]
            self.smiles_var = max(range(len(var_scored)),
                                  key=lambda i: var_scored[i][1])
            self.title_var_model[:] = all_vars

            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()
            if self.data_subset:
                try:
                    self.data_subset = self.data_subset.select(
                        self.data.domain)
                except Exception:
                    self.data_subset = []
            self.openContext("", data)
        else:
            self.defFragmentSmiles = []
            if not self.fragmentSmilesAttr:
                self.listBox.clear()

            self.openContext("", data)
            self.send("Selected Molecules", None)

    def setMoleculeSubset(self, data):
        self.data_subset = data
        try:
            self.data_subset = self.data_subset.select(self.data.domain)
        except Exception:
            self.data_subset = []

    def setFragmentTable(self, data):
        self.fragment_data = data
        if data is not None:
            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()
            self.selectedFragment = ""
        else:
            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()

        self.fragmentSmilesCombo.setEnabled(data is not None)

    def handleNewSignals(self):
        self.updateitems()

    def clear(self):
        self.smiles_var_model[:] = []
        self.title_var_model[:] = []

        self.fragmentSmilesCombo.clear()
        self.grid.clear()
        self._widgets = []
        self._items = []

        if self.__loop is not None:
            self.__loop.close()
            self.__loop = None

    def cleargrid(self):
        self.grid.clear()
        self._widgets = []

    def _update_titles(self):
        if self.data is None:
            return

        title_vars = [
            self.title_var_model[ind.row()]
            for ind in self.title_var_view.selectedIndexes()
        ]

        for item, widget in zip(self._items, self._widgets):
            inst = self.data[item.index]
            text = " / ".join(map(str, (inst[var] for var in title_vars)))
            widget.label.setText(text)

    def setFragmentSmilesCombo(self):
        if self.fragment_data:
            candidates = score_smiles_variables(self.fragment_data)
        else:
            candidates = []

        self.fragmentSmilesCombo.model()[:] = [v for v, _ in candidates]

        if self.fragmentSmilesAttr > len(candidates):
            self.fragmentSmilesAttr = 0

    def updateFragmentsListBox(self):
        if pybel is None:
            return

        fragvars = self.fragmentSmilesCombo.model()
        if 0 <= self.fragmentSmilesAttr < len(fragvars):
            fvar = fragvars[self.fragmentSmilesAttr]
        else:
            fvar = None

        if fvar:
            frags = [
                str(e[fvar]) for e in self.fragment_data
                if not e[fvar].is_special()
            ]
            self.fragmentSmiles = [""] + frags
        else:
            self.fragmentSmiles = [""] + self.defFragmentSmiles

        self.listBox.clear()
        self.listBox.addItems(self.fragmentSmiles)

        self.showFragmentsRadioButton.setDisabled(
            len(self.fragmentSmiles) == 1)
        self.markFragmentsCheckBox.setDisabled(len(self.fragmentSmiles) == 1)
        self.selectMarkedMoleculesButton.setDisabled(True)

    def fragmentSelection(self, item):
        if pybel is None:
            return

        index = self.listBox.indexFromItem(item).row()
        if index == -1:
            index = 0
        self.selectedFragment = self.fragmentSmiles[index]
        self.selectMarkedMoleculesButton.setEnabled(bool(
            self.selectedFragment))
        self.markFragmentsCheckBox.setEnabled(bool(self.selectedFragment))
        if not self.showFragments and self.colorFragments:
            self._update()

    def _title_text(self, index):
        title_vars = [
            self.title_var_model[ind.row()]
            for ind in self.title_var_view.selectedIndexes()
        ]
        inst = self.data[index]
        return " / ".join(map(str, (inst[var] for var in title_vars)))

    def _items_from_var(self, var):
        if self.data is None:
            return None

        values = [(i, str(inst[var])) for i, inst in enumerate(self.data)
                  if not inst[var].is_special()]
        return [
            Item(i, smiles, *self._parse_smiles(smiles))
            for i, smiles in values
        ]

    def _parse_smiles(self, smiles):
        try:
            return (OK, molecule_from_smiles(smiles))
        except Exception:
            return (ParseError, None)

    def updateitems(self):
        if self.showFragments and self.fragmentSmiles:
            values = [(None, frag) for frag in self.fragmentSmiles[1:]]
            items = [
                Item(i, smiles, *self._parse_smiles(smiles))
                for i, smiles in values
            ]
        else:
            smilesvar = self.smiles_var_model[self.smiles_var]
            items = self._items_from_var(smilesvar)

        self._items = items
        self.setupgrid()

    def setupgrid(self):
        self.cleargrid()

        layout = self.grid
        widgets = []

        for item in self._items:
            thumb = ThumbnailWidget(self.grid)
            thumb.setImageSize(self.imageSize, self.imageSize)
            if item.index is not None:
                text = self._title_text(item.index)
            else:
                text = ""
            thumb.label.setText(text)

            widgets.append(thumb)
            layout.appendWidget(thumb)

        self._widgets = widgets
        self.infoLabel.setText("Chemicals %i" % len(self._items))
        self._update()

    def __update_items(self, items, widgets, pattern=None):
        for i, item, widget in zip(range(len(items)), items, widgets):
            if item.status != ParseError:
                if pattern is not None:
                    emb = substructure_embedding(item.molecule, pattern)
                    emb = reduce(list.__iadd__, emb, [])
                    svg = molecule_to_svg_with_substructure(item.molecule, emb)
                else:
                    svg = molecule_to_svg(item.molecule)
            else:
                svg = ""

            widget.setData(svg)
            widget.setEnabled(True)
            yield i * 100.0 / len(items)

    def _update(self):
        if self.showFragments and self.fragmentSmiles:
            loop = self.__update_items(self._items, self._widgets)
        elif self.colorFragments and self.selectedFragment:
            pattern = pybel.Smarts(self.selectedFragment)
            loop = self.__update_items(self._items, self._widgets, pattern)
        else:
            loop = self.__update_items(self._items, self._widgets)
        self.__schedule(loop)

    def __schedule(self, coroutine):
        if self.__loop is not None:
            self.progressBarFinished()
            self.__loop.close()
            self.__loop = None

        self.__loop = coroutine

        self.progressBarInit()
        QTimer.singleShot(0, self.__loop_update)

    @Slot()
    def __loop_update(self):
        if self.__loop is None:
            return

        try:
            progress = next(self.__loop)
        except StopIteration:
            self.__loop = None
            self.progressBarFinished()
        else:
            self.progressBarSet(progress)
            QTimer.singleShot(0, self.__loop_update)

    def _title_selection_changed(self):
        self._update_titles()

    def _image_size_changed(self):
        for widget in self._widgets:
            widget.setImageSize(self.imageSize, self.imageSize)

        self.grid.layout().invalidate()

    def select_marked(self):
        if not pybel:
            return

        if not self.showFragments:
            pattern = pybel.Smarts(self.selectedFragment)
            for item, widget in zip(self._items, self._widgets):
                if item.status != ParseError:
                    emb = substructure_embedding(item.molecule, pattern)
                    widget.setSelected(bool(emb))
                else:
                    widget.setSelected(False)

            if self.commitOnChange:
                self.commit()

    def _on_selection_changed(self):
        if self.commitOnChange:
            self.commit()

    def commit(self):
        if self.showFragments:
            svar = self.smiles_var_model[self.smiles_var]
            items = self._items_from_var(svar)
            frags = [
                item for item, w in zip(self._items, self._widgets)
                if w.selected
            ]
            patterns = [pybel.Smarts(item.smiles) for item in frags]

            def test(molecule, patterns):
                return any(
                    bool(substructure_embedding(molecule, patt))
                    for patt in patterns)

            matched = filter(
                lambda item: item.status != ParseError and test(
                    item.molecule, patterns), items)
            instances = [self.data[item.index] for item in matched]

            if instances:
                table = Orange.data.Table(instances)
                self.send("Selected Molecules", table)
            else:
                self.send("Selected Molecules", None)
        else:
            items = [
                item for item, w in zip(self._items, self._widgets)
                if w.selected
            ]
            instances = [self.data[item.index] for item in items]

            if instances:
                table = Orange.data.Table(instances)
                self.send("Selected Molecules", table)
            else:
                self.send("Selected Molecules", None)

    def onDeleteWidget(self):
        OWWidget.onDeleteWidget(self)
        if self.__loop is not None:
            self.__loop.close()
            self.__loop = None
Пример #3
0
class SeriesPreview(QDialog):

    def __init__(self, parent=None):
        super(SeriesPreview, self).__init__(parent)

        self.data = None
        self.workingSet = None

        self.list = QListWidget()
        self.cancel = QPushButton('Close')
        self.apply = QPushButton('Update')

        self.layout = QGridLayout()
        self.layout.addWidget(self.list, 0, 0, 1, 2)
        self.layout.addWidget(self.apply, 1, 0)
        self.layout.addWidget(self.cancel, 1, 1)
        self.setLayout(self.layout)

        self.initComponents()
        self.initActions()

    def initComponents(self):
        self.setWindowFlags(Qt.Tool)
        self.setWindowTitle("Time series")

        self.setStyleSheet('''QPushButton {
                                color: #333;
                                border: 1px solid #555;
                                border-radius: 11px;
                                padding: 2px;
                                background: qradialgradient(cx: 0.3, cy: -0.4,
                                fx: 0.3, fy: -0.4,
                                radius: 1.35, stop: 0 #fff, stop: 1 #888);
                                min-width: 80px;
                            }
                            QPushButton:hover {
                                color: #fff;
                                background: qradialgradient(cx: 0.3, cy: -0.4,
                                fx: 0.3, fy: -0.4,
                                radius: 1.35, stop: 0 #fff, stop: 1 #bbb);}
                            QPushButton:pressed {
                                background: qradialgradient(cx: 0.4, cy: -0.1,
                                fx: 0.4, fy: -0.1,
                                radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}
                            QPushButton:checked {
                                background: qradialgradient(cx: 0.4, cy: -0.1,
                                fx: 0.4, fy: -0.1,
                                radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}
                            QListView::focus {
                                border: 2px solid black;
                                border-radius: 6px;
                            }
                            QScrollBar:vertical {
                              width: 20px;
                              border: 1px solid grey;
                              border-radius: 6px;
                              background-color: transparent;
                              margin: 28px 0 28px 0;
                            }
                            QScrollBar::add-line:vertical {
                              background: transparent;
                              height: 32px;
                              subcontrol-position: bottom;
                              subcontrol-origin: margin;
                            }
                            QScrollBar::sub-line:vertical {
                              background: transparent;
                              height: 32px;
                              subcontrol-position: top;
                              subcontrol-origin: margin;
                            }
                            QScrollBar::up-arrow:vertical {
                              width: 20px;
                              height: 32px;
                              background: transparent;
                              image: url(../res/icons/arrow_up.png);
                            }
                            QScrollBar::up-arrow:hover {
                              bottom: 2px;
                            }
                            QScrollBar::down-arrow:vertical {
                              width: 20px;
                              height: 32px;
                              background: transparent;
                              image: url(../res/icons/arrow_down.png);
                            }
                            QScrollBar::down-arrow:hover {
                              top: 2px;
                            }
                            QScrollBar::handle:vertical {
                                border-radius: 6px;
                                background: url(../res/icons/handle.png) 0% center no-repeat;
                                background-color: white;
                                min-height: 32px;
                            }
                            QScrollBar::handle:hover {
                                background: url(../res/icons/handle_hover.png) 0% center no-repeat;
                                background-color: white;
                                border: 1px solid gray;
                            }''')

        self.list.setAlternatingRowColors(True)
        self.list.setStyleSheet('''QListView::item:selected:active {
                 background: qlineargradient(x1: 1, y1: 0, x2: 0, y2: 3, stop: 0 #cbdaf1, stop: 1 #bfcde4);
            }
            QListView::item {
                border: 1px solid #d9d9d9;
                border-top-color: transparent;
                border-bottom-color: transparent;
            }
            QListView::item:hover {
                 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
                 border: 1px solid #bfcde4;
            }''')

        self.list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list.setContextMenuPolicy(Qt.ActionsContextMenu)

    def initActions(self):
        self.apply.clicked.connect(self.applyChanges)
        self.cancel.clicked.connect(self.close)

        self.list.itemDoubleClicked.connect(self.removeFromList)
        self.list.addAction(QAction('&Remove selected', self, triggered=self.removeItems))

    #--- actions ---#
    def updateData(self, data):
        self.data = data
        self.workingSet = data[0][:]
        self.updateList()

    def updateList(self):
        self.list.clear()
        for item in self.workingSet:
            item = QListWidgetItem(str(item))
            item.setTextAlignment(Qt.AlignCenter)
            self.list.addItem(item)

    def applyChanges(self):
        self.data = (self.workingSet, self.data[1])

    def removeFromList(self, item):
        self.workingSet.remove(float(item.text()))
        self.list.takeItem(self.list.indexFromItem(item).row())

    def removeItems(self):
        for item in self.list.selectedItems():
            self.workingSet.remove(float(item.text()))
            self.list.takeItem(self.list.indexFromItem(item).row())
Пример #4
0
class LeapFlow (QMainWindow):

	def __init__ (self):
		QMainWindow.__init__ (self)

		self.controller = Controller ()
		self.listener = LeapListener (self)
		self.controller.add_listener (self.listener)

		self.mode = "gallery"
		self.scroll = False
		self.direction = ""
		self.direction_x = 0
		self.scroll_velocity = 0
		self.current_index = 0

		# List containing images for the gallery
		self.list_view = QListWidget ()
		self.list_view.setFlow (0)
		self.list_view.setHorizontalScrollMode (1)
		self.list_view.setMouseTracking (True)
		self.list_view.itemClicked.connect (self.show_image)

		# Setting the style of the ListView, background, item selected, etc
		self.list_view.setStyleSheet ("""
				QListWidget::item:hover {background: transparent;}
				QListWidget::item:disabled:hover {background: transparent;}
				QListWidget::item:hover:!active {background: transparent;}
				QListWidget::item:selected:active {background: transparent;}
	            QListWidget::item:selected:!active {background: transparent;}
	            QListWidget::item:selected:disabled {background: transparent;}
	            QListWidget::item:selected:!disabled {background: transparent;}
	            QListWidget {background: #2C3539}
			""")

		# Image viewer
		self.scene = QGraphicsScene ()
		self.viewer = QGraphicsView (self.scene)

		self.stackedWidget = QStackedWidget ()
		self.stackedWidget.addWidget (self.list_view)
		self.stackedWidget.addWidget (self.viewer)

		self.setCentralWidget (self.stackedWidget)
		self.resize (500, 400)
		self.showMaximized ()

		scan = ScanLibrary ("/home/chris/Example")
		threads.append (scan)
		self.connect (scan, SIGNAL (scan.signal), self.add_images_to_list)
		scan.start ()

		self.connect (self, SIGNAL ("scrollChanged(bool)"), self.scroll_view)

	def setScroll (self, scroll):
		"""Emit signal to scroll the view"""
		if (self.scroll != scroll):
			self.scroll = scroll
			self.emit (SIGNAL("scrollChanged(bool)"), scroll)

	def scroll_view (self):
		"""Scroll the view based on scroll velocity and direction"""

		x = self.direction_x * self.scroll_velocity / 100
		bar_x = self.list_view.horizontalScrollBar ().value ()
		self.list_view.horizontalScrollBar ().setValue (bar_x + x)

	def add_images_to_list (self):
		"""To add a widget to the listview you must add a QListWidgetItem
		and replace with your widget"""

		for image in library:
			item = QListWidgetItem ()
			pixmap = QPixmap.fromImage (QImage (library[image]))
			label = QLabel ()
			label.setPixmap (pixmap.scaled (600, 400))
			item.setSizeHint (label.sizeHint ())
			item.setData (0, library[image])
			self.list_view.addItem (item)
			self.list_view.setItemWidget (item, label)

	def show_image (self, item):
		""""Display the selected image"""

		self.current_index = self.list_view.indexFromItem (item).row ()
		self.scene.addPixmap ((QPixmap.fromImage (QImage (item.text()))).scaled (self.viewer.size()))

		self.stackedWidget.setCurrentIndex (1)
		self.mode = "viewer"

	def previous_image (self):
		"""Load previous image"""

		if self.current_index - 1 >= 0:
			self.current_index -= 1
			self.load_image ()

	def next_image (self):
		"""Load next image"""

		if self.current_index + 1 <= len(library.keys ()) - 1:
			self.current_index += 1
			self.load_image ()

	def load_image (self):
		"""Load the image in self.current_index"""

		self.scene.addPixmap (QPixmap.fromImage (QImage (library[library.keys()[self.current_index]])))
Пример #5
0
class ListParameterWidget(GenericParameterWidget):
    """Widget class for List parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor

        .. versionadded:: 2.2

        :param parameter: A ListParameter object.
        :type parameter: ListParameter

        """
        super(ListParameterWidget, self).__init__(parameter, parent)

        self._input = QListWidget()

        self._input.setSelectionMode(QAbstractItemView.MultiSelection)

        if self._parameter.maximum_item_count != \
                self._parameter.minimum_item_count:
            tool_tip = 'Select between %d and %d items' % (
                self._parameter.minimum_item_count,
                self._parameter.maximum_item_count)
        else:
            tool_tip = 'Select exactly %d items' % (
                self._parameter.maximum_item_count)

        self._input.setToolTip(tool_tip)

        for opt in self._parameter.options_list:
            item = QListWidgetItem()
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            item.setText(str(opt))
            self._input.addItem(item)
            if opt in self._parameter.value:
                item.setSelected(True)

        self.inner_input_layout.addWidget(self._input)

        # override self._input_layout arrangement to make the label at the top
        # reset the layout
        self.input_layout.setParent(None)
        self.help_layout.setParent(None)

        self.label.setParent(None)
        self.inner_input_layout.setParent(None)

        self.input_layout = QVBoxLayout()
        self.input_layout.setSpacing(0)

        # put element into layout
        self.input_layout.addWidget(self.label)
        self.input_layout.addLayout(self.inner_input_layout)

        self.main_layout.addLayout(self.input_layout)
        self.main_layout.addLayout(self.help_layout)

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A ListParameter from the current state of widget

        """
        selected_value = []
        for opt in self._input.selectedItems():
            index = self._input.indexFromItem(opt)
            selected_value.append(self._parameter.options_list[index.row()])

        try:
            self._parameter.value = selected_value
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        return self._parameter
Пример #6
0
class FileArgs(QtHelper.EnhancedQDialog, Logger.ClassLogger):
    """
    File arguments dialog
    """
    def __init__(self, dataArgs, parent=None):
        """
        Dialog to fill arguments for the file probe

        @param dataArgs: 
        @type dataArgs: 

        @param parent: 
        @type parent:
        """
        super(FileArgs, self).__init__(parent)
        self.dataArgs = dataArgs
        self.createDialog()
        self.createConnections()
        self.loadDefaultData()

    def createDialog(self):
        """
        Create qt dialog
        """
        mainLayout = QHBoxLayout()

        dataLayout = QVBoxLayout()
        self.labelHelp = QLabel("Path of the file to retrieve:")
        self.lineEdit = QLineEdit()
        self.listBox = QListWidget()
        dataLayout.addWidget(self.labelHelp)
        dataLayout.addWidget(self.lineEdit)
        dataLayout.addWidget(self.listBox)

        buttonLayout = QVBoxLayout()
        self.addButton = QPushButton("Add", self)
        self.delButton = QPushButton("Remove", self)
        self.delButton.setEnabled(False)
        self.editButton = QPushButton("Edit", self)
        self.editButton.setEnabled(False)
        self.clearButton = QPushButton("Clear", self)
        self.okButton = QPushButton("Ok", self)
        self.cancelButton = QPushButton("Cancel", self)
        buttonLayout.addWidget(self.addButton)
        buttonLayout.addWidget(self.delButton)
        buttonLayout.addWidget(self.editButton)
        buttonLayout.addWidget(self.clearButton)
        buttonLayout.addWidget(self.okButton)
        buttonLayout.addWidget(self.cancelButton)

        mainLayout.addLayout(dataLayout)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

        self.setWindowTitle("File Probe > Arguments")

    def createConnections(self):
        """
        Create qt connections
        """
        self.okButton.clicked.connect(self.accept)
        self.cancelButton.clicked.connect(self.reject)
        self.addButton.clicked.connect(self.addItem)
        self.delButton.clicked.connect(self.delItem)
        self.editButton.clicked.connect(self.editItem)
        self.clearButton.clicked.connect(self.clearList)
        self.listBox.itemClicked.connect(self.onItemSelected)

    def clearList(self):
        """
        Clear the list
        """
        self.listBox.clear()

    def onItemSelected(self, itm):
        """
        Called when an item is selected
        """
        self.delButton.setEnabled(True)
        self.editButton.setEnabled(True)

    def editItem(self):
        """
        Edit the selected item
        """
        self.delButton.setEnabled(False)
        self.editButton.setEnabled(False)
        # retrieve value to put it in the line edit and then remove item
        model = self.listBox.model()
        for selectedItem in self.listBox.selectedItems():
            qIndex = self.listBox.indexFromItem(selectedItem)
            if sys.version_info > (3, ):
                self.lineEdit.setText(model.data(qIndex))
            else:
                self.lineEdit.setText(model.data(qIndex).toString())
            model.removeRow(qIndex.row())

    def delItem(self):
        """
        Delete the selected item
        """
        self.delButton.setEnabled(False)
        self.editButton.setEnabled(False)
        # remove item
        model = self.listBox.model()
        for selectedItem in self.listBox.selectedItems():
            qIndex = self.listBox.indexFromItem(selectedItem)
            model.removeRow(qIndex.row())

    def addItem(self):
        """
        Add item
        """
        txt = self.lineEdit.text()
        if txt != '':
            self.listBox.insertItem(0, txt)
            self.lineEdit.setText('')

    def loadDefaultData(self):
        """
        Load the default data
        """
        try:
            if len(self.dataArgs) == 0:
                return
            dat = eval(self.dataArgs)
            if 'files' in dat:
                list_files = dat['files']
                self.listBox.insertItems(0, list_files)
        except Exception as e:
            self.error(e)

    def getArgs(self):
        """
        Returns arguments
        Examples: {'files': [ '/etc/init.d/ntpd', '/root/wmi-1.3.14-2.el5.art.x86_64.rpm' ] }
        """
        listFiles = []
        model = self.listBox.model()
        # iterate all items in a QListWidget
        for index in xrange(self.listBox.count()):
            itm = self.listBox.item(index)
            qIndex = self.listBox.indexFromItem(itm)
            if sys.version_info > (3, ):
                listFiles.append(model.data(qIndex))
            else:
                listFiles.append(str(model.data(qIndex).toString()))
        ret = {'files': listFiles}
        if len(listFiles) == 0:
            ret = ''
        return str(ret)
Пример #7
0
class InputListParameterWidget(GenericParameterWidget):
    """Widget class for List parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor

        .. versionadded:: 2.2

        :param parameter: A ListParameter object.
        :type parameter: InputListParameter

        """
        super(InputListParameterWidget, self).__init__(parameter, parent)

        # value cache for self._parameter.value
        # copy the list so the original is unaffected
        self._value_cache = list(self._parameter.value)

        self._input = QListWidget()

        self._input.setSelectionMode(QAbstractItemView.SingleSelection)

        if self._parameter.maximum_item_count != \
                self._parameter.minimum_item_count:
            tool_tip = 'Select between %d and %d items' % (
                self._parameter.minimum_item_count,
                self._parameter.maximum_item_count)
        else:
            tool_tip = 'Select exactly %d items' % (
                self._parameter.maximum_item_count)

        self._input.setToolTip(tool_tip)

        # arrange widget

        self._insert_item_input = QLineEdit()

        vbox_layout = QVBoxLayout()
        hbox_layout = QHBoxLayout()
        self._input_add_button = QPushButton('Add')
        self._input_remove_button = QPushButton('Remove')
        # arrange line edit, add button, remove button in horizontal layout
        hbox_layout.addWidget(self._insert_item_input)
        hbox_layout.addWidget(self._input_add_button)
        hbox_layout.addWidget(self._input_remove_button)
        # arrange vertical layout
        vbox_layout.addLayout(hbox_layout)
        vbox_layout.addWidget(self._input)
        self._inner_input_layout.addLayout(vbox_layout)

        # override self._input_layout arrangement to make the label at the top
        # reset the layout
        self._input_layout.setParent(None)
        self._help_layout.setParent(None)

        self._label.setParent(None)
        self._inner_input_layout.setParent(None)

        self._input_layout = QVBoxLayout()
        self._input_layout.setSpacing(0)

        # put element into layout
        self._input_layout.addWidget(self._label)
        self._input_layout.addLayout(self._inner_input_layout)

        self._main_layout.addLayout(self._input_layout)
        self._main_layout.addLayout(self._help_layout)

        # connect handler
        # noinspection PyUnresolvedReferences
        self._input_add_button.clicked.connect(self.on_add_button_click)
        # noinspection PyUnresolvedReferences
        self._input_remove_button.clicked.connect(self.on_remove_button_click)
        # noinspection PyUnresolvedReferences
        self._insert_item_input.returnPressed.connect(
            self._input_add_button.click)
        # noinspection PyUnresolvedReferences
        self._input.itemChanged.connect(self.on_row_changed)

        self.refresh_list()

        # init row add error handler
        self._add_row_error_handler = None

    @property
    def add_row_error_handler(self):
        """return error handler if user mistakenly add row of unexpected type
        :return: a function handler
        :rtype: () -> None
        """
        return self._add_row_error_handler

    @add_row_error_handler.setter
    def add_row_error_handler(self, value):
        """Set error handler to handle user mistakenly add row of unexpected
        type
        """
        self._add_row_error_handler = value

    def refresh_list(self):
        self._input.clear()
        if not self._parameter.ordering == InputListParameter.NotOrdered:
            self._value_cache.sort()
        if self._parameter.ordering == InputListParameter.DescendingOrder:
            self._value_cache.reverse()
        for opt in self._value_cache:
            item = QListWidgetItem()
            item.setText(str(opt))
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self._input.addItem(item)

    def on_add_button_click(self):
        try:
            value = self._parameter.element_type(
                self._insert_item_input.text())
            self._value_cache.append(value)
            self.refresh_list()
        except ValueError:
            err = self.raise_invalid_type_exception()
            if self.add_row_error_handler is not None:
                self.add_row_error_handler(err)
            else:
                raise err

    def on_remove_button_click(self):
        for opt in self._input.selectedItems():
            index = self._input.indexFromItem(opt)
            del self._value_cache[index.row()]
        self.refresh_list()

    def on_row_changed(self, item):
        try:
            index = self._input.indexFromItem(item).row()
            prev_value = self._value_cache[index]
            self._value_cache[index] = self._parameter.element_type(
                item.text())
            self.refresh_list()
        except ValueError:
            item.setText(str(prev_value))
            self.raise_invalid_type_exception()

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A ListParameter from the current state of widget

        """

        try:
            self._parameter.value = self._value_cache
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        return self._parameter
Пример #8
0
class ListParameterWidget(GenericParameterWidget):
    """Widget class for List parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor

        .. versionadded:: 2.2

        :param parameter: A ListParameter object.
        :type parameter: ListParameter

        """
        super(ListParameterWidget, self).__init__(parameter, parent)

        self._input = QListWidget()

        self._input.setSelectionMode(QAbstractItemView.MultiSelection)

        if self._parameter.maximum_item_count != \
                self._parameter.minimum_item_count:
            tool_tip = 'Select between %d and %d items' % (
                self._parameter.minimum_item_count,
                self._parameter.maximum_item_count)
        else:
            tool_tip = 'Select exactly %d items' % (
                       self._parameter.maximum_item_count)

        self._input.setToolTip(tool_tip)

        for opt in self._parameter.options_list:
            item = QListWidgetItem()
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            item.setText(str(opt))
            self._input.addItem(item)
            if opt in self._parameter.value:
                item.setSelected(True)

        self._inner_input_layout.addWidget(self._input)

        # override self._input_layout arrangement to make the label at the top
        # reset the layout
        self._input_layout.setParent(None)
        self._help_layout.setParent(None)

        self._label.setParent(None)
        self._inner_input_layout.setParent(None)

        self._input_layout = QVBoxLayout()
        self._input_layout.setSpacing(0)

        # put element into layout
        self._input_layout.addWidget(self._label)
        self._input_layout.addLayout(self._inner_input_layout)

        self._main_layout.addLayout(self._input_layout)
        self._main_layout.addLayout(self._help_layout)

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A ListParameter from the current state of widget

        """
        selected_value = []
        for opt in self._input.selectedItems():
            index = self._input.indexFromItem(opt)
            selected_value.append(self._parameter.options_list[index.row()])

        try:
            self._parameter.value = selected_value
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        return self._parameter
class OWMoleculeVisualizer(OWWidget):
    settingsList = ["colorFragmets", "showFragments"]

    contextHandlers = {
        "": DomainContextHandler(
            "",
            [ContextField("selected_title_indices"),
             ContextField("moleculeTitleAttributeList",
                          (DomainContextHandler.List +
                           DomainContextHandler.SelectedRequired +
                           DomainContextHandler.IncludeMetaAttributes),
                          selected="selectedMoleculeTitleAttrs"),
             ContextField("smiles_var",
                          DomainContextHandler.Required +
                          DomainContextHandler.IncludeMetaAttributes)],
             maxAttributesToPickle=1000)
    }

    def __init__(self, parent=None, signalManager=None,
                 title="Molecule visualizer"):
        super(OWMoleculeVisualizer, self).__init__(parent, signalManager, title)

        self.colorFragments = 1
        self.showFragments = 0
        self.selectedFragment = ""
        self.moleculeSmiles = []
        self.fragmentSmiles = []
        self.defFragmentSmiles = []
        self.smiles_var = 0
        self.moleculeTitleAttr = 0
        self.moleculeTitleAttributeList = []
        self.selectedMoleculeTitleAttrs = []
        self.fragmentSmilesAttr = 0
        self.imageSize = 200
        self.numColumns = 4
        self.commitOnChange = 0

        ## GUI
        box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True)
        self.infoLabel = OWGUI.label(box, self, "Chemicals:")
        box = OWGUI.radioButtonsInBox(
            self.controlArea, self, "showFragments",
            ["Show molecules", "Show fragments"], "Show",
            callback=self.updateitems
        )

        self.showFragmentsRadioButton = box.buttons[-1]
        self.markFragmentsCheckBox = OWGUI.checkBox(
            box, self, "colorFragments", "Mark fragments",
            callback=self._update
        )
        box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum))
        OWGUI.separator(self.controlArea)

        self.moleculeSmilesCombo = OWGUI.comboBox(
            self.controlArea, self, "smiles_var",
            "Molecule SMILES Attribute",
            callback=self.updateitems
        )
        self.moleculeSmilesCombo.box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        )
        self.smiles_var_model = VariableListModel(parent=self)
        self.moleculeSmilesCombo.setModel(self.smiles_var_model)

        OWGUI.separator(self.controlArea)
        box = OWGUI.widgetBox(self.controlArea, "Molecule Title Attributes",
                              addSpace=True)

        self.title_var_view = QListView(
            selectionMode=QListView.ExtendedSelection
        )
        self.title_var_model = VariableListModel(parent=self)
        self.title_var_view.setModel(self.title_var_model)
        self.title_var_view.selectionModel().selectionChanged.connect(
            self._title_selection_changed
        )
        box.layout().addWidget(self.title_var_view)

        OWGUI.separator(self.controlArea)
        self.fragmentSmilesCombo = OWGUI.comboBox(
            self.controlArea, self, "fragmentSmilesAttr",
            "Fragment SMILES Attribute",
            callback=self.updateFragmentsListBox
        )

        self.fragmentSmilesCombo.setModel(VariableListModel(parent=self))
        self.fragmentSmilesCombo.box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        )
        OWGUI.separator(self.controlArea)
        box = OWGUI.spin(self.controlArea, self, "imageSize", 50, 500, 10,
                         box="Image Size", callback=self._image_size_changed)

        box.setSizePolicy(
            QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum))

        OWGUI.separator(self.controlArea)
        box = OWGUI.widgetBox(self.controlArea, "Selection", addSpace=True)
        OWGUI.checkBox(box, self, "commitOnChange", "Commit on change")

        self.selectMarkedMoleculesButton = OWGUI.button(
            box, self, "Select &matched molecules", self.select_marked
        )
        OWGUI.button(box, self, "&Commit", callback=self.commit, default=True)
        OWGUI.separator(self.controlArea)
        OWGUI.rubber(self.controlArea)

        spliter = QSplitter(Qt.Vertical)
        self.scrollArea = ScrollArea(spliter)

        self.grid = GridWidget()
        self.grid.selectionChanged.connect(self._on_selection_changed)

        self.scrollArea.setWidget(self.grid)
        self.scrollArea.setWidgetResizable(True)
        self.mainArea.layout().addWidget(spliter)

        if pybel:
            self.listBox = QListWidget(spliter)
        else:
            self.listBox = QListWidget(None)
            self.listBox.setHidden(True)

        self.listBox.itemClicked.connect(self.fragmentSelection)

        self.fragmentSmilesCombo.box.setDisabled(not pybel)

        self.data = None
        self.data_subset = []
        self.fragment_data = None
        self.resize(800, 600)
        self.listBox.setMaximumHeight(150)
        self.fragmentSmilesCombo.setDisabled(True)
        self.selectMarkedMoleculesButton.setDisabled(True)
        self.markFragmentsCheckBox.setDisabled(True)
        self.showFragmentsRadioButton.setDisabled(True)

        self.loadSettings()

        if not pybel:
            self.showFragments = 0
            self.warning(10,
                         "Pybel module not installed. To view molecule fragments\n"
                         "please install openbabel python extension.")

        self.__loop = None

    def setMoleculeTable(self, data):
        self.closeContext()
        self.clear()

        self.data = data
        if data is not None:
            all_vars = data.domain.variables + data.domain.get_metas().values()
            text_vars = filter(
                lambda v: isinstance(v, (Orange.feature.Discrete,
                                         Orange.feature.String)),
                all_vars)
            var_scored = score_smiles_variables(data, text_vars)
            self.smiles_var_model[:] = [var for var, _ in var_scored]
            self.smiles_var = max(range(len(var_scored)),
                                  key=lambda i: var_scored[i][1])
            self.title_var_model[:] = all_vars

            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()
            if self.data_subset:
                try:
                    self.data_subset = self.data_subset.select(self.data.domain)
                except Exception:
                    self.data_subset = []
            self.openContext("", data)
        else:
            self.defFragmentSmiles = []
            if not self.fragmentSmilesAttr:
                self.listBox.clear()

            self.openContext("", data)
            self.send("Selected Molecules", None)

    def setMoleculeSubset(self, data):
        self.data_subset = data
        try:
            self.data_subset = self.data_subset.select(self.data.domain)
        except Exception:
            self.data_subset = []

    def setFragmentTable(self, data):
        self.fragment_data = data
        if data is not None:
            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()
            self.selectedFragment = ""
        else:
            self.setFragmentSmilesCombo()
            self.updateFragmentsListBox()

        self.fragmentSmilesCombo.setEnabled(data is not None)

    def handleNewSignals(self):
        self.updateitems()

    def clear(self):
        self.smiles_var_model[:] = []
        self.title_var_model[:] = []

        self.fragmentSmilesCombo.clear()
        self.grid.clear()
        self._widgets = []
        self._items = []

        if self.__loop is not None:
            self.__loop.close()
            self.__loop = None

    def cleargrid(self):
        self.grid.clear()
        self._widgets = []

    def _update_titles(self):
        if self.data is None:
            return

        title_vars = [self.title_var_model[ind.row()]
                      for ind in self.title_var_view.selectedIndexes()]

        for item, widget in zip(self._items, self._widgets):
            inst = self.data[item.index]
            text = " / ".join(map(str, (inst[var] for var in title_vars)))
            widget.label.setText(text)

    def setFragmentSmilesCombo(self):
        if self.fragment_data:
            candidates = score_smiles_variables(self.fragment_data)
        else:
            candidates = []

        self.fragmentSmilesCombo.model()[:] = [v for v, _ in candidates]

        if self.fragmentSmilesAttr > len(candidates):
            self.fragmentSmilesAttr = 0

    def updateFragmentsListBox(self):
        if pybel is None:
            return

        fragvars = self.fragmentSmilesCombo.model()
        if 0 <= self.fragmentSmilesAttr < len(fragvars):
            fvar = fragvars[self.fragmentSmilesAttr]
        else:
            fvar = None

        if fvar:
            frags = [str(e[fvar]) for e in self.fragment_data
                     if not e[fvar].is_special()]
            self.fragmentSmiles = [""] + frags
        else:
            self.fragmentSmiles = [""] + self.defFragmentSmiles

        self.listBox.clear()
        self.listBox.addItems(self.fragmentSmiles)

        self.showFragmentsRadioButton.setDisabled(len(self.fragmentSmiles) == 1)
        self.markFragmentsCheckBox.setDisabled(len(self.fragmentSmiles) == 1)
        self.selectMarkedMoleculesButton.setDisabled(True)

    def fragmentSelection(self, item):
        if pybel is None:
            return

        index = self.listBox.indexFromItem(item).row()
        if index == -1:
            index = 0
        self.selectedFragment = self.fragmentSmiles[index]
        self.selectMarkedMoleculesButton.setEnabled(bool(self.selectedFragment))
        self.markFragmentsCheckBox.setEnabled(bool(self.selectedFragment))
        if not self.showFragments and self.colorFragments:
            self._update()

    def _title_text(self, index):
        title_vars = [self.title_var_model[ind.row()]
                      for ind in self.title_var_view.selectedIndexes()]
        inst = self.data[index]
        return " / ".join(map(str, (inst[var] for var in title_vars)))

    def _items_from_var(self, var):
        if self.data is None:
            return None

        values = [(i, str(inst[var])) for i, inst in enumerate(self.data)
                  if not inst[var].is_special()]
        return [Item(i, smiles, *self._parse_smiles(smiles))
                for i, smiles in values]

    def _parse_smiles(self, smiles):
        try:
            return (OK, molecule_from_smiles(smiles))
        except Exception:
            return (ParseError, None)

    def updateitems(self):
        if self.showFragments and self.fragmentSmiles:
            values = [(None, frag) for frag in self.fragmentSmiles[1:]]
            items = [Item(i, smiles, *self._parse_smiles(smiles))
                     for i, smiles in values]
        else:
            smilesvar = self.smiles_var_model[self.smiles_var]
            items = self._items_from_var(smilesvar)

        self._items = items
        self.setupgrid()

    def setupgrid(self):
        self.cleargrid()

        layout = self.grid
        widgets = []

        for item in self._items:
            thumb = ThumbnailWidget(self.grid)
            thumb.setImageSize(self.imageSize, self.imageSize)
            if item.index is not None:
                text = self._title_text(item.index)
            else:
                text = ""
            thumb.label.setText(text)

            widgets.append(thumb)
            layout.appendWidget(thumb)

        self._widgets = widgets
        self.infoLabel.setText("Chemicals %i" % len(self._items))
        self._update()

    def __update_items(self, items, widgets, pattern=None):
        for i, item, widget in zip(range(len(items)), items, widgets):
            if item.status != ParseError:
                if pattern is not None:
                    emb = substructure_embedding(item.molecule, pattern)
                    emb = reduce(list.__iadd__, emb, [])
                    svg = molecule_to_svg_with_substructure(item.molecule, emb)
                else:
                    svg = molecule_to_svg(item.molecule)
            else:
                svg = ""

            widget.setData(svg)
            widget.setEnabled(True)
            yield i * 100.0 / len(items)

    def _update(self):
        if self.showFragments and self.fragmentSmiles:
            loop = self.__update_items(self._items, self._widgets)
        elif self.colorFragments and self.selectedFragment:
            pattern = pybel.Smarts(self.selectedFragment)
            loop = self.__update_items(self._items, self._widgets, pattern)
        else:
            loop = self.__update_items(self._items, self._widgets)
        self.__schedule(loop)

    def __schedule(self, coroutine):
        if self.__loop is not None:
            self.progressBarFinished()
            self.__loop.close()
            self.__loop = None

        self.__loop = coroutine

        self.progressBarInit()
        QTimer.singleShot(0, self.__loop_update)

    @Slot()
    def __loop_update(self):
        if self.__loop is None:
            return

        try:
            progress = next(self.__loop)
        except StopIteration:
            self.__loop = None
            self.progressBarFinished()
        else:
            self.progressBarSet(progress)
            QTimer.singleShot(0, self.__loop_update)

    def _title_selection_changed(self):
        self._update_titles()

    def _image_size_changed(self):
        for widget in self._widgets:
            widget.setImageSize(self.imageSize, self.imageSize)

        self.grid.layout().invalidate()

    def select_marked(self):
        if not pybel:
            return

        if not self.showFragments:
            pattern = pybel.Smarts(self.selectedFragment)
            for item, widget in zip(self._items, self._widgets):
                if item.status != ParseError:
                    emb = substructure_embedding(item.molecule, pattern)
                    widget.setSelected(bool(emb))
                else:
                    widget.setSelected(False)

            if self.commitOnChange:
                self.commit()

    def _on_selection_changed(self):
        if self.commitOnChange:
            self.commit()

    def commit(self):
        if self.showFragments:
            svar = self.smiles_var_model[self.smiles_var]
            items = self._items_from_var(svar)
            frags = [item for item, w in zip(self._items, self._widgets)
                     if w.selected]
            patterns = [pybel.Smarts(item.smiles) for item in frags]

            def test(molecule, patterns):
                return any(bool(substructure_embedding(molecule, patt))
                           for patt in patterns)

            matched = filter(
                lambda item: item.status != ParseError and
                             test(item.molecule, patterns),
                items
            )
            instances = [self.data[item.index] for item in matched]

            if instances:
                table = Orange.data.Table(instances)
                self.send("Selected Molecules", table)
            else:
                self.send("Selected Molecules", None)
        else:
            items = [item for item, w in zip(self._items, self._widgets)
                     if w.selected]
            instances = [self.data[item.index] for item in items]

            if instances:
                table = Orange.data.Table(instances)
                self.send("Selected Molecules", table)
            else:
                self.send("Selected Molecules", None)

    def onDeleteWidget(self):
        OWWidget.onDeleteWidget(self)
        if self.__loop is not None:
            self.__loop.close()
            self.__loop = None
class InputListParameterWidget(GenericParameterWidget):
    """Widget class for List parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor

        .. versionadded:: 2.2

        :param parameter: A ListParameter object.
        :type parameter: InputListParameter

        """
        super(InputListParameterWidget, self).__init__(parameter, parent)

        # value cache for self._parameter.value
        # copy the list so the original is unaffected
        self._value_cache = list(self._parameter.value)

        self._input = QListWidget()

        self._input.setSelectionMode(QAbstractItemView.SingleSelection)

        if self._parameter.maximum_item_count != \
                self._parameter.minimum_item_count:
            tool_tip = 'Select between %d and %d items' % (
                self._parameter.minimum_item_count,
                self._parameter.maximum_item_count)
        else:
            tool_tip = 'Select exactly %d items' % (
                       self._parameter.maximum_item_count)

        self._input.setToolTip(tool_tip)

        # arrange widget

        self._insert_item_input = QLineEdit()

        vbox_layout = QVBoxLayout()
        hbox_layout = QHBoxLayout()
        self._input_add_button = QPushButton('Add')
        self._input_remove_button = QPushButton('Remove')
        # arrange line edit, add button, remove button in horizontal layout
        hbox_layout.addWidget(self._insert_item_input)
        hbox_layout.addWidget(self._input_add_button)
        hbox_layout.addWidget(self._input_remove_button)
        # arrange vertical layout
        vbox_layout.addLayout(hbox_layout)
        vbox_layout.addWidget(self._input)
        self._inner_input_layout.addLayout(vbox_layout)

        # override self._input_layout arrangement to make the label at the top
        # reset the layout
        self._input_layout.setParent(None)
        self._help_layout.setParent(None)

        self._label.setParent(None)
        self._inner_input_layout.setParent(None)

        self._input_layout = QVBoxLayout()
        self._input_layout.setSpacing(0)

        # put element into layout
        self._input_layout.addWidget(self._label)
        self._input_layout.addLayout(self._inner_input_layout)

        self._main_layout.addLayout(self._input_layout)
        self._main_layout.addLayout(self._help_layout)

        # connect handler
        # noinspection PyUnresolvedReferences
        self._input_add_button.clicked.connect(self.on_add_button_click)
        # noinspection PyUnresolvedReferences
        self._input_remove_button.clicked.connect(self.on_remove_button_click)
        # noinspection PyUnresolvedReferences
        self._insert_item_input.returnPressed.connect(
            self._input_add_button.click)
        # noinspection PyUnresolvedReferences
        self._input.itemChanged.connect(self.on_row_changed)

        self.refresh_list()

        # init row add error handler
        self._add_row_error_handler = None

    @property
    def add_row_error_handler(self):
        """return error handler if user mistakenly add row of unexpected type
        :return: a function handler
        :rtype: () -> None
        """
        return self._add_row_error_handler

    @add_row_error_handler.setter
    def add_row_error_handler(self, value):
        """Set error handler to handle user mistakenly add row of unexpected
        type
        """
        self._add_row_error_handler = value

    def refresh_list(self):
        self._input.clear()
        if not self._parameter.ordering == InputListParameter.NotOrdered:
            self._value_cache.sort()
        if self._parameter.ordering == InputListParameter.DescendingOrder:
            self._value_cache.reverse()
        for opt in self._value_cache:
            item = QListWidgetItem()
            item.setText(str(opt))
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self._input.addItem(item)

    def on_add_button_click(self):
        try:
            value = self._parameter.element_type(
                self._insert_item_input.text())
            self._value_cache.append(value)
            self.refresh_list()
        except ValueError:
            err = self.raise_invalid_type_exception()
            if self.add_row_error_handler is not None:
                self.add_row_error_handler(err)
            else:
                raise err

    def on_remove_button_click(self):
        for opt in self._input.selectedItems():
            index = self._input.indexFromItem(opt)
            del self._value_cache[index.row()]
        self.refresh_list()

    def on_row_changed(self, item):
        try:
            index = self._input.indexFromItem(item).row()
            prev_value = self._value_cache[index]
            self._value_cache[index] = self._parameter.element_type(
                item.text())
            self.refresh_list()
        except ValueError:
            item.setText(str(prev_value))
            self.raise_invalid_type_exception()

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A ListParameter from the current state of widget

        """

        try:
            self._parameter.value = self._value_cache
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        return self._parameter