[qt] refactorize: move tree graph drawing into a dedicated mixin

authoralain leufroy <alain@leufroy.fr>
changeset5c63ff427714
branchdefault
phasepublic
hiddenno
parent revision#c0ffd3ac12a9 [qt] refactorize: split graph node drawing into one method per node symbol
child revision#519b4a226b8c [qt4] persistent toolbar visibility (closes #109851), #4859c72b5d9b [qt4] persistent toolbar visibility (closes #109851), #b9aa413b46c5 [qt4] persistent toolbar visibility - remove configs (closes #109851)
files modified by this revision
hgviewlib/qt4/hgrepomodel.py
# HG changeset patch
# User alain leufroy <alain@leufroy.fr>
# Date 1365772435 -7200
# Fri Apr 12 15:13:55 2013 +0200
# Node ID 5c63ff4277144537011bb96806c46ca3b3456cc9
# Parent c0ffd3ac12a9582d53dd880ba26a718db53796d6
[qt] refactorize: move tree graph drawing into a dedicated mixin

diff --git a/hgviewlib/qt4/hgrepomodel.py b/hgviewlib/qt4/hgrepomodel.py
@@ -114,11 +114,133 @@
1          if result is not nullvariant:
2              self._datacache[(row, col, role)] = result
3          return result
4      return data
5 
6 -class HgRepoListModel(QAbstractTableModel, HgRepoListWalker):
7 +class GraphCtxMixin(object):
8 +    """A mixin that add a method to draw the tree."""
9 +    def draw_graph(self, ctx, gnode):
10 +        """
11 +        Draw the tree edges for the mercurial context ``ctx`` at the graph
12 +        node ``gnode``.
13 +
14 +        ..note:: ``ctx`` and ``gnode`` is quite redundant as
15 +                 ``ctx=self.repo.changectx(gnode.rev)``. But this avoids
16 +                 computing ``ctx`` twice.
17 +        """
18 +        pan = 2
19 +        w = self.col2x(gnode.cols, pan)
20 +        h = self.rowheight
21 +
22 +        pix = QPixmap(w, h)
23 +        pix.fill(QColor(0,0,0,0))
24 +        painter = QPainter(pix)
25 +        try:
26 +            self._draw_graph_ctx(painter, pix, ctx, gnode, pan)
27 +        finally:
28 +            painter.end()
29 +        return QVariant(pix)
30 +
31 +    def _draw_graph_ctx(self, painter, pix, ctx, gnode, pan):
32 +        h = pix.height()
33 +        radius = self.dot_radius
34 +        dot_x = self.col2x(gnode.x, pan)
35 +        dot_y = h / 2
36 +
37 +        painter.setRenderHint(QPainter.Antialiasing)
38 +
39 +        for y1, y2, lines in ((dot_y, dot_y + h, gnode.bottomlines),
40 +                              (dot_y - h, dot_y, gnode.toplines)):
41 +            for start, end, color, fill in lines:
42 +                x1 = self.col2x(start, pan) + radius / 2
43 +                x2 = self.col2x(end, pan) + radius / 2
44 +                color = QColor(self.get_color(color))
45 +                self._draw_graph_line(painter, x1, x2, y1, y2, color, not fill)
46 +
47 +        dot_color = QColor(self.namedbranch_color(ctx.branch()))
48 +        self._draw_graph_node(painter, dot_x, dot_y, radius, dot_color, ctx)
49 +
50 +    def _draw_graph_node(self, painter, x, y, r, color, ctx):
51 +        y -= r / 2 # middle -> border
52 +
53 +        tags = set(ctx.tags())
54 +        phase = ctx.phase()
55 +
56 +        if ctx.rev() is None:
57 +            # WD is displayed only if there are local
58 +            # modifications, so let's use the modified icon
59 +            self._draw_graph_node_modified(painter, x, y)
60 +        elif tags.intersection(self.mqueues):
61 +            self._draw_graph_node_mqpatch(painter, x, y)
62 +        elif phase == phases.draft:
63 +            self._draw_graph_node_draft(painter, x, y, r, color, ctx)
64 +        elif phase == phases.secret:
65 +            self._draw_graph_node_secret(painter, x, y, r, color, ctx)
66 +        else:
67 +            self._draw_graph_node_public(painter, x, y, r, color, ctx)
68 +
69 +    def _set_graph_node_style(self, painter, dot_color, ctx):
70 +        rev = ctx.rev()
71 +        dotcolor = QColor(dot_color)
72 +        if ctx.obsolete():
73 +            penradius = 1
74 +            pencolor = dotcolor.setAlpha(150)
75 +        elif rev in self.heads:
76 +            penradius = 2
77 +            pencolor = dotcolor.darker()
78 +        else:
79 +            penradius = 1
80 +            pencolor = Qt.black
81 +
82 +        if rev in self.wd_revs:
83 +            pen = QPen(Qt.red)
84 +            pen.setWidth(2)
85 +        else:
86 +            pen = QPen(pencolor)
87 +            pen.setWidth(1)
88 +        painter.setPen(pen)
89 +        painter.setBrush(dotcolor)        
90 +
91 +    @staticmethod
92 +    def _draw_graph_node_modified(painter, x, y):
93 +        geticon('modified').paint(painter, x - 5, y - 5, 17, 17)
94 +
95 +    @staticmethod
96 +    def _draw_graph_node_mqpatch(painter, x, y):
97 +        geticon('mqpatch').paint(painter, x - 5, y - 5, 17, 17)
98 +
99 +    def _draw_graph_node_public(self, painter, x, y, r, color, ctx):
100 +        if ctx.rev() in self.wd_revs:
101 +            geticon('clean').paint(painter, x - 5, y - 5, 17, 17)
102 +        else:
103 +            self._set_graph_node_style(painter, color, ctx)
104 +            painter.drawEllipse(x, y, r, r)
105 +
106 +    def _draw_graph_node_draft(self, painter, x, y, r, color, ctx):
107 +        self._set_graph_node_style(painter, color, ctx)
108 +        painter.drawRect(x, y, r, r)
109 +
110 +    def _draw_graph_node_secret(self, painter, x, y, r, color, ctx):
111 +        self._set_graph_node_style(painter, color, ctx)
112 +        painter.drawPolygon(
113 +            QPointF(x + (r // 2), y),
114 +            QPointF(x, y + r),
115 +            QPointF(x + r, y + r)
116 +        )
117 +        
118 +    @staticmethod
119 +    def _draw_graph_line(painter, x1, x2, y1, y2, color, isobsolete):
120 +        lpen = QPen(color)
121 +        if isobsolete:
122 +             lpen.setStyle(Qt.DotLine)
123 +             color.setAlpha(150)
124 +        lpen.setWidth(2)
125 +        painter.setPen(lpen)
126 +        painter.drawLine(x1, y1, x2, y2)
127 +
128 +
129 +class HgRepoListModel(QAbstractTableModel, HgRepoListWalker, GraphCtxMixin):
130      """
131      Model used for displaying the revisions of a Hg *local* repository
132      """
133      _allcolumns = ('ID', 'Branch', 'Log', 'Author', 'Date', 'Tags',)
134      _columns = ('ID', 'Branch', 'Log', 'Author', 'Date', 'Tags',)
@@ -259,131 +381,13 @@
135          elif role == Qt.DecorationRole:
136              if column != 'Log':
137                  return nullvariant
138              if not getattr(ctx, 'applied', True):
139                  return nullvariant
140 -            return self.graphctx(ctx, gnode)
141 +            return self.draw_graph(ctx, gnode)
142          return nullvariant
143 
144 -    def graphctx(self, ctx, gnode):
145 -        """
146 -        Draw the tree edges for the mercurial context ``ctx`` at the graph
147 -        node ``gnode``.
148 -
149 -        ..note:: ``ctx`` and ``gnode`` is quite redundant as
150 -                 ``ctx=self.repo.changectx(gnode.rev)``. But this avoids
151 -                 computing ``ctx`` twice.
152 -        """
153 -        pan = 2
154 -        w = self.col2x(gnode.cols, pan)
155 -        h = self.rowheight
156 -
157 -        pix = QPixmap(w, h)
158 -        pix.fill(QColor(0,0,0,0))
159 -        painter = QPainter(pix)
160 -        try:
161 -            self._drawgraphctx(painter, pix, ctx, gnode, pan)
162 -        finally:
163 -            painter.end()
164 -        return QVariant(pix)
165 -
166 -    def _drawgraphctx(self, painter, pix, ctx, gnode, pan):
167 -        h = pix.height()
168 -        radius = self.dot_radius
169 -        dot_x = self.col2x(gnode.x, pan)
170 -        dot_y = h / 2
171 -
172 -        painter.setRenderHint(QPainter.Antialiasing)
173 -
174 -        for y1, y2, lines in ((dot_y, dot_y + h, gnode.bottomlines),
175 -                              (dot_y - h, dot_y, gnode.toplines)):
176 -            for start, end, color, fill in lines:
177 -                x1 = self.col2x(start, pan) + radius / 2
178 -                x2 = self.col2x(end, pan) + radius / 2
179 -                color = QColor(self.get_color(color))
180 -                self._draw_graph_line(painter, x1, x2, y1, y2, color, not fill)
181 -
182 -        dot_color = QColor(self.namedbranch_color(ctx.branch()))
183 -        self._draw_graph_node(painter, dot_x, dot_y, radius, dot_color, ctx)
184 -
185 -    def _draw_graph_node(self, painter, x, y, r, color, ctx):
186 -        y -= r / 2 # middle -> border
187 -
188 -        tags = set(ctx.tags())
189 -        phase = ctx.phase()
190 -
191 -        if ctx.rev() is None:
192 -            # WD is displayed only if there are local
193 -            # modifications, so let's use the modified icon
194 -            self._draw_graph_node_modified(painter, x, y)
195 -        elif tags.intersection(self.mqueues):
196 -            self._draw_graph_node_mqpatch(painter, x, y)
197 -        elif phase == phases.draft:
198 -            self._draw_graph_node_draft(painter, x, y, r, color, ctx)
199 -        elif phase == phases.secret:
200 -            self._draw_graph_node_secret(painter, x, y, r, color, ctx)
201 -        else:
202 -            self._draw_graph_node_public(painter, x, y, r, color, ctx)
203 -
204 -    def _set_graph_node_style(self, painter, dot_color, ctx):
205 -        rev = ctx.rev()
206 -        dotcolor = QColor(dot_color)
207 -        if ctx.obsolete():
208 -            penradius = 1
209 -            pencolor = dotcolor.setAlpha(150)
210 -        elif rev in self.heads:
211 -            penradius = 2
212 -            pencolor = dotcolor.darker()
213 -        else:
214 -            penradius = 1
215 -            pencolor = Qt.black
216 -
217 -        if rev in self.wd_revs:
218 -            pen = QPen(Qt.red)
219 -            pen.setWidth(2)
220 -        else:
221 -            pen = QPen(pencolor)
222 -            pen.setWidth(1)
223 -        painter.setPen(pen)
224 -        painter.setBrush(dotcolor)        
225 -
226 -    @staticmethod
227 -    def _draw_graph_node_modified(painter, x, y):
228 -        geticon('modified').paint(painter, x - 5, y - 5, 17, 17)
229 -
230 -    @staticmethod
231 -    def _draw_graph_node_mqpatch(painter, x, y):
232 -        geticon('mqpatch').paint(painter, x - 5, y - 5, 17, 17)
233 -
234 -    def _draw_graph_node_public(self, painter, x, y, r, color, ctx):
235 -        if ctx.rev() in self.wd_revs:
236 -            geticon('clean').paint(painter, x - 5, y - 5, 17, 17)
237 -        else:
238 -            self._set_graph_node_style(painter, color, ctx)
239 -            painter.drawEllipse(x, y, r, r)
240 -
241 -    def _draw_graph_node_draft(self, painter, x, y, r, color, ctx):
242 -        self._set_graph_node_style(painter, color, ctx)
243 -        painter.drawRect(x, y, r, r)
244 -
245 -    def _draw_graph_node_secret(self, painter, x, y, r, color, ctx):
246 -        self._set_graph_node_style(painter, color, ctx)
247 -        painter.drawPolygon(
248 -            QPointF(x + (r // 2), y),
249 -            QPointF(x, y + r),
250 -            QPointF(x + r, y + r)
251 -        )
252 -        
253 -    @staticmethod
254 -    def _draw_graph_line(painter, x1, x2, y1, y2, color, isobsolete):
255 -        lpen = QPen(color)
256 -        if isobsolete:
257 -             lpen.setStyle(Qt.DotLine)
258 -             color.setAlpha(150)
259 -        lpen.setWidth(2)
260 -        painter.setPen(lpen)
261 -        painter.drawLine(x1, y1, x2, y2)
262 
263      def headerData(self, section, orientation, role):
264          if orientation == Qt.Horizontal and role == Qt.DisplayRole:
265              return QVariant(self._columns[section])
266          return nullvariant