Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 1.9.2, 1.9.3, and 2.0

fileview: replace old annotator with our new annotation widget

This is going to need further work, but at least we won't have to explain how
the annotate feature in everything but the manifest widget is obsolete.

Changeset ce5bd1bafdf1

Parent 448add7dbf32

by Steve Borho

Changes to 5 files · Browse files at ce5bd1bafdf1 Showing diff from parent 448add7dbf32 Diff from another changeset...

 
139
140
141
142
 
143
144
145
 
139
140
141
 
142
143
144
145
@@ -139,7 +139,7 @@
  self.splitter = QSplitter(Qt.Vertical)   self.setCentralWidget(self.splitter)   self.repoview = HgRepoView(self.repo, self) - self.textView = HgFileView(self) + self.textView = HgFileView(self.repo, self)   self.splitter.addWidget(self.repoview)   self.splitter.addWidget(self.textView)  
 
30
31
32
33
 
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
 
95
96
97
98
 
 
 
 
 
 
 
 
 
 
99
100
101
 
132
133
134
 
 
 
135
 
 
136
137
138
139
140
141
 
172
173
174
175
176
 
 
 
 
 
 
 
 
177
178
179
 
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
 
268
269
270
271
272
273
274
275
276
277
278
279
 
281
282
283
284
 
 
 
 
285
286
287
 
303
304
305
306
 
307
308
309
 
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
 
400
401
402
403
 
 
 
404
405
406
 
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
 
 
440
441
442
 
30
31
32
 
33
34
35
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
38
39
 
44
45
46
 
47
48
49
50
51
52
53
54
55
56
57
58
59
 
90
91
92
93
94
95
96
97
98
99
 
 
100
101
102
 
133
134
135
 
 
136
137
138
139
140
141
142
143
144
145
146
 
152
153
154
 
 
 
 
 
155
156
157
158
159
 
 
 
 
160
161
162
 
226
227
228
 
 
 
 
 
 
229
230
231
 
233
234
235
 
236
237
238
239
240
241
242
 
258
259
260
 
261
262
263
264
 
270
271
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
274
 
275
276
277
 
333
334
335
 
336
337
338
339
340
341
 
360
361
362
 
 
363
 
 
 
 
 
 
 
 
 
364
365
366
367
368
@@ -30,61 +30,10 @@
   from tortoisehg.util import hglib, patchctx  from tortoisehg.hgqt.i18n import _ -from tortoisehg.hgqt import qscilib, qtlib, blockmatcher, lexers +from tortoisehg.hgqt import annotate, qscilib, qtlib, blockmatcher, lexers    qsci = Qsci.QsciScintilla   -class Annotator(qsci): - # we use a QScintilla for the annotater cause it makes - # it much easier to keep the text area and the annotater sync - # (same font rendering etc). However, it have the drawback of making much - # more difficult to implement things like QTextBrowser.anchorClicked, which - # would have been nice to directly go to the annotated revision... - def __init__(self, textarea, parent=None): - qsci.__init__(self, parent) - - self.setFrameStyle(0) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setReadOnly(True) - self.sizePolicy().setControlType(QSizePolicy.Slider) - self.setMinimumWidth(20) - self.setMaximumWidth(40) # XXX TODO make this computed - self.setFont(textarea.font()) - self.setMarginWidth(0, '') - self.setMarginWidth(1, '') - - self.SendScintilla(qsci.SCI_SETCURSOR, 2) - self.SendScintilla(qsci.SCI_SETCARETSTYLE, 0) - - # used to set a background color for every annotating rev - N = 32 - self.markers = [] - for i in range(N): - marker = self.markerDefine(qsci.Background) - color = 0x7FFF00 + (i-N/2)*256/N*256*256 - i*256/N*256 + i*256/N - self.SendScintilla(qsci.SCI_MARKERSETBACK, marker, color) - self.markers.append(marker) - - textarea.verticalScrollBar().valueChanged.connect( - self.verticalScrollBar().setValue) - - def setFilectx(self, fctx): - self.fctx = fctx - if fctx.rev() is None: - # the working context does not support annotate yet. I need to - # add that to Mercurial at some point. - self.setText('') - self.fctxann = [] - return - self.fctxann = [f for f, line in fctx.annotate(follow=True)] - revlist = [str(f.rev()) for f in self.fctxann] - self.setText('\n'.join(revlist)) - uniqrevs = list(sorted(set(revlist))) - for i, rev in enumerate(revlist): - idx = uniqrevs.index(rev) - self.markerAdd(i, self.markers[idx % len(self.markers)]) -  class HgFileView(QFrame):   """file diff and content viewer"""   @@ -95,7 +44,16 @@
  revForDiffChanged = pyqtSignal(int)   filled = pyqtSignal()   - def __init__(self, parent=None): + searchRequested = pyqtSignal(unicode) + """Emitted (pattern) when user request to search content""" + + editSelected = pyqtSignal(unicode, object, int) + """Emitted (path, rev, line) when user requests to open editor""" + + grepRequested = pyqtSignal(unicode, dict) + """Emitted (pattern, opts) when user request to search changelog""" + + def __init__(self, repo, parent):   QFrame.__init__(self, parent)   framelayout = QVBoxLayout(self)   framelayout.setContentsMargins(0,0,0,0) @@ -132,10 +90,13 @@
  framelayout.addLayout(self.topLayout)   framelayout.addLayout(l, 1)   + self._stacked = QStackedWidget() + l.addWidget(self._stacked, 1) +   self.sci = qscilib.Scintilla(self) + self._stacked.addWidget(self.sci) +   self.sci.setFrameStyle(0) - l.addWidget(self.sci, 1) - #self.sci.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)   self.sci.setReadOnly(True)   self.sci.setUtf8(True)   self.sci.installEventFilter(qscilib.KeyPressInterceptor(self)) @@ -172,8 +133,14 @@
  self.markertriangle = self.sci.markerDefine(qsci.Background)   self.sci.SendScintilla(qsci.SCI_MARKERSETBACK, self.markertriangle,   0xFFA0A0) - self.lastrev = None - self.sci.mouseMoveEvent = self.mouseMoveEvent + + self._annotate = annotate.AnnotateView(repo, self) + for name in ('searchRequested', 'editSelected', 'grepRequested'): + getattr(self._annotate, name).connect(getattr(self, name)) + self._annotate.revisionHint.connect(self.showMessage) + self._annotate.setAnnotationEnabled(True) + self._stacked.addWidget(self._annotate) + # self._annotate.sourceChanged.connect( ?? )     ll = QVBoxLayout()   ll.setContentsMargins(0, 0, 0, 0) @@ -185,20 +152,11 @@
  ll2.setSpacing(0)   ll.addLayout(ll2)   - # used to fill height of the horizontal scroll bar - w = QWidget(self) - ll.addWidget(w) - self._spacer = w -   self.blk = blockmatcher.BlockList(self)   self.blk.linkScrollBar(self.sci.verticalScrollBar())   ll2.addWidget(self.blk)   self.blk.setVisible(False)   - self.ann = Annotator(self.sci, self) - ll2.addWidget(self.ann) - self.ann.setVisible(False) -   self._ctx = None   self._filename = None   self._status = None @@ -268,12 +226,6 @@
  def saveSettings(self, qs, prefix):   self.sci.saveSettings(qs, prefix)   - def resizeEvent(self, event): - QFrame.resizeEvent(self, event) - h = self.sci.horizontalScrollBar().height() - self._spacer.setMinimumHeight(h) - self._spacer.setMaximumHeight(h) -   @pyqtSlot(QAction)   def setMode(self, action):   'One of the mode toolbar buttons has been toggled' @@ -281,7 +233,10 @@
  self.actionNextDiff.setEnabled(mode != 'diff')   self.actionPrevDiff.setEnabled(False)   self.blk.setVisible(mode != 'diff') - self.ann.setVisible(mode == 'ann') + if mode == 'ann': + self._stacked.setCurrentWidget(self._annotate) + else: + self._stacked.setCurrentWidget(self.sci)   if mode != self._mode:   self._mode = mode   if not self._lostMode: @@ -303,7 +258,7 @@
  self.actionNextDiff.setEnabled(False)   self.actionPrevDiff.setEnabled(False)   self.blk.setVisible(mode == 'file') - self.ann.setVisible(False) + self._stacked.setCurrentWidget(self.sci)     def setContext(self, ctx):   self._ctx = ctx @@ -315,30 +270,8 @@
  if rev != self._p_rev:   self.displayFile(rev=rev)   - def mouseMoveEvent(self, event): - if self._mode == 'ann' and self.ann.fctxann: - # Calculate row index from the scroll offset and mouse position - scroll_offset = self.sci.verticalScrollBar().value() - idx = scroll_offset + event.pos().y() / self.sci.textHeight(0) - # It's possible to scroll below the bottom line - if idx >= len(self.ann.fctxann): - idx = len(self.ann.fctxann) - 1 - ctx = self.ann.fctxann[idx] - rev = ctx.rev() - desc = hglib.get_revision_desc(ctx, self._filename) - if rev != self.lastrev: - self.showDescSignal.emit(desc) - self.lastrev = rev - qsci.mouseMoveEvent(self.sci, event) - - def leaveEvent(self, event): - if self._mode == 'ann': - self.lastrev = None - self.showDescSignal.emit('') -   def clearDisplay(self):   self.sci.clear() - self.ann.clear()   self.blk.clear()   # Setting the label to ' ' rather than clear() keeps the label   # from disappearing during refresh, and tool layouts bouncing @@ -400,7 +333,9 @@
  self.actionAnnMode.trigger()   self._lostMode = None   - if self._mode == 'diff': + if self._mode == 'ann': + self._annotate.setSource(filename, ctx.rev()) + elif self._mode == 'diff':   lexer = lexers.get_diff_lexer(self)   self.sci.setLexer(lexer)   # trim first three lines, for example: @@ -425,18 +360,9 @@
    uf = hglib.tounicode(self._filename)   self.fileDisplayed.emit(uf, fd.contents or QString()) - if self._mode == 'diff': - return   - if self._mode == 'ann': - if lexer is not None: - self.ann.setFont(lexer.font(0)) - else: - self.ann.setFont(self.sci.font()) - self.ann.setFilectx(self._ctx[filename]) - - # Update diff margin - if fd.contents and fd.olddata: + if self._mode == 'file' and fd.contents and fd.olddata: + # Update diff margin   if self.timer.isActive():   self.timer.stop()  
 
59
60
61
62
 
63
64
65
 
59
60
61
 
62
63
64
65
@@ -59,7 +59,7 @@
    self.queueFrame = QFrame(splitter)   self.messageFrame = QFrame(splitter) - self.fileview = fileview.HgFileView(splitter) + self.fileview = fileview.HgFileView(repo, splitter)     self.fileview.showMessage.connect(self.showMessage)   self.fileview.setContext(repo[None])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
 
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
 # repowidget.py - TortoiseHg repository widget  #  # Copyright (C) 2007-2010 Logilab. All rights reserved.  # Copyright (C) 2010 Adrian Buehlmann <adrian@cadifra.com>  #  # This software may be used and distributed according to the terms  # of the GNU General Public License, incorporated herein by reference.    from tortoisehg.hgqt.qtlib import getfont, geticon, descriptionhtmlizer  from tortoisehg.hgqt.i18n import _  from tortoisehg.hgqt.filelistmodel import HgFileListModel  from tortoisehg.hgqt.filelistview import HgFileListView  from tortoisehg.hgqt.fileview import HgFileView  from tortoisehg.hgqt.revpanel import RevPanelWidget  from tortoisehg.hgqt import thgrepo, qscilib    from PyQt4.QtCore import *  from PyQt4.QtGui import *    class RevDetailsWidget(QWidget):     showMessage = pyqtSignal(str)   linkActivated = pyqtSignal(unicode)     def __init__(self, repo):   QWidget.__init__(self)     self.repo = repo   self.splitternames = []     self._deschtmlize = descriptionhtmlizer(repo.ui)   repo.configChanged.connect(self._updatedeschtmlizer)     # these are used to know where to go after a reload   self._last_rev = None   self._reload_file = None     self.setupUi()   self.createActions()   self.setupModels()     self.fileview.setFont(getfont('fontdiff').font())   self.fileview.showMessage.connect(self.showMessage)   self.restoreSettings()     def setRepo(self, repo):   self.repo = repo     def setupUi(self):   SP = QSizePolicy   sp = SP(SP.Preferred, SP.Expanding)   sp.setHorizontalStretch(0)   sp.setVerticalStretch(0)   sp.setHeightForWidth(self.sizePolicy().hasHeightForWidth())   self.setSizePolicy(sp)     # + revisiondetails_layout -----------------------------------------+   # |+ filelist_splitter ........ |   # | + tbarFileListFrame (vbox)| + cset_and_file_details_frame (vbox)|   # | + diffToolbar | + revpanel |   # +---------------------------+-------------------------------------+   # | + filelist | + message_splitter |   # | | :+ message |   # | | :----------------------------------+   # | | + fileview |   # +---------------------------+-------------------------------------+   # |+ searchbar |   # +-----------------------------------------------------------------+     revisiondetails_layout = QVBoxLayout(self)   revisiondetails_layout.setSpacing(0)   revisiondetails_layout.setMargin(0)   revisiondetails_layout.setContentsMargins(2, 2, 2, 2)     self.filelist_splitter = QSplitter(self)   self.splitternames.append('filelist_splitter')     sp = SP(SP.Expanding, SP.Expanding)   sp.setHorizontalStretch(0)   sp.setVerticalStretch(0)   sp.setHeightForWidth(self.filelist_splitter.sizePolicy().hasHeightForWidth())   self.filelist_splitter.setSizePolicy(sp)   self.filelist_splitter.setOrientation(Qt.Horizontal)   self.filelist_splitter.setChildrenCollapsible(False)     self.mergeToolBar = QToolBar(_('Merge Toolbar'))   self.mergeToolBar.setIconSize(QSize(16,16))   self.filelist = HgFileListView()     self.tbarFileListFrame = QFrame(self.filelist_splitter)   sp = SP(SP.Preferred, SP.Preferred)   sp.setHorizontalStretch(3)   sp.setVerticalStretch(0)   sp.setHeightForWidth(   self.tbarFileListFrame.sizePolicy().hasHeightForWidth())   self.tbarFileListFrame.setSizePolicy(sp)   self.tbarFileListFrame.setFrameShape(QFrame.NoFrame)   vbox = QVBoxLayout()   vbox.setSpacing(0)   vbox.setMargin(0)   vbox.addWidget(self.mergeToolBar)   vbox.addWidget(self.filelist)   self.tbarFileListFrame.setLayout(vbox)     self.cset_and_file_details_frame = QFrame(self.filelist_splitter)   sp = SP(SP.Preferred, SP.Preferred)   sp.setHorizontalStretch(7)   sp.setVerticalStretch(0)   sp.setHeightForWidth(   self.cset_and_file_details_frame.sizePolicy().hasHeightForWidth())   self.cset_and_file_details_frame.setSizePolicy(sp)   self.cset_and_file_details_frame.setFrameShape(QFrame.NoFrame)     vbox = QVBoxLayout(self.cset_and_file_details_frame)   vbox.setSpacing(0)   vbox.setSizeConstraint(QLayout.SetDefaultConstraint)   vbox.setMargin(0)   cset_and_file_details_layout = vbox     self.message_splitter = QSplitter(self.cset_and_file_details_frame)   self.splitternames.append('message_splitter')   sp = SP(SP.Preferred, SP.Expanding)   sp.setHorizontalStretch(0)   sp.setVerticalStretch(0)   sp.setHeightForWidth(self.message_splitter.sizePolicy().hasHeightForWidth())   self.message_splitter.setSizePolicy(sp)   self.message_splitter.setMinimumSize(QSize(50, 50))   self.message_splitter.setFrameShape(QFrame.NoFrame)   self.message_splitter.setLineWidth(0)   self.message_splitter.setMidLineWidth(0)   self.message_splitter.setOrientation(Qt.Vertical)   self.message_splitter.setOpaqueResize(True)   self.message = QTextBrowser(self.message_splitter,   lineWrapMode=QTextEdit.NoWrap,   openLinks=False)   self.message.minimumSizeHint = lambda: QSize(0, 25)   self.message.anchorClicked.connect(   lambda url: self.linkActivated.emit(url.toString()))     sp = SP(SP.Expanding, SP.Expanding)   sp.setHorizontalStretch(0)   sp.setVerticalStretch(2)   sp.setHeightForWidth(self.message.sizePolicy().hasHeightForWidth())   self.message.setSizePolicy(sp)   self.message.setMinimumSize(QSize(0, 0))   f = getfont('fontcomment')   self.message.setFont(f.font())   f.changed.connect(lambda font: self.message.setFont(font))   - self.fileview = HgFileView(self.message_splitter) + self.fileview = HgFileView(self.repo, self.message_splitter)   sp = SP(SP.Expanding, SP.Expanding)   sp.setHorizontalStretch(0)   sp.setVerticalStretch(5)   sp.setHeightForWidth(self.fileview.sizePolicy().hasHeightForWidth())   self.fileview.setSizePolicy(sp)   self.fileview.setMinimumSize(QSize(0, 0))     self.revpanel = RevPanelWidget(self.repo)   self.revpanel.linkActivated.connect(self.linkActivated)     cset_and_file_details_layout.addWidget(self.revpanel)   cset_and_file_details_layout.addWidget(self.message_splitter)     revisiondetails_layout.addWidget(self.filelist_splitter)     self.searchbar = qscilib.SearchToolBar(hidable=True)   self.searchbar.hide()   self.searchbar.searchRequested.connect(self.fileview.find)   self.searchbar.conditionChanged.connect(self.fileview.highlightText)   revisiondetails_layout.addWidget(self.searchbar)   self.fileview.filled.connect(self._updateHighlightText)   self.filelist.fileRevSelected.connect(self._displayFile)   self.filelist.clearDisplay.connect(self.fileview.clearDisplay)     def createActions(self):   # Activate file (file diff navigator)   self.actionActivateFile = QAction('Activate file', self)   self.actionActivateFileAlt = QAction('Activate alt. file', self)   self.actionActivateFileAlt.setShortcuts([Qt.ALT+Qt.Key_Return,   Qt.ALT+Qt.Key_Enter])   self.actionActivateFileAlt.triggered.connect(   lambda self=self:   self.filelist.fileActivated(self.filelist.currentIndex(),   alternate=True))     @pyqtSlot()   def toggleSearchBar(self):   vis = self.searchbar.isVisible()   if vis:   self.searchbar.hide()   else:   self.searchbar.show()   self.searchbar.setFocus()     @pyqtSlot()   def _updateHighlightText(self):   if not self.searchbar.isVisible():   return   self.fileview.highlightText(self.searchbar.pattern(),   self.searchbar.caseInsensitive())     def create_models(self):   self.filelistmodel = HgFileListModel(self.repo, parent=self)     def setupModels(self):   self.create_models()   self.filelist.setModel(self.filelistmodel)     @pyqtSlot(object, object, object)   def _displayFile(self, file, rev, status):   self.fileview.displayFile(file, rev, status)   self._updateHighlightText()     def revision_selected(self, rev):   self._last_rev = rev   ctx = self.repo.changectx(rev)   self.revpanel.set_revision(rev)   self.revpanel.update(repo = self.repo)   self.message.setHtml('<pre>%s</pre>'   % self._deschtmlize(ctx.description()))   self.fileview.setContext(ctx)   self.filelistmodel.setContext(ctx)     @pyqtSlot()   def _updatedeschtmlizer(self):   self._deschtmlize = descriptionhtmlizer(self.repo.ui)   self.revision_selected(self._last_rev) # regenerate desc html     def record(self):   'Repo widget is reloading, record current file'   self._reload_file = self.filelist.currentFile()     def finishReload(self):   'Finish reload by re-selecting previous file'   if self._reload_file:   self.filelist.selectFile(self._reload_file)   elif not self.filelist.selectedIndexes():   self.filelist.selectRow(0)     def reload(self):   'Task tab is reloaded, or repowidget is refreshed'   if len(self.repo) <= self._last_rev:   self._last_rev = '.'   f = self.filelist.currentFile()   self.revision_selected(self._last_rev)   self.filelist.selectFile(f)     def storeSettings(self):   s = QSettings()   wb = "RevDetailsWidget/"   for n in self.splitternames:   s.setValue(wb + n, getattr(self, n).saveState())   s.setValue(wb + 'revpanel.expanded', self.revpanel.is_expanded())   self.fileview.saveSettings(s, 'revpanel/fileview')     def restoreSettings(self):   s = QSettings()   wb = "RevDetailsWidget/"   for n in self.splitternames:   getattr(self, n).restoreState(s.value(wb + n).toByteArray())   expanded = s.value(wb + 'revpanel.expanded', False).toBool()   self.revpanel.set_expanded(expanded)   self.fileview.loadSettings(s, 'revpanel/fileview')
 
168
169
170
171
 
172
173
174
 
168
169
170
 
171
172
173
174
@@ -168,7 +168,7 @@
  docf.setLayout(vbox)   self.docf = docf   - self.fileview = fileview.HgFileView(self) + self.fileview = fileview.HgFileView(self.repo, self)   self.fileview.showMessage.connect(self.showMessage)   self.fileview.linkActivated.connect(self.linkActivated)   self.fileview.fileDisplayed.connect(self.fileDisplayed)