[qt] mimic the curses layout by adding "description" to the files list (wip #83294)

Add a description entry in the file list that display the changeset description.

There only one text area on the bottom left that display the description OR a diff/source file.

authorAlain Leufroy <alain.leufroy@logilab.fr>
changeset68ab533747a4
branchdefault
phasepublic
hiddenno
parent revision#4017b4155c6a [TUI] phases support (closes #87899)
child revision#552064e111f8 [curses] improve signals patching (wip #92204)
files modified by this revision
hgviewlib/config.py
hgviewlib/qt4/hgfileview.py
hgviewlib/qt4/hgrepomodel.py
hgviewlib/qt4/hgrepoviewer.py
# HG changeset patch
# User Alain Leufroy <alain.leufroy@logilab.fr>
# Date 1327606970 -3600
# Thu Jan 26 20:42:50 2012 +0100
# Node ID 68ab533747a455db40fc8a6a6d056676118f5e78
# Parent 4017b4155c6a66287574fa6dd9aece97b5b0739e
[qt] mimic the curses layout by adding "description" to the files list (wip #83294)

Add a *description* entry in the file list that display the changeset
description.

There only one text area on the bottom left that display the
description OR a diff/source file.

diff --git a/hgviewlib/config.py b/hgviewlib/config.py
@@ -123,10 +123,26 @@
1                  else:
2                      users[currid][cmd] = val
3          return users, aliases
4 
5      @cached
6 +    def getFileDescriptionView(self, default='persistent'):
7 +        """
8 +        descriptionview:
9 +
10 +          :asfile: compact view with changeset description in the file list
11 +          :persistent: persistent view with changeset description always visible (default)
12 +        """
13 +        return self.ui.config(self.section, 'descriptionview', default).lower()
14 +
15 +    @cached
16 +    def getFileDescriptionColor(self, default='magenta'):
17 +        """
18 +        filedescriptioncolor: display color of the "description" entry
19 +        """
20 +        return self.ui.config(self.section, 'filedescriptioncolor', default)
21 +    @cached
22      def getFileModifiedColor(self, default='blue'):
23          """
24          filemodifiedcolor: display color of a modified file
25          """
26          return self.ui.config(self.section, 'filemodifiedcolor', default)
diff --git a/hgviewlib/qt4/hgfileview.py b/hgviewlib/qt4/hgfileview.py
@@ -531,10 +531,12 @@
27      def selectFile(self, filename):
28          self.setCurrentIndex(self.model().indexFromFile(filename))
29 
30      def fileActivated(self, index, alternate=False):
31          sel_file = self.model().fileFromIndex(index)
32 +        if sel_file is '':
33 +            return
34          if alternate:
35              self.navigate(sel_file)
36          else:
37              self.diffNavigate(sel_file)
38 
@@ -549,11 +551,11 @@
39 
40      def _navigate(self, filename, dlgclass, dlgdict):
41          if filename is None:
42              filename = self.currentFile()
43          model = self.model()
44 -        if filename is not None and len(model.repo.file(filename))>0:
45 +        if filename and len(model.repo.file(filename))>0:
46              if filename not in dlgdict:
47                  dlg = dlgclass(model.repo, filename,
48                                 repoviewer=self.window())
49                  dlgdict[filename] = dlg
50 
diff --git a/hgviewlib/qt4/hgrepomodel.py b/hgviewlib/qt4/hgrepomodel.py
@@ -387,10 +387,14 @@
51 
52  class HgFileListModel(QtCore.QAbstractTableModel):
53      """
54      Model used for listing (modified) files of a given Hg revision
55      """
56 +
57 +    _description_desc = dict(path='', flag='', desc='Display revision description',
58 +                             bfile=None, parent=None, fromside=None, infiles=False)
59 +
60      def __init__(self, repo, parent=None):
61          """
62          data is a HgHLRepo instance
63          """
64          QtCore.QAbstractTableModel.__init__(self, parent)
@@ -410,15 +414,17 @@
65          self.emit(SIGNAL('layoutChanged()'))
66 
67      def load_config(self):
68          cfg = HgConfig(self.repo.ui)
69          self._flagcolor = {}
70 -        self._flagcolor['='] = cfg.getFileModifiedColor(default='blue')
71 -        self._flagcolor['-'] = cfg.getFileRemovedColor(default='red')
72 -        self._flagcolor['-'] = cfg.getFileDeletedColor(default='red')
73 -        self._flagcolor['+'] = cfg.getFileAddedColor(default='green')
74 +        self._flagcolor['='] = cfg.getFileModifiedColor()
75 +        self._flagcolor['-'] = cfg.getFileRemovedColor()
76 +        self._flagcolor['-'] = cfg.getFileDeletedColor()
77 +        self._flagcolor['+'] = cfg.getFileAddedColor()
78 +        self._flagcolor[''] = cfg.getFileDescriptionColor()
79          self._displaydiff = cfg.getDisplayDiffStats()
80 +        self._descriptionview = cfg.getFileDescriptionView()
81 
82      def setDiffWidth(self, w):
83          if w != self.diffwidth:
84              self.diffwidth = w
85              self._datacache = {}
@@ -448,22 +454,21 @@
86 
87      def fileFromIndex(self, index):
88          if not index.isValid() or index.row()>=len(self) or not self.current_ctx:
89              return None
90          row = index.row()
91 +        file_info = self._files[row]
92          return self._files[row]['path']
93 
94      def revFromIndex(self, index):
95          if self._fulllist and ismerge(self.current_ctx):
96              if not index.isValid() or index.row()>=len(self) or not self.current_ctx:
97                  return None
98              row = index.row()
99 -            current_file_desc = self._files[row]
100 -            if current_file_desc['fromside'] == 'right':
101 +            if self._files[row]['fromside'] == 'right':
102                  return self.current_ctx.parents()[1].rev()
103 -            else:
104 -                return self.current_ctx.parents()[0].rev()
105 +            return self.current_ctx.parents()[0].rev()
106          return None
107 
108      def indexFromFile(self, filename):
109          if filename in self._filesdict:
110              row = self._files.index(self._filesdict[filename])
@@ -481,21 +486,19 @@
111          ctxfiles = ctx.files()
112          changes = self.repo.status(parent.node(), ctx.node())[:3]
113          modified, added, removed = changes
114          for lst, flag in ((added, '+'), (modified, '='), (removed, '-')):
115              for f in [x for x in lst if self._filterFile(x, ctxfiles)]:
116 -                _files.append({'path': f, 'flag': flag, 'desc': f,
117 +                descr = f
118 +                bfile = isbfile(f)
119 +                if bfile:
120 +                    desc = desc.replace('.hgbfiles'+os.sep, '')
121 +                _files.append({'path': f, 'flag': flag, 'desc': descr, 'bfile': bfile,
122                                 'parent': parent, 'fromside': fromside,
123                                 'infiles': f in ctxfiles})
124                  # renamed/copied files are handled by background
125                  # filling process since it can be a bit long
126 -        for fdesc in _files:
127 -            bfile = isbfile(fdesc['path'])
128 -            fdesc['bfile'] = bfile
129 -            if bfile:
130 -                fdesc['desc'] = fdesc['desc'].replace('.hgbfiles'+os.sep, '')
131 -
132          return _files
133 
134      def loadFiles(self):
135          self._fill_iter = None
136          self._files = []
@@ -504,10 +507,12 @@
137          if ismerge(self.current_ctx):
138              _paths = [x['path'] for x in self._files]
139              _files = self._buildDesc(self.current_ctx.parents()[1], 'right')
140              self._files += [x for x in _files if x['path'] not in _paths]
141          self._filesdict = dict([(f['path'], f) for f in self._files])
142 +        if self._descriptionview == 'asfile':
143 +            self._files.insert(0, self._description_desc)
144          self.fillFileStats()
145 
146      def setSelectedRev(self, ctx):
147          if ctx != self.current_ctx:
148              self.current_ctx = ctx
@@ -538,11 +543,14 @@
149          except StopIteration:
150              self._fill_iter = None
151 
152      def _fill(self):
153          # the generator used to fill file stats as a background process
154 -        for row, desc in enumerate(self._files):
155 +        files = enumerate(self._files)
156 +        if self._descriptionview == 'asfile':
157 +            files.next() # consume description entry
158 +        for row, desc in files:
159              filename = desc['path']
160              if desc['flag'] == '=' and self._displaydiff:
161                  try:
162                      diff = revdiff(self.repo, self.current_ctx, None, files=[filename])
163                      tot = self.current_ctx.filectx(filename).data().count('\n')
@@ -577,11 +585,10 @@
164      def data(self, index, role):
165          if not index.isValid() or index.row()>len(self) or not self.current_ctx:
166              return nullvariant
167          row = index.row()
168          column = index.column()
169 -
170          current_file_desc = self._files[row]
171          current_file = current_file_desc['path']
172          stats = current_file_desc.get('stats')
173          if column == 1:
174              if stats is not None:
@@ -623,17 +630,19 @@
175          elif column == 0:
176              if role in (QtCore.Qt.DisplayRole, QtCore.Qt.ToolTipRole):
177                  return QtCore.QVariant(current_file_desc['desc'])
178              elif role == QtCore.Qt.DecorationRole:
179                  if self._fulllist and ismerge(self.current_ctx):
180 +                    icn = None
181                      if current_file_desc['infiles']:
182                          icn = geticon('leftright')
183                      elif current_file_desc['fromside'] == 'left':
184                          icn = geticon('left')
185                      elif current_file_desc['fromside'] == 'right':
186                          icn = geticon('right')
187 -                    return QtCore.QVariant(icn.pixmap(20,20))
188 +                    if icn:
189 +                        return QtCore.QVariant(icn.pixmap(20,20))
190              elif role == QtCore.Qt.FontRole:
191                  if self._fulllist and current_file_desc['infiles']:
192                      font = QtGui.QFont()
193                      font.setBold(True)
194                      return QtCore.QVariant(font)
diff --git a/hgviewlib/qt4/hgrepoviewer.py b/hgviewlib/qt4/hgrepoviewer.py
@@ -381,16 +381,29 @@
195          self.tableView_revisions.setModel(self.repomodel)
196          self.tableView_filelist.setModel(self.filelistmodel)
197          self.textview_status.setModel(self.repomodel)
198          self.find_toolbar.setModel(self.repomodel)
199 
200 -        filetable = self.tableView_filelist
201 -        connect(filetable, SIGNAL('fileSelected'),
202 -                self.textview_status.displayFile)
203 +        if self.cfg.getFileDescriptionView() == 'asfile':
204 +            fileselcallback = self.displaySelectedFile
205 +        else:
206 +            fileselcallback = self.textview_status.displayFile
207 +        connect(self.tableView_filelist, SIGNAL('fileSelected'),
208 +                fileselcallback)
209 +
210          connect(self.textview_status, SIGNAL('revForDiffChanged'),
211                  self.textview_header.setDiffRevision)
212 
213 +    def displaySelectedFile(self, filename=None, rev=None):
214 +        if filename == '':
215 +            self.textview_status.hide()
216 +            self.textview_header.show()
217 +        else:
218 +            self.textview_header.hide()
219 +            self.textview_status.show()
220 +            self.textview_status.displayFile(filename, rev)
221 +
222      def setupRevisionTable(self):
223          view = self.tableView_revisions
224          view.installEventFilter(self)
225          connect(view, SIGNAL('revisionSelected'), self.revision_selected)
226          connect(view, SIGNAL('revisionActivated'), self.revision_activated)