Esempio n. 1
0
 def __init__(self, g, mappedClass, query, columns, defaultSortClause=None):
     super(BaseQueryModel, self).__init__()
     self.g = g
     self.mappedClass = mappedClass
     self.g.registerRetranslate(self.allDataChanged)
     self.baseQuery = query
     self.columns = []
     for column in columns:
         try:
             self.columns.append(ModelColumn.load(column, model=self))
         except Exception:
             traceback.print_exc()
             print 'Failed to load column:', column
     if defaultSortClause is None:
         self.defaultSortClause = self.columns[0].getSortClause()
     else:
         self.defaultSortClause = defaultSortClause
     self.sortClauses = SortModel(self, [])
     self.sortClauses.rowsInserted.connect(self.sortChanged)
     self.sortClauses.rowsRemoved.connect(self.sortChanged)
     self.sortClauses.dataChanged.connect(self.sortChanged)
     self.filters = []
     self._setQuery()
Esempio n. 2
0
 def __init__(self, g, mappedClass, query, columns, defaultSortClause=None):
     super(BaseQueryModel, self).__init__()
     self.g = g
     self.mappedClass = mappedClass
     self.g.registerRetranslate(self.allDataChanged)
     self.baseQuery = query
     self.columns = []
     for column in columns:
         try:
             self.columns.append(ModelColumn.load(column, model=self))
         except Exception:
             traceback.print_exc()
             print 'Failed to load column:', column
     if defaultSortClause is None:
         self.defaultSortClause = self.columns[0].getSortClause()
     else:
         self.defaultSortClause = defaultSortClause
     self.sortClauses = SortModel(self, [])
     self.sortClauses.rowsInserted.connect(self.sortChanged)
     self.sortClauses.rowsRemoved.connect(self.sortChanged)
     self.sortClauses.dataChanged.connect(self.sortChanged)
     self.filters = []
     self._setQuery()
Esempio n. 3
0
class BaseQueryModel(QtCore.QAbstractItemModel):
    """A model that displays an ORM query, with a set of custom columns.

    Can be queried the Python way, (with []).
    """
    collapsingPossible = False
    _pagesize = 1000
    __metaclass__ = ModelMetaclass

    def __init__(self, g, mappedClass, query, columns, defaultSortClause=None):
        super(BaseQueryModel, self).__init__()
        self.g = g
        self.mappedClass = mappedClass
        self.g.registerRetranslate(self.allDataChanged)
        self.baseQuery = query
        self.columns = []
        for column in columns:
            try:
                self.columns.append(ModelColumn.load(column, model=self))
            except Exception:
                traceback.print_exc()
                print 'Failed to load column:', column
        if defaultSortClause is None:
            self.defaultSortClause = self.columns[0].getSortClause()
        else:
            self.defaultSortClause = defaultSortClause
        self.sortClauses = SortModel(self, [])
        self.sortClauses.rowsInserted.connect(self.sortChanged)
        self.sortClauses.rowsRemoved.connect(self.sortChanged)
        self.sortClauses.dataChanged.connect(self.sortChanged)
        self.filters = []
        self._setQuery()

    @property
    def allSortClauses(self):
        return (self.defaultSortClause, ) + tuple(self.sortClauses)

    def _setQuery(self):
        """Called every time the query changes"""
        builder = self.baseBuilder()
        for clause in reversed(self.allSortClauses):
            clause.sort(builder)
        self._query = builder.query
        self._rows = int(self._query.count())
        self.pages = [None] * (self._rows // self._pagesize + 1)

    def baseBuilder(self):
        """Return a QueryBuilder corresponding to the base query
        """
        return QueryBuilder(self.baseQuery, self.mappedClass)

    def dump(self):
        """Dump a simple representation of the data to stdout
        """
        for item in self:
            for column in self.columns:
                print column.data(item, None),
            print

    def allDataChanged(self):
        """Called when all of the data is changed, e.g. retranslated"""
        self._setQuery()
        self.dataChanged.emit(
                self.index(0, 0),
                self.index(self.rowCount() - 1, self.columnCount() - 1),
            )
        self.headerDataChanged.emit(Qt.Horizontal, 0, self.columnCount() - 1)

    def __getitem__(self, i):
        pageno, offset = divmod(i, self._pagesize)
        page = self.pages[pageno]
        if not page:
            start = pageno * self._pagesize
            end = (pageno + 1) * self._pagesize
            page = self.pages[pageno] = self._query[start:end]
        return page[offset]

    def columnCount(self, parent=QtCore.QModelIndex()):
        return len(self.columns)

    def data(self, index, role=Qt.DisplayRole):
        item = self.itemForIndex(index)
        if item:
            return self.columns[index.column()].data(item, role)

    def itemForIndex(self, index):
        """Returns the item that corresponds to the given index"""
        if index.isValid() and not index.parent().isValid():
            return self[index.row()]

    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal:
            return self.columns[section].headerData(role, self)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            if 0 <= row < self.rowCount() and 0 <= column < self.columnCount():
                return self.createIndex(row, column)

    def rowCount(self, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            return self._rows
        else:
            return 0

    def parent(self, index):
        return QtCore.QModelIndex()

    def save(self):
        """Can't save a query directly"""
        raise AssertionError("Can't save a BaseQueryModel")

    def removeColumns(self, column, count, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            last = column + count - 1
            if column == 0:
                # Can't remove the first column
                column += 1
                last -= 1
                if column == last:
                    return False
            self.beginRemoveColumns(QtCore.QModelIndex(), column, last)
            del self.columns[column:last + 1]
            self.endRemoveColumns()
            return True

    def insertQueryColumn(self, position, column):
        """Insert a ModelColumn at the specified position

        Qt's normal column-inserting API doesn't work: it doesn't specify
        the column to be inserted.
        """
        self.beginInsertColumns(QtCore.QModelIndex(), position, position)
        self.columns.insert(position, column)
        self.endInsertColumns()

    def replaceQueryColumn(self, position, new_column):
        old_column = self.columns[position]
        self.columns[position] = new_column
        self.dataChanged.emit(self.index(0, position),
                self.index(self.rowCount, position))
        self.headerDataChanged.emit(Qt.Horizontal, position, position)

    def sort(self, columnIndex, order=Qt.AscendingOrder):
        newClauses = [self.defaultSortClause]
        if columnIndex == -1:
            pass
        else:
            column = self.columns[columnIndex]
            descending = (order == Qt.DescendingOrder)
            sortClause = column.getSortClause(descending=descending)
            self.sortClauses.append(sortClause)

    def sortChanged(self):
        # Sorting's an expensive operation; if there are more resorts in a
        # single event loop iteration, only actually sort once
        self._sortChanged = True
        def resort():
            if not self._sortChanged:
                return
            self._sortChanged = False
            QtGui.QApplication.setOverrideCursor(QtGui.QCursor(Qt.WaitCursor))
            try:
                self.layoutAboutToBeChanged.emit()
                self._setQuery()
                self.layoutChanged.emit()
            finally:
                QtGui.QApplication.restoreOverrideCursor()
        QtCore.QTimer.singleShot(0, resort)
Esempio n. 4
0
class BaseQueryModel(QtCore.QAbstractItemModel):
    """A model that displays an ORM query, with a set of custom columns.

    Can be queried the Python way, (with []).
    """
    collapsingPossible = False
    _pagesize = 1000
    __metaclass__ = ModelMetaclass

    def __init__(self, g, mappedClass, query, columns, defaultSortClause=None):
        super(BaseQueryModel, self).__init__()
        self.g = g
        self.mappedClass = mappedClass
        self.g.registerRetranslate(self.allDataChanged)
        self.baseQuery = query
        self.columns = []
        for column in columns:
            try:
                self.columns.append(ModelColumn.load(column, model=self))
            except Exception:
                traceback.print_exc()
                print 'Failed to load column:', column
        if defaultSortClause is None:
            self.defaultSortClause = self.columns[0].getSortClause()
        else:
            self.defaultSortClause = defaultSortClause
        self.sortClauses = SortModel(self, [])
        self.sortClauses.rowsInserted.connect(self.sortChanged)
        self.sortClauses.rowsRemoved.connect(self.sortChanged)
        self.sortClauses.dataChanged.connect(self.sortChanged)
        self.filters = []
        self._setQuery()

    @property
    def allSortClauses(self):
        return (self.defaultSortClause, ) + tuple(self.sortClauses)

    def _setQuery(self):
        """Called every time the query changes"""
        builder = self.baseBuilder()
        for clause in reversed(self.allSortClauses):
            clause.sort(builder)
        self._query = builder.query
        self._rows = int(self._query.count())
        self.pages = [None] * (self._rows // self._pagesize + 1)

    def baseBuilder(self):
        """Return a QueryBuilder corresponding to the base query
        """
        return QueryBuilder(self.baseQuery, self.mappedClass)

    def dump(self):
        """Dump a simple representation of the data to stdout
        """
        for item in self:
            for column in self.columns:
                print column.data(item, None),
            print

    def allDataChanged(self):
        """Called when all of the data is changed, e.g. retranslated"""
        self._setQuery()
        self.dataChanged.emit(
            self.index(0, 0),
            self.index(self.rowCount() - 1,
                       self.columnCount() - 1),
        )
        self.headerDataChanged.emit(Qt.Horizontal, 0, self.columnCount() - 1)

    def __getitem__(self, i):
        pageno, offset = divmod(i, self._pagesize)
        page = self.pages[pageno]
        if not page:
            start = pageno * self._pagesize
            end = (pageno + 1) * self._pagesize
            page = self.pages[pageno] = self._query[start:end]
        return page[offset]

    def columnCount(self, parent=QtCore.QModelIndex()):
        return len(self.columns)

    def data(self, index, role=Qt.DisplayRole):
        item = self.itemForIndex(index)
        if item:
            return self.columns[index.column()].data(item, role)

    def itemForIndex(self, index):
        """Returns the item that corresponds to the given index"""
        if index.isValid() and not index.parent().isValid():
            return self[index.row()]

    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal:
            return self.columns[section].headerData(role, self)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            if 0 <= row < self.rowCount() and 0 <= column < self.columnCount():
                return self.createIndex(row, column)

    def rowCount(self, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            return self._rows
        else:
            return 0

    def parent(self, index):
        return QtCore.QModelIndex()

    def save(self):
        """Can't save a query directly"""
        raise AssertionError("Can't save a BaseQueryModel")

    def removeColumns(self, column, count, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            last = column + count - 1
            if column == 0:
                # Can't remove the first column
                column += 1
                last -= 1
                if column == last:
                    return False
            self.beginRemoveColumns(QtCore.QModelIndex(), column, last)
            del self.columns[column:last + 1]
            self.endRemoveColumns()
            return True

    def insertQueryColumn(self, position, column):
        """Insert a ModelColumn at the specified position

        Qt's normal column-inserting API doesn't work: it doesn't specify
        the column to be inserted.
        """
        self.beginInsertColumns(QtCore.QModelIndex(), position, position)
        self.columns.insert(position, column)
        self.endInsertColumns()

    def replaceQueryColumn(self, position, new_column):
        old_column = self.columns[position]
        self.columns[position] = new_column
        self.dataChanged.emit(self.index(0, position),
                              self.index(self.rowCount, position))
        self.headerDataChanged.emit(Qt.Horizontal, position, position)

    def sort(self, columnIndex, order=Qt.AscendingOrder):
        newClauses = [self.defaultSortClause]
        if columnIndex == -1:
            pass
        else:
            column = self.columns[columnIndex]
            descending = (order == Qt.DescendingOrder)
            sortClause = column.getSortClause(descending=descending)
            self.sortClauses.append(sortClause)

    def sortChanged(self):
        # Sorting's an expensive operation; if there are more resorts in a
        # single event loop iteration, only actually sort once
        self._sortChanged = True

        def resort():
            if not self._sortChanged:
                return
            self._sortChanged = False
            QtGui.QApplication.setOverrideCursor(QtGui.QCursor(Qt.WaitCursor))
            try:
                self.layoutAboutToBeChanged.emit()
                self._setQuery()
                self.layoutChanged.emit()
            finally:
                QtGui.QApplication.restoreOverrideCursor()

        QtCore.QTimer.singleShot(0, resort)