コード例 #1
0
    def data(self, idx: QModelIndex, role: int = Qt.DisplayRole):
        depth = Id.depth(idx)
        if depth == Id.Depth.Invalid:
            return

        if role == Role.Data:
            # return the top level plugin
            if depth == Id.Depth.D0:
                return self.sourcePlugin(idx.row())
            if depth == Id.Depth.D1:
                return self.sourcePlugin(Id.row(idx.internalId()))
            if depth == Id.Depth.D2:
                return self.sourcePlugin(Id.row(Id.parentId(idx.internalId())))

        if role == Role.MergeAssociations:
            if depth == Id.Depth.D0:
                return self.mergeAssociations(idx.row())
            if depth == Id.Depth.D1:
                return self.mergeAssociations(Id.row(idx.internalId()))
            if depth == Id.Depth.D2:
                return self.mergeAssociations(
                    Id.row(Id.parentId(idx.internalId())))

        if role == Role.Cell:
            return self._display_data(idx)
        if not idx.parent().isValid():
            return
        if role == Qt.DisplayRole:
            return self._display_data(idx)
        return self._style_data(idx, role)
コード例 #2
0
def depth(idx: QtCore.QModelIndex):
    if not idx.isValid():
        return Depth.Invalid
    if not isValid(idx.internalId()):
        return Depth.D0
    if not isValid(parentId(idx.internalId())):
        return Depth.D1
    return Depth.D2
コード例 #3
0
ファイル: MergeModel.py プロジェクト: mdavis199/MergeWizard
 def parent(self, child: QModelIndex):
     if not child.isValid():
         return QModelIndex()
     parentId = child.internalId()
     if not Id.isValid(parentId):
         return QModelIndex()
     return self.createIndex(Id.row(parentId), Id.column(parentId), Id.parentId(parentId))
コード例 #4
0
ファイル: uitest.py プロジェクト: btownshend/pyTecan
 def selectSample(self,index: QModelIndex):
     print("select row",index.row(),"column",index.column(),"id",index.internalId())
     self.currentWell=self.sampleTable.item(index.row(),1).text()
     print("sample item=",self.sampleTable.item(index.row(),0).text())
     self.currentSample=int(self.sampleTable.item(index.row(),0).text())
     #self.plateTable.selectRow(index.row())
     self.refreshAll()
コード例 #5
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def is_deletable(self, index: QtCore.QModelIndex) -> bool:
        """
        Returns if an item is deletable

        Args:
            index (): The index

        Returns:
            True, if it can be deleted, false if not
        """

        column = index.internalId()
        # All deletable items are in the Items column
        if column != self.Columns.ITEMS:
            return False

        # These can be deleted in any case
        if self.root_row in (self.RootItems.AUTHOR, self.RootItems.CATEGORIES,
                             self.RootItems.CUISINE,
                             self.RootItems.YIELD_UNITS):
            return True

        # All other items may be only deleted if they are "empty" i.e. have no children
        number_of_items = index.data(QtCore.Qt.UserRole)
        if number_of_items > 0:
            return False

        # Last but not least: The base units cannot be deleted
        if self.root_row == self.RootItems.INGREDIENTUNITS:
            ingredient_unit = self._item_lists[self.Columns.ITEMS][
                index.row()][0]
            return ingredient_unit not in data.IngredientUnit.base_units

        return True
コード例 #6
0
 def _mapToLocal(self, index: QModelIndex) -> QModelIndex:
     """Возвращает индекс из модели с локальными данными для соответствующего индекса `index` из текущей модели."""
     if not index.isValid():
         return QModelIndex()
     assert index.model() is self
     return self.__localDataModel.createIndex(index.row(), index.column(),
                                              index.internalId())
コード例 #7
0
    def dataColumnView_updatePreviewWidget(self, index: QtCore.QModelIndex):
        item = None
        recipe_list = None
        column = index.internalId()
        model = self._item_model
        data = model.get_item(index.row(), index.internalId())
        if column == model.Columns.INGREDIENTLIST_ENTRIES:
            item = data
            recipe_list = [
                item.recipe,
            ]
        else:
            item = data[0]
            recipe_list = [recipe for recipe in item.recipes]

        self._recipe_list_model.set_recipe_list(recipe_list)
コード例 #8
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def parent(self, child: QtCore.QModelIndex) -> QtCore.QModelIndex:

        # Again - the "display" column, *not* the model column (which is always 0)
        child_column = child.internalId()
        if child_column == self.Columns.ROOT:
            # The items on the root level have no parent
            return QtCore.QModelIndex()
        return self.createIndex(self._parent_row[child_column - 1], 0,
                                child_column - 1)
コード例 #9
0
ファイル: uitest.py プロジェクト: btownshend/pyTecan
 def selectPlate(self,index: QModelIndex):
     print("select row",index.row(),"column",index.column(),"id",index.internalId())
     rec=self.plateTable.model().record(index.row())
     for i in range(rec.count()):
         print(rec.fieldName(i),"=",rec.field(i).value())
     self.currentPlate=rec.field(0).value()
     #self.plateTable.selectRow(index.row())
     self.currentSample=None
     self.currentWell=None
     self.refreshAll()
コード例 #10
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def canDropMimeData(self, data: QtCore.QMimeData,
                        action: QtCore.Qt.DropAction, row: int, column: int,
                        parent: QtCore.QModelIndex) -> bool:

        if not data.hasFormat(self.mime_type):
            return False

        # Only drops on the Item columns are allowed. And then only dropping directly on an item - the seconds
        # clause takes care of that. Otherwise it would be possible (at least visibly) to move an item to a leaf above
        # or beneath another item
        return parent.internalId() == self.Columns.ITEMS and column < 0
コード例 #11
0
ファイル: uitest.py プロジェクト: btownshend/pyTecan
    def selectRun(self,index: QModelIndex):
        print("select row",index.row(),"column",index.column(),"id",index.internalId())
        pkIndex=index.sibling(index.row(),0)

        self.currentRun=self.runsTable.model().data(pkIndex).value()
        pgmIndex=index.sibling(index.row(),3)
        self.currentProgram=self.runsTable.model().data(pgmIndex).value()
        self.currentPlate=None
        self.currentSample=None
        self.currentWell=None
        #self.runsTable.selectRow(index.row())
        self.refreshAll()
コード例 #12
0
    def _get_item_for_stackedwidget(self, selected_index: QtCore.QModelIndex):

        model = self._item_model
        column = selected_index.internalId()

        the_item = None
        if column == model.Columns.INGREDIENTLIST_ENTRIES:
            # Ingredient list items
            the_item = model.get_item(selected_index.row(), column)
        else:
            the_item = model.get_item(selected_index.row(), column)[0]
        return the_item
コード例 #13
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
 def index(self,
           row: int,
           column: int,
           parent: QtCore.QModelIndex = ...) -> QtCore.QModelIndex:
     if not parent.isValid():
         # The very first column, the root column. There's only one (model) column, hence the 0
         return self.createIndex(row, 0, self.Columns.ROOT)
     else:
         # The "display" column, *not* the model column
         parent_column = parent.internalId()
         self._parent_row[parent_column] = parent.row()
         return self.createIndex(row, 0, parent_column + 1)
コード例 #14
0
    def rowCount(self, parent: QModelIndex = QModelIndex()):
        if not self.sourceModel():
            return 0
        depth = Id.depth(parent)

        if depth == Id.Depth.Invalid:
            return self.sourceModel().rowCount()
        if parent.column() != 0:
            return 0
        if depth == Id.Depth.D0:
            return len(Row)
        if depth == Id.Depth.D1:
            plugin = self.sourcePlugin(Id.row(parent.internalId()))
            if not plugin.isMerge and not plugin.isMerged:
                return 0
            plugins, merges = self.mergeAssociations(
                Id.row(parent.internalId()))
            if parent.row() == Row.MergedPlugins:
                return len(plugins)
            if parent.row() == Row.MergedBy:
                return len(merges)
            if plugin.mergeFile and parent.row() == Row.ZEditOptions:
                return len(MERGE_OPTIONS)
        return 0
コード例 #15
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def setData(self,
                index: QtCore.QModelIndex,
                value: typing.Any,
                role: int = ...) -> bool:
        # TODO: Maybe test for the role?
        value = nullify(value)
        if value is None:
            return False

        column = index.internalId()
        row = index.row()
        root_row = self._parent_row[self.Columns.ROOT]

        item = None
        if column == self.Columns.INGREDIENTLIST_ENTRIES:
            item = self._item_lists[self.Columns.INGREDIENTLIST_ENTRIES][row]
        else:
            item = self._item_lists[column][row][0]

        if item.name == value:
            # User has double clicked without changing the value
            return False

        # Test if the value already exists - but only in case of items.
        if column == self.Columns.ITEMS:
            the_table = self._first_column[root_row][0]
            duplicate = self._session.query(the_table).filter(
                the_table.name == value).first()
            if duplicate:
                if duplicate == item:
                    # The same item - user has double clicked and then again. Nothing to do here.
                    return False
                else:
                    # Duplicate item. There three possible ways to deal with this:
                    # 1.) Silently discard the change
                    # 2.) Open a Error dialog telling the user about the problem
                    # 3.) Like in drag&drop, merge both items.

                    # Currently: #2

                    self.illegalValue.emit(
                        misc.IllegalValueEntered.ISDUPLICATE, value)
                    return False

        self.changed.emit()
        item.name = value
        self.dataChanged.emit(index, index)
        return True
コード例 #16
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def flags(self, index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlags:
        flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
        column = index.internalId()

        is_editable = False
        is_drop_enabled = False
        is_drag_enabled = False

        if column in (self.Columns.ITEMS, self.Columns.INGREDIENTLIST_ENTRIES):

            # Only certain combinations of drag&drop make sense: The item column can drag itself on another item
            # and recipes can be dragged to another author or cuisine. All other combination aren't very useful
            is_drag_enabled = (column == self.Columns.ITEMS
                               or self._parent_row[self.Columns.ROOT]
                               in (self.RootItems.INGREDIENTS,
                                   self.RootItems.CUISINE))

            if column == self.Columns.ITEMS:
                is_drop_enabled = True
                if self.root_row == self.RootItems.INGREDIENTUNITS:
                    ingredient_unit = self._item_lists[self.Columns.ITEMS][
                        index.row()][0]
                    is_editable = not ingredient_unit.cldr and not ingredient_unit in data.IngredientUnit.base_units.values(
                    )
                    is_drag_enabled = is_editable
                else:
                    is_editable = True
                    is_drag_enabled = True
            else:
                is_editable = self.root_row in (self.RootItems.INGREDIENTS,
                                                self.RootItems.INGREDIENTUNITS)

        if is_editable:
            flags |= QtCore.Qt.ItemIsEditable

        if is_drop_enabled:
            flags |= QtCore.Qt.ItemIsDropEnabled

        if is_drag_enabled:
            flags |= QtCore.Qt.ItemIsDragEnabled

        return flags
コード例 #17
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def delete_item(self, index: QtCore.QModelIndex):
        """
        Deletes an item (if allowed, that is)

        Args:
            index (): The index

        Returns:

        """

        if self.is_deletable(index):
            self.changed.emit()
            index_row = index.row()
            self.beginRemoveRows(
                self.createIndex(self.root_row, 0, self.Columns.ROOT),
                index_row, index_row)
            the_item = self._item_lists[index.internalId()][index_row][0]
            self._session.delete(the_item)
            self.endRemoveRows()
コード例 #18
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def data(self, index: QtCore.QModelIndex, role: int = ...) -> typing.Any:
        if role not in (QtCore.Qt.DisplayRole, QtCore.Qt.DecorationRole,
                        QtCore.Qt.EditRole, QtCore.Qt.FontRole,
                        QtCore.Qt.UserRole, QtCore.Qt.SizeHintRole):
            return QtCore.QVariant(None)

        column = index.internalId()
        row = index.row()
        count = 0
        if column == self.Columns.ROOT:
            # TODO: This needs optimization, for example caching.
            if role in (QtCore.Qt.DisplayRole, QtCore.Qt.UserRole):
                # Construct a query, i.e. which table to query
                query = self._session.query(
                    self._first_column[row][self.FirstColumnData.TABLE])

                # Ingredients and ingredient groups only differ whether to display ingredients groups
                # (and no ingredients) or only ingredients (and not groups)
                if row in (self.RootItems.INGREDIENTS,
                           self.RootItems.INGREDIENTGROUPS):
                    group = (row == self.RootItems.INGREDIENTGROUPS)
                    # is False/is True wouldn't work here
                    query = query.filter(data.Ingredient.is_group == group)
                count = query.count()

                if role == QtCore.Qt.DisplayRole:
                    return QtCore.QVariant(
                        f"{self._first_column[row][self.FirstColumnData.NAME]} ({count})"
                    )
                if role == QtCore.Qt.UserRole:
                    return QtCore.QVariant(count)

            if role == QtCore.Qt.DecorationRole:
                icon = self._first_column[row][self.FirstColumnData.ICON]
                if icon is not None:
                    return QtCore.QVariant(QtGui.QIcon(icon))

            return QtCore.QVariant()

        if column == self.Columns.ITEMS:
            item = self._item_lists[self.Columns.ITEMS][row][0]
            count = self._item_lists[self.Columns.ITEMS][row][1]
            if role == QtCore.Qt.UserRole:
                if self.root_row in (self.RootItems.INGREDIENTS,
                                     self.RootItems.INGREDIENTUNITS):
                    return QtCore.QVariant(count)
                else:
                    return 0

            if role == QtCore.Qt.DisplayRole:
                title = f"{item.name} ({count})"
                if self.root_row == self.RootItems.INGREDIENTUNITS:
                    # Display the unit in the user's locale
                    if item.cldr:
                        title = f"{item.unit_string()} ({count})"
                return QtCore.QVariant(title)

            if role == QtCore.Qt.EditRole:
                return QtCore.QVariant(item.name)

            # Ingredient icon
            if self.root_row == self.RootItems.INGREDIENTS:
                if role == QtCore.Qt.SizeHintRole:
                    return QtCore.QVariant(
                        QtCore.QSize(0, misc.values.ingredient_icon_height))
                elif role == QtCore.Qt.DisplayRole and item.icon is not None:
                    pixmap = QtGui.QPixmap()
                    if pixmap.loadFromData(item.icon):
                        return QtCore.QVariant(pixmap)

            if self.root_row == self.RootItems.INGREDIENTUNITS:
                ingredient_unit = item
                is_base_unit = ingredient_unit in data.IngredientUnit.base_units.values(
                )

                if role == QtCore.Qt.FontRole:
                    if is_base_unit:
                        return QtCore.QVariant(self._baseunit_font)
                    elif ingredient_unit.cldr:
                        return QtCore.QVariant(self._cldr_font)

                if role == QtCore.Qt.DecorationRole:
                    return QtCore.QVariant(
                        QtGui.QIcon(self._ingredient_unit_icons[
                            ingredient_unit.type_]))

        elif column == self.Columns.INGREDIENTLIST_ENTRIES:
            item = self._item_lists[column][row]
            if role == QtCore.Qt.UserRole:
                return 0

            if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
                return QtCore.QVariant(item.name)

        return QtCore.QVariant(None)
コード例 #19
0
def idForIndex(idx: QtCore.QModelIndex):
    return INVALID_ID if not idx.isValid() else idFor(idx.row(), idx.column(),
                                                      idx.internalId())
コード例 #20
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def rowCount(self, parent: QtCore.QModelIndex = ...) -> int:
        if parent.row() == -1:
            return self.RootItems.YIELD_UNITS + 1

        column = parent.internalId() + 1

        # Lazily load the columns. Note: Usually this is done using fetchMore() / canFetchMore. However, since
        # counting the rows and fetching the data at the same time is more efficient than first counting the rows
        # and then fetching the data (duplicating the same joins) this is done here
        parent_row = parent.row()

        # TODO: Restore/optimize by caching
        if column == self.Columns.ITEMS:
            the_table = self._first_column[parent_row][
                self.FirstColumnData.TABLE]

            # Construct the query
            query = None
            if parent_row == self.RootItems.INGREDIENTUNITS:
                # Ingredients (or better: amount units) are rather special - due to the handling of
                # CLDR the query has too little in common with the other ones. There's also the one
                # special class for Ingredient Groups
                self._item_lists[column] = self._session.query(the_table, func.count(data.IngredientListEntry.id)) \
                    .join(data.IngredientListEntry, data.IngredientUnit.id == data.IngredientListEntry.unit_id,
                          isouter=True).order_by(text('cldr DESC, type_ ASC,  lower(ingredient_unit.name) ASC')) \
                    .group_by(the_table.id) \
                    .filter(data.IngredientUnit.type_ != data.IngredientUnit.UnitType.GROUP).all()
            else:
                if parent_row in (self.RootItems.INGREDIENTS,
                                  self.RootItems.INGREDIENTGROUPS):
                    # Ingredient groups and Ingredients are virtually the same - the only difference is that
                    # Ingredients have is_group = False, where for Ingredients groups it's true
                    group = (parent_row == self.RootItems.INGREDIENTGROUPS)
                    query = self._session.query(the_table, func.count(data.IngredientListEntry.id).label("count")) \
                        .join(data.IngredientListEntry, isouter=True).filter(data.Ingredient.is_group == group)
                else:
                    # Items which have recipes attached to them
                    query = self._session.query(
                        the_table,
                        func.count(data.Recipe.id).label("count"))

                    # Categories need an additional join
                    if parent_row == self.RootItems.CATEGORIES:
                        query = query.join(
                            data.CategoryList,
                            data.Category.id == data.CategoryList.category_id,
                            isouter=True)
                    query = query.join(data.Recipe, isouter=True)

                self._item_lists[column] = query.group_by(
                    the_table.id).order_by(func.lower(the_table.name)).all()

        elif column == self.Columns.INGREDIENTLIST_ENTRIES:
            # Potential effects of Drag & Drop
            if len(self._item_lists[self.Columns.ITEMS]) > 0:
                item = self._item_lists[self.Columns.ITEMS][parent_row][0]

                # Copy the lists. Otherwise - when cleared - they would be erased from the
                # database itself: items/recipes are sqlalchemy lists, very convenient - but changes
                # there will cause database changes, too, so clearing() such a list will cause the references
                # to be deleted for real.
                item_list = None
                if self.root_row == self.RootItems.INGREDIENTS:
                    item_list = item.items
                else:
                    item_list = item.ingredientlist
                self._item_lists[column] = [
                    item_data for item_data in item_list
                ]
        else:
            return 0

        return len(self._item_lists[column])
コード例 #21
0
ファイル: data_editor_model.py プロジェクト: mnowiasz/qisit
    def dropMimeData(self, mimedata: QtCore.QMimeData,
                     action: QtCore.Qt.DropAction, row: int, column: int,
                     parent: QtCore.QModelIndex) -> bool:

        index_list = pickle.loads(mimedata.data(self.mime_type))
        target_row = parent.row()
        target_column = parent.internalId()

        # The affected recipes
        recipes_ids = set()

        # Merge vs append
        merged = False
        cached = {}

        # This is needed because of the rows that will be removed - the indexes aren't valid after that, so
        # this is to conserve (temporarily) the status quo ante
        for (index_row, index_column) in index_list:
            cached[(
                target_column,
                target_row)] = self._item_lists[target_column][target_row][0]
            if index_column == target_column:
                cached[(
                    target_column,
                    index_row)] = self._item_lists[target_column][index_row][0]
            else:
                cached[(index_column,
                        index_row)] = self._item_lists[index_column][index_row]

        for (index_row, index_column) in index_list:
            if index_column == target_column:
                # Merge operation
                merged = True

                source_item = cached[(target_column, index_row)]
                target_item = cached[(target_column, target_row)]

                # Merging an item with itself is useless
                if source_item == target_item:
                    return False

                self.changed.emit()

                recipes_ids = recipes_ids.union(
                    [recipe.id for recipe in source_item.recipes])
                self.beginRemoveRows(
                    self.createIndex(self.root_row, 0, self.Columns.ROOT),
                    index_row, index_row)

                the_table = None
                if self.root_row in (self.RootItems.AUTHOR,
                                     self.RootItems.CUISINE,
                                     self.RootItems.YIELD_UNITS):
                    the_query = self._session.query(data.Recipe)
                    if self.root_row == self.RootItems.AUTHOR:
                        the_query.filter(
                            data.Recipe.author_id == source_item.id).update(
                                {data.Recipe.author_id: target_item.id},
                                synchronize_session='evaluate')
                    elif self.root_row == self.RootItems.CUISINE:
                        the_query.filter(
                            data.Recipe.cuisine_id == source_item.id).update(
                                {data.Recipe.cuisine_id: target_item.id},
                                synchronize_session='evaluate')
                    elif self.root_row == self.RootItems.YIELD_UNITS:
                        the_query.filter(
                            data.Recipe.yield_unit_id ==
                            source_item.id).update(
                                {data.Recipe.yield_unit_id: target_item.id},
                                synchronize_session='evaluate')

                elif self.root_row == self.RootItems.CATEGORIES:
                    # Categories are special. TODO: Maybe construct a (rather complicated, probably) Query instead
                    # of this

                    # Need to copy the list recipes - because making changes will alter the original recipes
                    recipes = [recipe for recipe in source_item.recipes]
                    for recipe in recipes:
                        if target_item not in recipe.categories:
                            recipe.categories.append(target_item)
                        recipe.categories.remove(source_item)
                        self._session.merge(recipe)
                elif self.root_row in (self.RootItems.INGREDIENTGROUPS,
                                       self.RootItems.INGREDIENTS):
                    self._session.query(data.IngredientListEntry).filter(
                        data.IngredientListEntry.ingredient_id ==
                        source_item.id).update(
                            {
                                data.IngredientListEntry.ingredient_id:
                                target_item.id
                            },
                            synchronize_session='evaluate')
                elif self.root_row == self.RootItems.INGREDIENTUNITS:
                    self._session.query(data.IngredientListEntry).filter(
                        data.IngredientListEntry.unit_id ==
                        source_item.id).update(
                            {data.IngredientListEntry.unit_id: target_item.id},
                            synchronize_session='evaluate')
                self._session.expire_all()
                self._session.delete(source_item)
            else:
                # Append operation. Only allowed on Cuisine or Ingredients
                self.changed.emit()
                # target_item = self._item_lists[target_column][target_row][0]
                target_item = cached[(target_column, target_row)]
                parent_index = self._parent_row[target_column]
                self.beginRemoveRows(
                    self.createIndex(parent_index, 0, self.Columns.ITEMS),
                    index_row, index_row)
                if self.root_row == self.RootItems.CUISINE:
                    recipe = cached[(index_column, index_row)]
                    recipe.cuisine = target_item

                elif self.root_row == self.RootItems.INGREDIENTS:
                    ingredient_list_entry = cached[(index_column, index_row)]
                    ingredient_list_entry.ingredient = target_item
                self._session.refresh(target_item)

            self.endRemoveRows()

        if merged:
            self.changeSelection.emit(parent)

        return True