Staging
v0.5.0
https://foss.heptapod.net/mercurial/hgview
Raw File
Tip revision: 6b70062505a2d3001f5208161f8a68694534505c authored by David Douard on 30 May 2012, 10:09:40 UTC
close 0.x
Tip revision: 6b70062
hgrepomodel.py
import sys
from PyQt4 import QtCore, QtGui
connect = QtCore.QObject.connect
    
class HgRepoListModel(QtCore.QAbstractTableModel):
    def __init__(self, data, parent=None):
        """
        data is a HgHLRepo instance
        """
        QtCore.QAbstractTableModel.__init__(self,parent)
        self.repo = data
        self.graph = None
        self.__len = 0
        self.__cache = {} 
        self.dot_radius = 8

    def set_graph(self, graph):
        self.graph = graph
        self.compute_len()
        
    def compute_len(self):
        if self.graph:
            self.__len = len(filter(None, self.graph.rows))
        else:
            self.__len = 0

    def __len__(self):
        if self.graph:
            return len(filter(None, self.graph.rows))
        return 0
        print "len = ", self.__len
        return self.__len
    
    def rowCount(self, parent):
        return len(self)

    def columnCount(self, parent):
        return 4

    def data(self, index, role):
        if not index.isValid() or self.graph is None:
            return QtCore.QVariant()
        row = index.row()
        column = index.column()
        node = self.graph.rows[row]
        
        if node is None:
            return  QtCore.QVariant()
        idx = (row, column, role)
        if idx in self.__cache:
            return self.__cache[idx]

        rev_node = self.repo.read_node(node)

        if role == QtCore.Qt.DisplayRole:
            item = QtCore.QVariant(self.getData(row, index.column()))
            self.__cache[idx] = item
            return item
        elif role == QtCore.Qt.ForegroundRole:
            if column == 2: #author
                color = self.repo.colors[rev_node.author_id]
                color = QtCore.QVariant(QtGui.QColor(color))
                self.__cache[idx]=color
                return color
            
        elif role == QtCore.Qt.DecorationRole:
            if column == 1:
                
                node_x = self.graph.x[node]
                lines = self.graph.rowlines[row]

                xmax = self.graph.rownlines[row]
                w = (xmax)*(1*self.dot_radius + 0) + 2
                h = 30 # ? how to get it
                
                dot_x = (1*self.dot_radius + 0) * node_x + self.dot_radius/2
                dot_y = (h/2)-self.dot_radius/2
                tags = rev_node.tags
                if isinstance(tags, (list, tuple)):
                    tags = ", ".join(tags)
                tags = tags.strip()
                font = QtGui.QFont()
                font.setPointSize(font.pointSize()*0.8)
                fontmetric = QtGui.QFontMetrics(font)
                tag_rect = fontmetric.boundingRect(tags)
                tag_w = tag_rect.width()
                tag_h = tag_rect.height()
                
                pix = QtGui.QPixmap(w+tag_w+4, h)
                pix.fill(QtGui.QColor(0,0,0,0))
                painter = QtGui.QPainter(pix)
                painter.setRenderHint(QtGui.QPainter.Antialiasing)

                pen = QtGui.QPen(QtCore.Qt.blue)
                pen.setWidth(2)
                painter.setPen(pen)

                for color_src_node, x1, y1, x2, y2 in lines:
                    # x y are expressed here in terms of colums (in the graph)
                    # and row (in the list)
                    color = self.graph.colors.get(color_src_node, "black")
                    lpen = QtGui.QPen(pen)
                    lpen.setColor(QtGui.QColor(color))
                    painter.setPen(lpen)
                        
                    x1 = (1*self.dot_radius + 0) * x1  + self.dot_radius
                    x2 = (1*self.dot_radius + 0) * x2  + self.dot_radius
                    y1 = (y1 - row)*h + h/2
                    y2 = (y2 - row)*h + h/2
                    painter.drawLine(x1, y1, x2, y2)

                if tags:
                    dot_color = "yellow"
                else:
                    dot_color = "gray"
                    
                painter.setBrush(QtGui.QColor(dot_color))
                painter.setPen(QtCore.Qt.black)
                painter.drawEllipse(dot_x, dot_y, self.dot_radius, self.dot_radius)
                if tags:
                    painter.setBrush(QtCore.Qt.yellow)
                    painter.drawRect(w, 2, tag_w+4, tag_h+2)
                    
                    painter.setFont(font)
                    painter.drawText(w+2, tag_h-1, tags)
                
                painter.end()
                ret = QtCore.QVariant(pix)
                self.__cache[idx] = ret
                return ret
        return QtCore.QVariant()

    def headerData(self, section, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(['ID','Log','Author','Date'][section])

        return QtCore.QVariant()

    def getData(self, row, column):
        #print "gatData", row, column
        rev_node = self.repo.read_node(self.graph.rows[row])
        if column == 0:
            data = rev_node.rev
        elif column == 1:
            data = rev_node.short
        elif column == 2:
            data = self.repo.authors[rev_node.author_id]
        elif column == 3:
            data = rev_node.date
        else:
            data = ""
        return data

    def row_from_node(self, node):
        try:
            return self.graph.rows.index(node)
        except ValueError:
            return None
    
    def clear(self):
        """empty the list"""
        self.graph = None
        self.__len = 0
        self.__cache = {}
        self.notify_data_changed()

    def notify_data_changed(self):
        self.compute_len()
        self.emit(QtCore.SIGNAL("layoutChanged()"))

class HgFileListModel(QtCore.QAbstractTableModel):
    def __init__(self, repo, graph, parent=None):
        """
        data is a HgHLRepo instance
        """
        QtCore.QAbstractTableModel.__init__(self,parent)
        self.repo = repo
        self.stats = [] # list of couples (n_line_added, n_line_removed),
                        # one for each file 
        self.current_node = None
        self.connect(self, QtCore.SIGNAL("dataChanged(const QModelIndex & , const QModelIndex & )"),
                     self.datachangedcalled)

    def __len__(self):
        if self.current_node:
            rev_node = self.repo.read_node(self.current_node)
            n = len(rev_node.files)
            if n > 0:
                return n+1
        return 0
    
    def datachangedcalled(self, fr, to):
        print "datachangedcalled"
    def rowCount(self, parent):
        return len(self)

    def columnCount(self, parent):
        return 2

    def setSelectedNode(self, node, stats):
        self.current_node = node
        #assert len(self.repo.read_node(node).files) == len(stats)
        self.stats = stats
        if self.stats:
            self.statmax = max([sum(x) for x in self.stats.values()])
        else:
            self.statmax = 0
        
        self.emit(QtCore.SIGNAL("layoutChanged()"))

    def data(self, index, role):
        if not index.isValid() or index.row()>len(self) or not self.current_node:
            return QtCore.QVariant()
        row = index.row()
        column = index.column()

        current_file = self.repo.read_node(self.current_node).files[index.row()-1]
        stats = self.stats.get(current_file)
        if role == QtCore.Qt.DisplayRole:
            if column == 0:
                if row == 0:
                    return QtCore.QVariant("Content")
                else:
                    return QtCore.QVariant(current_file)
            elif column == 1:
                if row == 0 or stats is None:
                    return QtCore.QVariant("")
                else:
                    return QtCore.QVariant("+%s | -%s"%tuple(stats))
                
        if role == QtCore.Qt.DecorationRole:
            if column == 1:
                if row == 0 or stats is None:
                    return QtCore.QVariant()

                w = 100 # ? how to get it
                h = 20 

                np = int(w*stats[0]/self.statmax)
                nm = int(w*stats[1]/self.statmax)
                nd = w-np-nm

                pix = QtGui.QPixmap(w+10, h)
                pix.fill(QtGui.QColor(0,0,0,0))
                painter = QtGui.QPainter(pix)
                #painter.setRenderHint(QtGui.QPainter.Antialiasing)

                for x0,w0, color in ((0,nm, 'red'), (nm,np, 'green'),
                                    (nm+np, nd, 'gray')):
                    color = QtGui.QColor(color)
                    painter.setBrush(color)
                    painter.setPen(color)
                    painter.drawRect(x0+5,5,w0, h-5)
                painter.setBrush(QtGui.QColor(0,0,0,0))
                pen = QtGui.QPen(QtCore.Qt.black)
                pen.setWidth(0)
                painter.setPen(pen)
                painter.drawRect(5,5,w+2,h-6)
                painter.end()
                return QtCore.QVariant(pix)
        return QtCore.QVariant()

    def headerData(self, section, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(['File','Diff'][section])

        return QtCore.QVariant()

        
if __name__ == "__main__":
    from hgview.hgrepo import HgHLRepo
    app = QtGui.QApplication(sys.argv)

    repo = HgHLRepo(".")
    model = HgRepoListModel(repo)
        
    view = QtGui.QTableView()
    #delegate = GraphDelegate()
    #view.setItemDelegateForColumn(1, delegate)
    view.setShowGrid(False)
    view.verticalHeader().hide()
    view.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
    view.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
    view.setModel(model)
    view.setWindowTitle("Simple Hg List Model")
    view.show()
    view.setAlternatingRowColors(True)
    view.resizeColumnsToContents()
    sys.exit(app.exec_())
back to top