Merge lp:~abudden/qbzr/tab-width-on-view-menu into lp:qbzr

Proposed by Dr Al
Status: Merged
Approved by: Alexander Belchenko
Approved revision: 1375
Merge reported by: Dr Al
Merged at revision: not available
Proposed branch: lp:~abudden/qbzr/tab-width-on-view-menu
Merge into: lp:qbzr
Diff against target: 375 lines (+207/-22)
7 files modified
NEWS.txt (+6/-2)
lib/annotate.py (+10/-2)
lib/config.py (+2/-2)
lib/diffwindow.py (+62/-4)
lib/util.py (+41/-12)
lib/widgets/__init__.py (+1/-0)
lib/widgets/tab_width_selector.py (+85/-0)
To merge this branch: bzr merge lp:~abudden/qbzr/tab-width-on-view-menu
Reviewer Review Type Date Requested Status
Alexander Belchenko Needs Fixing
Review via email: mp+59334@code.launchpad.net

Description of the change

> Hi Alan,
>
> I've just thought that you may want to add support to change Tab Width directly for GUI: via View Options menu on toolbar (in qdiff and qannotate) similar to encoding change, if you like. You don't have to though. That's just a thought.

Implemented in this branch.

To post a comment you must log in.
Revision history for this message
Alexander Belchenko (bialix) wrote :

You need to update your NEWS changes to 0.20b2 cycle now.

Also, I wonder why don't you want to save the changed value in corresponding branch.conf as encoding selector does? See get_set_encoding() function in util.py as reference (but please use the latest revision from lp:qbzr).

Revision history for this message
Alexander Belchenko (bialix) :
review: Needs Fixing
1370. By Dr Al

Merged latest trunk.

1371. By Dr Al

Store custom tab width in branch.conf if it is changed in annotate or diff window.

Revision history for this message
Dr Al (abudden) wrote :

NEWS moved and branch.conf saving implemented.

Revision history for this message
Alexander Belchenko (bialix) wrote :

Your both util functions are extended to get aditional parameter tab_width, but their signatures different:

def get_set_tab_width_chars(tab_width=None, branch=None):
vs
def get_tab_width_pixels(branch=None, tab_width_chars=None):

As I undersstand in both cases you might pass optional tab_width in chars. I think we should use the same order of arguments in both functions to reduce the possible mistakes in usage of that API. I'm asking you for consistency between those 2 functions. Can you fix this please?

1372. By Dr Al

Changed parameter order in get_set_tab_width_chars to match that of get_set_tab_width_pixels.

1373. By Dr Al

Expanded docstrings describing utility function usage.

Revision history for this message
Dr Al (abudden) wrote :

Fixed. I've also put more explanation into the docstrings since they're util functions.

Revision history for this message
Alexander Belchenko (bialix) wrote :

Thanks for descriptive docstring.

Revision history for this message
Alexander Belchenko (bialix) wrote :

Okay, we need couple of small fixes there.

1) Please put the new file under lib/widgets/ subdirectory (it does not exist yet in trun, so add it). I've long imagined how to improve qbzr internal modules layout. So let's start with it. See https://bugs.launchpad.net/qbzr/+bug/420757 for refrence.

2) It seems the import of from bzrlib.plugins.qbzr.lib.util import get_tab_width_pixels is unneeded in tab_width_selector.py. Remove it.

Otherwise it's fine for me.

review: Needs Fixing
1374. By Dr Al

Merge trunk

1375. By Dr Al

Removed redundant import and moved tab width selector into widgets subdirectory.

Revision history for this message
Dr Al (abudden) wrote :

Okay, that's done.

Revision history for this message
Alexander Belchenko (bialix) wrote :

Dr Al пишет:
> Okay, that's done.
You should fix the imports in the modules that requires new TabSelector.
Also, please keep 2 blank lines between NEWS groups for different releases.

Othewrwise, I'm fine with that. Please land.

--
All the dude wanted was his rug back

Revision history for this message
Alexander Belchenko (bialix) :
review: Needs Fixing
Revision history for this message
Dr Al (abudden) wrote :

Fixed the imports (oops) and re-added blank lines. I can't land this.

1376. By Dr Al

Fixed imports and re-added blank line to news.

Revision history for this message
Dr Al (abudden) wrote :

Merged.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.txt'
2--- NEWS.txt 2011-05-03 09:21:56 +0000
3+++ NEWS.txt 2011-05-11 11:51:06 +0000
4@@ -5,6 +5,10 @@
5 * Fixed problem with viewing file from qbrowse.
6 (Alexander Belchenko, Bug #776196)
7
8+ * qdiff, qannotate:
9+ Tab-width can be customised from the view menu.
10+ (Bug #490377, A. S. Budden)
11+
12
13 0.21 beta 1 - 2011/05/02
14 ------------------------
15@@ -63,16 +67,16 @@
16 * qannotate, qdiff:
17 * Find text box turns red if no matches are found.
18 (A. S. Budden, Bug #772244)
19+
20 * qcat, qannotate, qdiff, qconfig:
21 * Added ability to customise the tab-stop width (setting in qconfig,
22- affects qcat, qannotate and qdiff).
23+ affects qcat, qannotate and qdiff).
24 The setting is stored in [DEFAULT] section of bazaar.conf,
25 and is named tab_width (it can also be configured with qconfig). Units
26 are characters (so 4 means a tab should be displayed with the width of 4
27 spaces). The default value is 8. The setting can also be adjusted in
28 branch.conf for specific branches. (Bug #490377, A. S. Budden)
29
30-
31 0.20.1 - 2011/04/26
32 --------------------
33 Maintenance release.
34
35=== modified file 'lib/annotate.py'
36--- lib/annotate.py 2011-04-27 14:13:50 +0000
37+++ lib/annotate.py 2011-05-11 11:51:06 +0000
38@@ -37,6 +37,7 @@
39 get_icon,
40 get_monospace_font,
41 get_set_encoding,
42+ get_set_tab_width_chars,
43 get_tab_width_pixels,
44 runs_in_loading_queue,
45 )
46@@ -53,6 +54,7 @@
47 from bzrlib.revisiontree import RevisionTree
48 from bzrlib.plugins.qbzr.lib.revisionmessagebrowser import LogListRevisionMessageBrowser
49 from bzrlib.plugins.qbzr.lib.encoding_selector import EncodingMenuSelector
50+from bzrlib.plugins.qbzr.lib.widgets.tab_width_selector import TabWidthMenuSelector
51 from bzrlib.plugins.qbzr.lib.syntaxhighlighter import highlight_document
52 from bzrlib.plugins.qbzr.lib.revtreeview import paint_revno, get_text_color
53 from bzrlib.plugins.qbzr.lib import logmodel
54@@ -269,8 +271,6 @@
55 self.text_edit.setLineWrapMode(QtGui.QPlainTextEdit.NoWrap)
56
57 self.text_edit.document().setDefaultFont(get_monospace_font())
58-
59- self.text_edit.setTabStopWidth(get_tab_width_pixels(branch))
60
61 self.annotate_bar = AnnotateBar(self.text_edit, self, self.get_revno)
62 annotate_spliter = QtGui.QSplitter(QtCore.Qt.Horizontal, self)
63@@ -337,7 +337,15 @@
64 self.connect(word_wrap,
65 QtCore.SIGNAL("toggled (bool)"),
66 self.word_wrap_toggle)
67+
68+ def setTabStopWidth(tw):
69+ self.text_edit.setTabStopWidth(get_tab_width_pixels(tab_width_chars=tw))
70+ get_set_tab_width_chars(branch=self.branch,tab_width_chars=tw)
71+ self.tab_width_selector = TabWidthMenuSelector(get_set_tab_width_chars(branch=branch),
72+ gettext("Tab Width"),
73+ setTabStopWidth)
74
75+ view_menu.addMenu(self.tab_width_selector)
76 view_menu.addMenu(self.encoding_selector)
77 view_menu.addAction(word_wrap)
78
79
80=== modified file 'lib/config.py'
81--- lib/config.py 2011-04-26 08:26:28 +0000
82+++ lib/config.py 2011-05-11 11:51:06 +0000
83@@ -35,7 +35,7 @@
84 extract_name,
85 get_qbzr_config,
86 get_global_config,
87- get_tab_width_chars,
88+ get_set_tab_width_chars,
89 )
90
91
92@@ -305,7 +305,7 @@
93 self.emailClientCombo.setCurrentIndex(index)
94
95 # Tab-width
96- self.tabWidthSpinner.setValue(get_tab_width_chars())
97+ self.tabWidthSpinner.setValue(get_set_tab_width_chars())
98
99 # Spellcheck language
100 spellcheck_language = config.get_user_option('spellcheck_language') or 'en'
101
102=== modified file 'lib/diffwindow.py'
103--- lib/diffwindow.py 2011-04-29 10:12:04 +0000
104+++ lib/diffwindow.py 2011-05-11 11:51:06 +0000
105@@ -54,6 +54,7 @@
106 ToolBarThrobberWidget,
107 get_icon,
108 get_set_encoding,
109+ get_set_tab_width_chars,
110 get_tab_width_pixels,
111 is_binary_content,
112 run_in_loading_queue,
113@@ -63,6 +64,7 @@
114 from bzrlib.plugins.qbzr.lib.uifactory import ui_current_widget
115 from bzrlib.plugins.qbzr.lib.trace import reports_exception
116 from bzrlib.plugins.qbzr.lib.encoding_selector import EncodingMenuSelector
117+from bzrlib.plugins.qbzr.lib.widgets.tab_width_selector import TabWidthMenuSelector
118
119 try:
120 from bzrlib.errors import FileTimestampUnavailable
121@@ -154,6 +156,11 @@
122 vbox = QtGui.QVBoxLayout(self.centralwidget)
123 vbox.addWidget(self.stack)
124
125+ # Don't use a custom tab width by default
126+ # Indices are left side, right side and unidiff
127+ # respectively
128+ self.custom_tab_widths = [-1,-1,-1]
129+
130 for browser in self.diffview.browsers:
131 browser.installEventFilter(self)
132
133@@ -273,6 +280,42 @@
134 self.ignore_whitespace_action = self.create_ignore_ws_action()
135 view_menu.addAction(self.ignore_whitespace_action)
136
137+ def on_unidiff_tab_width_changed(tabwidth):
138+ if self.branches:
139+ get_set_tab_width_chars(branch=self.branches[0],tab_width_chars=tabwidth)
140+ self.custom_tab_widths[2] = tabwidth
141+ self.setup_tab_width()
142+ self.tab_width_selector_unidiff = TabWidthMenuSelector(
143+ label_text=gettext("Tab width"),
144+ onChanged=on_unidiff_tab_width_changed)
145+ view_menu.addMenu(self.tab_width_selector_unidiff)
146+
147+ def on_left_tab_width_changed(tabwidth):
148+ if self.branches:
149+ get_set_tab_width_chars(branch=self.branches[0],tab_width_chars=tabwidth)
150+ self.custom_tab_widths[0] = tabwidth
151+ self.setup_tab_width()
152+ self.tab_width_selector_left = TabWidthMenuSelector(
153+ label_text=gettext("Left side tab width"),
154+ onChanged=on_left_tab_width_changed)
155+ view_menu.addMenu(self.tab_width_selector_left)
156+
157+ def on_right_tab_width_changed(tabwidth):
158+ if self.branches:
159+ get_set_tab_width_chars(branch=self.branches[1],tab_width_chars=tabwidth)
160+ self.custom_tab_widths[1] = tabwidth
161+ self.setup_tab_width()
162+ self.tab_width_selector_right = TabWidthMenuSelector(
163+ label_text=gettext("Right side tab width"),
164+ onChanged=on_right_tab_width_changed)
165+ view_menu.addMenu(self.tab_width_selector_right)
166+
167+ if self.stack.currentWidget() == self.diffview:
168+ self.tab_width_selector_unidiff.menuAction().setVisible(False)
169+ else:
170+ self.tab_width_selector_left.menuAction().setVisible(False)
171+ self.tab_width_selector_right.menuAction().setVisible(False)
172+
173 def on_left_encoding_changed(encoding):
174 if self.branches:
175 get_set_encoding(encoding, self.branches[0])
176@@ -371,10 +414,19 @@
177 self.processEvents()
178
179 def setup_tab_width(self):
180- tabWidths = (get_tab_width_pixels(self.branches[0]),
181- get_tab_width_pixels(self.branches[1]))
182- self.diffview.setTabStopWidths(tabWidths)
183- self.sdiffview.setTabStopWidth(tabWidths[0])
184+ tabWidths = self.custom_tab_widths
185+ if tabWidths[0] < 0:
186+ tabWidths[0] = get_set_tab_width_chars(branch=self.branches[0])
187+ self.tab_width_selector_left.setTabWidth(tabWidths[0])
188+ if tabWidths[1] < 0:
189+ tabWidths[1] = get_set_tab_width_chars(branch=self.branches[1])
190+ self.tab_width_selector_right.setTabWidth(tabWidths[1])
191+ if tabWidths[2] < 0:
192+ tabWidths[2] = get_set_tab_width_chars(branch=self.branches[0])
193+ self.tab_width_selector_unidiff.setTabWidth(tabWidths[2])
194+ tabWidthsPixels = [get_tab_width_pixels(tab_width_chars=i) for i in tabWidths]
195+ self.diffview.setTabStopWidths(tabWidthsPixels)
196+ self.sdiffview.setTabStopWidth(tabWidthsPixels[2])
197
198 def load_diff(self):
199 self.view_refresh.setEnabled(False)
200@@ -532,9 +584,15 @@
201 if checked:
202 view = self.sdiffview
203 self.find_toolbar.text_edit = view
204+ self.tab_width_selector_left.menuAction().setVisible(False)
205+ self.tab_width_selector_right.menuAction().setVisible(False)
206+ self.tab_width_selector_unidiff.menuAction().setVisible(True)
207 else:
208 view = self.diffview
209 self.find_toolbar.text_edit = view.browsers[0]
210+ self.tab_width_selector_left.menuAction().setVisible(True)
211+ self.tab_width_selector_right.menuAction().setVisible(True)
212+ self.tab_width_selector_unidiff.menuAction().setVisible(False)
213 view.rewind()
214 index = self.stack.indexOf(view)
215 self.stack.setCurrentIndex(index)
216
217=== modified file 'lib/util.py'
218--- lib/util.py 2011-05-07 15:50:46 +0000
219+++ lib/util.py 2011-05-11 11:51:06 +0000
220@@ -1232,17 +1232,46 @@
221 font.setFixedPitch(True)
222 return font
223
224-def get_tab_width_chars(branch=None):
225- """Function to get the tab width in characters from the configuration."""
226- config = get_branch_config(branch)
227- try:
228- tabWidth = int(config.get_user_option('tab_width'))
229- except TypeError:
230- tabWidth = 8
231- return tabWidth
232-
233-def get_tab_width_pixels(branch=None):
234- """Function to get the tab width in pixels based on a monospaced font."""
235+def get_set_tab_width_chars(branch=None, tab_width_chars=None):
236+ """Function to get the tab width in characters from the configuration.
237+
238+ @param branch: Use branch.conf as well as bazaar.conf if this is provided.
239+ @param tab_width_chars: Number of characters to use as tab width: if branch
240+ is provided, the tab width will be stored in branch.conf
241+
242+ Both arguments are optional, but if tab_width_chars is provided and branch is
243+ not, nothing will be done.
244+
245+ @return: Tab width, in characters.
246+ """
247+ if tab_width_chars is None:
248+ config = get_branch_config(branch)
249+ try:
250+ tab_width_chars = int(config.get_user_option('tab_width'))
251+ if tab_width_chars < 0:
252+ raise TypeError("Invalid tab width")
253+ except TypeError:
254+ tab_width_chars = 8
255+ else:
256+ if branch:
257+ branch.get_config().set_user_option("tab_width", tab_width_chars)
258+
259+ return tab_width_chars
260+
261+def get_tab_width_pixels(branch=None, tab_width_chars=None):
262+ """Function to get the tab width in pixels based on a monospaced font.
263+
264+ If tab_width_chars is provided, it is simply converted to a value in pixels. If
265+ it is not provided, the configuration is retrieved from bazaar.conf. If branch is
266+ provided (and tab_width_chars is not), branch.conf is also checked.
267+
268+ @param tab_width_chars: Number of characters of tab width to convert to pixels.
269+ @param branch: Branch to use when retrieving tab width from configuration.
270+
271+ @return: Tab width, in pixels.
272+ """
273 monospacedFont = get_monospace_font()
274 char_width = QtGui.QFontMetrics(monospacedFont).width(" ")
275- return char_width*get_tab_width_chars(branch)
276+ if tab_width_chars is None:
277+ tab_width_chars = get_set_tab_width_chars(branch=branch)
278+ return char_width*tab_width_chars
279
280=== added directory 'lib/widgets'
281=== added file 'lib/widgets/__init__.py'
282--- lib/widgets/__init__.py 1970-01-01 00:00:00 +0000
283+++ lib/widgets/__init__.py 2011-05-11 11:51:06 +0000
284@@ -0,0 +1,1 @@
285+""
286
287=== added file 'lib/widgets/tab_width_selector.py'
288--- lib/widgets/tab_width_selector.py 1970-01-01 00:00:00 +0000
289+++ lib/widgets/tab_width_selector.py 2011-05-11 11:51:06 +0000
290@@ -0,0 +1,85 @@
291+# -*- coding: utf-8 -*-
292+#
293+# QBzr - Qt frontend to Bazaar commands
294+#
295+# This program is free software; you can redistribute it and/or
296+# modify it under the terms of the GNU General Public License
297+# as published by the Free Software Foundation; either version 2
298+# of the License, or (at your option) any later version.
299+#
300+# This program is distributed in the hope that it will be useful,
301+# but WITHOUT ANY WARRANTY; without even the implied warranty of
302+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
303+# GNU General Public License for more details.
304+#
305+# You should have received a copy of the GNU General Public License
306+# along with this program; if not, write to the Free Software
307+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
308+
309+from PyQt4 import QtGui, QtCore
310+
311+# Range of tab widths to display by default on the menu (if others are
312+# specified in either bazaar.conf or branch.conf they'll be added after
313+# a separator).
314+MIN_TAB_WIDTH = 1
315+MAX_TAB_WIDTH = 12
316+
317+class TabWidthMenuSelector(QtGui.QMenu):
318+ """Menu to control tab width."""
319+ def __init__(self, initial_tab_width=None, label_text=None, onChanged=None, *args):
320+ """Create tab width menu.
321+ @param label_text: text for label.
322+ @param onChanged: callback to processing tab width change.
323+ """
324+ QtGui.QMenu.__init__(self, *args)
325+ self.onChanged = onChanged
326+ if onChanged is None:
327+ self.onChanged = lambda settabwidth: None
328+
329+ self.setTitle(label_text)
330+
331+ self.action_group = QtGui.QActionGroup(self)
332+
333+ self.tabwidth_actions = {}
334+ for tabwidth in range(MIN_TAB_WIDTH, MAX_TAB_WIDTH+1):
335+ action = QtGui.QAction(str(tabwidth), self.action_group)
336+ action.setCheckable(True)
337+ action.setData(QtCore.QVariant(tabwidth))
338+ self.addAction(action)
339+ self.tabwidth_actions[tabwidth] = action
340+
341+ self._tabwidth = None
342+ self._has_separator = False
343+ self.connect(self, QtCore.SIGNAL("triggered(QAction *)"),
344+ self.triggered)
345+
346+ if initial_tab_width is not None:
347+ self.setTabWidth(initial_tab_width)
348+ self.triggered(self.tabwidth_actions[initial_tab_width])
349+
350+ def triggered(self, action):
351+ tw, success = action.data().toInt()
352+ if success and tw != self._tabwidth:
353+ self._tabwidth = tw
354+ self.onChanged(tw)
355+
356+ def setTabWidth(self, width):
357+ if width not in self.tabwidth_actions:
358+ action = QtGui.QAction(str(width), self.action_group)
359+ action.setCheckable(True)
360+ action.setData(QtCore.QVariant(width))
361+ # Find the next highest tab width currently in the menu
362+ for tw in sorted(self.tabwidth_actions.keys()):
363+ if tw > width:
364+ self.insertAction(action, self.tabwidth_actions[tw])
365+ break
366+ else:
367+ # Not found
368+ if not self._has_separator:
369+ self.addSeparator()
370+ self._has_separator = True
371+ self.addAction(action)
372+
373+ self.tabwidth_actions[width] = action
374+
375+ self.tabwidth_actions[width].setChecked(True)

Subscribers

People subscribed via source and target branches