[qt] move diff actions from toolbar to context menu and hide toolbar diff at startup (closes #87901)

  • remove actions from diff toolbar
  • remove diff toolbar
  • add action to the context menu of the text area
  • add icons
  • add config entry to display toolbar at startup
authorAlain Leufroy <alain.leufroy@logilab.fr>
changeset0f6fcebcd9cb
branchdefault
phasepublic
hiddenno
parent revision#78692ddfea30 [qt] add icon to "show/hide" hidden changesets action (wip #87901)
child revision#e0b63a609824 [qt] allow to pass node/rev/tag as link anchor (closes #87902)
files modified by this revision
hgviewlib/config.py
hgviewlib/qt4/hgfileview.py
hgviewlib/qt4/hgqv.qrc
hgviewlib/qt4/hgrepoviewer.py
hgviewlib/qt4/icons/README
hgviewlib/qt4/icons/diffmode.png
# HG changeset patch
# User Alain Leufroy <alain.leufroy@logilab.fr>
# Date 1336561403 -7200
# Wed May 09 13:03:23 2012 +0200
# Node ID 0f6fcebcd9cb4e5b0782ee8417b4bf0587964257
# Parent 78692ddfea30bd9d7a98086f2724ea29d27da406
[qt] move diff actions from toolbar to context menu and hide toolbar diff at startup (closes #87901)

* remove actions from diff toolbar
* remove diff toolbar
* add action to the context menu of the text area
* add icons
* add config entry to display toolbar at startup

diff --git a/hgviewlib/config.py b/hgviewlib/config.py
@@ -279,10 +279,17 @@
1          toolbarrev: show hidden changeset at startup
2          """
3          return bool(self.ui.config(self.section, 'toolbarrev', default))
4 
5      @cached
6 +    def getToolBarDiffAtStartup(self, default=True):
7 +        """
8 +        toolbardiff: show hidden changeset at startup
9 +        """
10 +        return bool(self.ui.config(self.section, 'toolbardiff', default))
11 +
12 +    @cached
13      def getContentAtStartUp(self, default=True):
14          """
15          contentatstartup: show the content of changeset at startup (bottom part)
16          """
17          return bool(self.ui.config(self.section, 'contentatstartup', default))
diff --git a/hgviewlib/qt4/hgfileview.py b/hgviewlib/qt4/hgfileview.py
@@ -89,10 +89,60 @@
18              idx = allrevs.index(rev)
19              self.markerAdd(i, self.markers[idx % len(self.markers)])
20 
21 
22 
23 +class HgQsci(qsci):
24 +
25 +    def __init__(self, *args, **kwargs):
26 +        super(HgQsci, self).__init__(*args, **kwargs)
27 +        self.createActions()
28 +
29 +    def _action_defs(self):
30 +        return [
31 +            ('selectall', self.tr("Select all"), None,
32 +             self.tr("Select all the text"), Qt.CTRL + Qt.Key_A,
33 +             self.selectAll),
34 +            ('copy', self.tr("Copy"), None, self.tr("Copy any selected text"),
35 +             Qt.CTRL + Qt.Key_C, self.copy),
36 +            ("diffmode", self.tr("Diff mode"), 'diffmode' ,
37 +             self.tr('Enable/Disable Diff mode'), None, None),
38 +            ("annmode", self.tr("Annotate mode"), None,
39 +             self.tr('Anable/Disable Annotatte mode'), None, None),
40 +            ("next", self.tr('Next hunk'), 'down', self.tr('Jump to the next hunk'),
41 +             Qt.ALT + Qt.Key_Down, None),
42 +            ("prev", self.tr('Prior hunk'), 'up', self.tr('Jump to the previous hunk'),
43 +             Qt.ALT + Qt.Key_Up, None),
44 +        ]
45 +
46 +    def createActions(self):
47 +        self._actions = {}
48 +        for name, desc, icon, tip, key, cb in self._action_defs():
49 +            act = QtGui.QAction(desc, self)
50 +            if icon:
51 +                act.setIcon(geticon(icon))
52 +            if tip:
53 +                act.setStatusTip(tip)
54 +            if key:
55 +                act.setShortcut(key)
56 +            if cb:
57 +                connect(act, SIGNAL('triggered()'), cb)
58 +            self._actions[name] = act
59 +            self.addAction(act)
60 +        self._actions['diffmode'].setCheckable(True)
61 +        self._actions['annmode'].setCheckable(True)
62 +
63 +    def contextMenuEvent(self, event):
64 +        menu = QtGui.QMenu(self)
65 +        for act in ['selectall', 'copy', None, 'diffmode', 'prev', 'next']:
66 +            if act:
67 +                menu.addAction(self._actions[act])
68 +            else:
69 +                menu.addSeparator()
70 +        self._actions['copy'].setEnabled(self.hasSelectedText())
71 +        menu.exec_(event.globalPos())
72 +
73  class HgFileView(QtGui.QFrame):
74      def __init__(self, parent=None):
75          QtGui.QFrame.__init__(self, parent)
76          framelayout = QtGui.QVBoxLayout(self)
77          framelayout.setContentsMargins(0,0,0,0)
@@ -114,11 +164,11 @@
78          self.topLayout.addWidget(self.execflaglabel)
79          self.execflaglabel.hide()
80          framelayout.addLayout(self.topLayout)
81          framelayout.addLayout(l, 1)
82 
83 -        self.sci = qsci(self)
84 +        self.sci = HgQsci(self)
85          self.sci.setFrameStyle(0)
86          l.addWidget(self.sci, 1)
87          self.sci.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
88          self.sci.setReadOnly(True)
89 
@@ -181,10 +231,19 @@
90 
91          self.timer = QtCore.QTimer()
92          self.timer.setSingleShot(False)
93          self.connect(self.timer, QtCore.SIGNAL("timeout()"),
94                       self.idle_fill_files)
95 +        self.connect(self.sci._actions['diffmode'], SIGNAL('toggled(bool)'),
96 +                     self.setMode)
97 +        self.connect(self.sci._actions['annmode'], SIGNAL('toggled(bool)'),
98 +                     self.setAnnotate)
99 +        self.connect(self.sci._actions['prev'], SIGNAL('triggered()'),
100 +                     self.prevDiff)
101 +        self.connect(self.sci._actions['next'], SIGNAL('triggered()'),
102 +                     self.nextDiff)
103 +        self.sci._actions['diffmode'].setChecked(True)
104 
105      def resizeEvent(self, event):
106          QtGui.QFrame.resizeEvent(self, event)
107          h = self.sci.horizontalScrollBar().height()
108          self._spacer.setMinimumHeight(h)
@@ -192,10 +251,14 @@
109 
110      def setMode(self, mode):
111          if isinstance(mode, bool):
112              mode = ['file', 'diff'][mode]
113          assert mode in ('diff', 'file')
114 +
115 +        self.sci._actions['annmode'].setEnabled(not mode)
116 +        self.sci._actions['next'].setEnabled(not mode)
117 +        self.sci._actions['prev'].setEnabled(not mode)
118          if mode != self._mode:
119              self._mode = mode
120              self.blk.setVisible(self._mode == 'file')
121              self.ann.setVisible(self._mode == 'file' and self._annotate)
122 
@@ -292,11 +355,11 @@
123          self.filenamelabel.setText(labeltxt)
124 
125          self.sci.setText(data)
126          if self._find_text:
127              self.highlightSearchString(self._find_text)
128 -        self.emit(SIGNAL('fileDisplayed'), self._filename)
129 +        self.sci._actions['prev'].setEnabled(False)
130          self.updateDiffDecorations()
131          if self._mode == 'file' and self._annotate:
132              if filectx.rev() is None: # XXX hide also for binary files
133                  self.ann.setVisible(False)
134              else:
@@ -336,11 +399,11 @@
135                                                       filedata,)
136                  self._diffs = []
137                  self.blk.syncPageStep()
138                  self.timer.start()
139 
140 -    def nextDiff(self):
141 +    def _nextDiff(self):
142          if self._mode == 'file':
143              row, column = self.sci.getCursorPosition()
144              for i, (lo, hi) in enumerate(self._diffs):
145                  if lo > row:
146                      last = (i == (len(self._diffs)-1))
@@ -349,11 +412,16 @@
147                  return False
148              self.sci.setCursorPosition(lo, 0)
149              self.sci.verticalScrollBar().setValue(lo)
150              return not last
151 
152 -    def prevDiff(self):
153 +    def nextDiff(self):
154 +        notlast = self._nextDiff()
155 +        self.sci._actions['next'].setEnabled(self.fileMode() and notlast and self.nDiffs())
156 +        self.sci._actions['prev'].setEnabled(self.fileMode() and self.nDiffs())
157 +
158 +    def _prevDiff(self):
159          if self._mode == 'file':
160              row, column = self.sci.getCursorPosition()
161              for i, (lo, hi) in enumerate(reversed(self._diffs)):
162                  if hi < row:
163                      first = (i == (len(self._diffs)-1))
@@ -362,10 +430,17 @@
164                  return False
165              self.sci.setCursorPosition(lo, 0)
166              self.sci.verticalScrollBar().setValue(lo)
167              return not first
168 
169 +    def prevDiff(self):
170 +        notfirst = self._prevDiff()
171 +        self.sci._actions['prev'].setEnabled(self.fileMode() and notfirst and self.nDiffs())
172 +        self.sci._actions['next'].setEnabled(self.fileMode() and self.nDiffs())
173 +
174 +
175 +
176      def nextLine(self):
177          x, y = self.sci.getCursorPosition()
178          self.sci.setCursorPosition(x+1, y)
179 
180      def prevLine(self):
@@ -441,11 +516,11 @@
181          self.blk.setUpdatesEnabled(False)
182          for n in range(30): # burst pool
183              if self._diff is None or not self._diff.get_opcodes():
184                  self._diff = None
185                  self.timer.stop()
186 -                self.emit(SIGNAL('filled'))
187 +                self.sci._actions['next'].setEnabled(self.fileMode() and self.nDiffs())
188                  break
189 
190              tag, alo, ahi, blo, bhi = self._diff.get_opcodes().pop(0)
191              if tag == 'replace':
192                  self._diffs.append([blo, bhi])
diff --git a/hgviewlib/qt4/hgqv.qrc b/hgviewlib/qt4/hgqv.qrc
@@ -20,7 +20,8 @@
193      <file>icons/mqpatch.svg</file>
194      <file>icons/mqpatch_x.svg</file>
195      <file>icons/showhide.png</file>
196      <file>icons/content.png</file>
197      <file>icons/unfilter.png</file>
198 +    <file>icons/diffmode.png</file>
199    </qresource>
200  </RCC>
diff --git a/hgviewlib/qt4/hgrepoviewer.py b/hgviewlib/qt4/hgrepoviewer.py
@@ -75,12 +75,10 @@
201          connect(self.tableView_revisions, SIGNAL('showMessage'),
202                  self.statusBar().showMessage)
203 
204          # setup tables and views
205          self.setupHeaderTextview()
206 -        connect(self.textview_status, SIGNAL('fileDisplayed'),
207 -                self.file_displayed)
208          self.setupBranchCombo()
209          self.setupModels(fromhead)
210          if fromhead:
211              self.startrev_entry.setText(str(fromhead))
212          self.setupRevisionTable()
@@ -142,11 +140,13 @@
213          findaction = self.find_toolbar.toggleViewAction()
214          findaction.setIcon(geticon('find'))
215          self.toolBar_edit.addAction(findaction)
216 
217          # tree filters toolbar
218 +        self.toolBar_treefilters.addAction(self.actionShowHidden)
219          self.toolBar_treefilters.addAction(self.tableView_revisions._actions['unfilter'])
220 +        self.toolBar_treefilters.addAction(self.actionShowHidden)
221 
222          self.branch_label = QtGui.QToolButton()
223          self.branch_label.setText("Branch")
224          self.branch_label.setStatusTip("Display graph the named branch only")
225          self.branch_label.setPopupMode(QtGui.QToolButton.InstantPopup)
@@ -163,12 +163,10 @@
226 
227          self.toolBar_treefilters.layout().setSpacing(3)
228 
229          self.branch_label_action = self.toolBar_treefilters.addWidget(self.branch_label)
230          self.branch_comboBox_action = self.toolBar_treefilters.addWidget(self.branch_comboBox)
231 -        # hidden changeset action
232 -        self.toolBar_treefilters.addAction(self.actionShowHidden)
233          # separator
234          self.toolBar_treefilters.addSeparator()
235 
236          self.startrev_label = QtGui.QToolButton()
237          self.startrev_label.setText("Start rev.")
@@ -194,14 +192,14 @@
238 
239          self.startrev_label_action = self.toolBar_treefilters.addWidget(self.startrev_label)
240          self.startrev_entry_action = self.toolBar_treefilters.addWidget(self.startrev_entry)
241 
242          # diff mode toolbar
243 -        self.toolBar_diff.addAction(self.actionDiffMode)
244 -        self.toolBar_diff.addAction(self.actionAnnMode)
245 -        self.toolBar_diff.addAction(self.actionNextDiff)
246 -        self.toolBar_diff.addAction(self.actionPrevDiff)
247 +        actions = self.textview_status.sci._actions
248 +        for action_name in ('diffmode', 'prev', 'next'):
249 +            self.toolBar_diff.addAction(actions[action_name])
250 +        self.toolBar_diff.setVisible(self.cfg.getToolBarDiffAtStartup())
251 
252          # rev mod toolbar
253          if self.textview_header.rst_action is not None:
254              self.toolBar_rev.addAction(self.textview_header.rst_action)
255          self.toolBar_rev.setVisible(self.cfg.getToolBarRevAtStartup())
@@ -215,20 +213,10 @@
256          connect(self.actionQuit, SIGNAL('triggered()'),
257                  self.close)
258          self.actionQuit.setIcon(geticon('quit'))
259          self.actionRefresh.setIcon(geticon('reload'))
260 
261 -        self.actionDiffMode = QtGui.QAction('Diff mode', self)
262 -        self.actionDiffMode.setCheckable(True)
263 -        connect(self.actionDiffMode, SIGNAL('toggled(bool)'),
264 -                self.setMode)
265 -
266 -        self.actionAnnMode = QtGui.QAction('Annotate', self)
267 -        self.actionAnnMode.setCheckable(True)
268 -        connect(self.actionAnnMode, SIGNAL('toggled(bool)'),
269 -                self.textview_status.setAnnotate)
270 -
271          self.actionHelp.setShortcut(Qt.Key_F1)
272          self.actionHelp.setIcon(geticon('help'))
273          connect(self.actionHelp, SIGNAL('triggered()'),
274                  self.on_help)
275 
@@ -250,21 +238,10 @@
276          self.actionShowMainContent.setStatusTip(tip)
277          self.actionShowMainContent.setShortcut(Qt.Key_Space)
278          connect(self.actionShowMainContent, SIGNAL('triggered()'),
279                  self.toggleMainContent)
280 
281 -        # Next/Prev diff (in full file mode)
282 -        self.actionNextDiff = QtGui.QAction(geticon('down'), 'Next diff', self)
283 -        self.actionNextDiff.setShortcut('Alt+Down')
284 -        self.actionPrevDiff = QtGui.QAction(geticon('up'), 'Previous diff', self)
285 -        self.actionPrevDiff.setShortcut('Alt+Up')
286 -        connect(self.actionNextDiff, SIGNAL('triggered()'),
287 -                self.nextDiff)
288 -        connect(self.actionPrevDiff, SIGNAL('triggered()'),
289 -                self.prevDiff)
290 -        self.actionDiffMode.setChecked(True)
291 -
292          # Next/Prev file
293          self.actionNextFile = QtGui.QAction('Next file', self)
294          self.actionNextFile.setShortcut('Right')
295          connect(self.actionNextFile, SIGNAL('triggered()'),
296                  self.tableView_filelist.nextFile)
@@ -343,23 +320,10 @@
297          if visible:
298              self.revision_selected(-1)
299 
300      def setMode(self, mode):
301          self.textview_status.setMode(mode)
302 -        self.actionAnnMode.setEnabled(not mode)
303 -        self.actionNextDiff.setEnabled(not mode)
304 -        self.actionPrevDiff.setEnabled(not mode)
305 -
306 -    def nextDiff(self):
307 -        notlast = self.textview_status.nextDiff()
308 -        self.actionNextDiff.setEnabled(self.textview_status.fileMode() and notlast and self.textview_status.nDiffs())
309 -        self.actionPrevDiff.setEnabled(self.textview_status.fileMode() and self.textview_status.nDiffs())
310 -
311 -    def prevDiff(self):
312 -        notfirst = self.textview_status.prevDiff()
313 -        self.actionPrevDiff.setEnabled(self.textview_status.fileMode() and notfirst and self.textview_status.nDiffs())
314 -        self.actionNextDiff.setEnabled(self.textview_status.fileMode() and self.textview_status.nDiffs())
315 
316      def load_config(self):
317          cfg = HgDialogMixin.load_config(self)
318          self.hidefinddelay = cfg.getHideFindDelay()
319 
@@ -466,16 +430,10 @@
320              rev = self.tableView_revisions.current_rev
321          self.toggleMainContent(True)
322          self._manifestdlg = ManifestViewer(self.repo, rev)
323          self._manifestdlg.show()
324 
325 -    def file_displayed(self, filename):
326 -        self.actionPrevDiff.setEnabled(False)
327 -        connect(self.textview_status, SIGNAL('filled'),
328 -                lambda self=self: self.actionNextDiff.setEnabled(self.textview_status.fileMode() \
329 -                                                                 and self.textview_status.nDiffs()))
330 -
331      def revision_selected(self, rev):
332          """
333          Callback called when a revision is selected in the revisions table
334          if rev == -1: refresh the current selected revision
335          """
diff --git a/hgviewlib/qt4/icons/README b/hgviewlib/qt4/icons/README
@@ -1,6 +1,6 @@
336  Most of the icons used here are from the Tango Icon Theme. Some of them have been modified.
337 
338  showhide.png: Gnome Project (GPL)
339 -content.png: by PC (Creative Common)
340 -
341 +content.png: by PC (Creative Common v3)
342 +diffmode.png: by FatCow (Creative Common v3)
343  unfilter.png: Everaldo Coelho (GPL)
344 \ No newline at end of file
diff --git a/hgviewlib/qt4/icons/diffmode.png b/hgviewlib/qt4/icons/diffmode.png