Merge lp:~dorins/qbzr/qdiff-changes into lp:qbzr

Proposed by Dorin Scutarașu
Status: Merged
Merged at revision: 1368
Proposed branch: lp:~dorins/qbzr/qdiff-changes
Merge into: lp:qbzr
Diff against target: 1172 lines (+463/-206)
6 files modified
data/qbzr.qrc (+3/-1)
lib/commands.py (+50/-45)
lib/diff_arg.py (+40/-31)
lib/diffwindow.py (+210/-100)
lib/resources.py (+144/-28)
lib/util.py (+16/-1)
To merge this branch: bzr merge lp:~dorins/qbzr/qdiff-changes
Reviewer Review Type Date Requested Status
Alexander Belchenko Approve
Gary van der Merwe Pending
Review via email: mp+34710@code.launchpad.net

Description of the change

Implements the following changes on the qdiff window:

- Move actions from the bottom of the window on a toolbar, similar to the toolbar from the qannotate window
- Add a Find actions which toggles a find toolbar. Find action acts on the active panel - the panel that had focus last.
- Add shortcut keys for "Refresh", "Find" and "Toggle view mode" actions and show shortcut key hints on tooltips for these actions and also for "Find next", "Find previous" actions.
- Add an "Ignore whitespace changes" option.

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

Looks nice.

Although it's not very intuitive that clicking lowered Side-by-side button will give me unidiff view.

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

Shortcut for switching between Side-by-Side and Unidiff is Crtl+| which means pressing Ctrl+Shift+\ on my keyboard. Is using Shift intended here? Maybe it worth to use something simler instead?

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

I see you have added Ignore whitespace changes option. Does it related to this merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-whitespace/+merge/35921 ?

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

Alexander Belchenko пишет:
> Shortcut for switching between Side-by-Side and Unidiff is Crtl+| which means pressing Ctrl+Shift+\ on my keyboard. Is using Shift intended here? Maybe it worth to use something simler instead?

I suggest using Ctrl+U.

Revision history for this message
Dorin Scutarașu (dorins) wrote :

> I see you have added Ignore whitespace changes option. Does it related to this
> merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
> whitespace/+merge/35921 ?

Yes. Looks like the other branch has similar changes except that the UI is different: I added a menu item to toggle whitespace changes, the other branch uses a command line parameter.

lp:~dorins/qbzr/qdiff-changes updated
1317. By Dorin Scutarașu

* Replaced "Side by side" toolbar button with "Unidiff" button to reflect default view mode.
* Changed shortcut key for toggling view mode to "Ctrl-U".

Revision history for this message
Dorin Scutarașu (dorins) wrote :

> Although it's not very intuitive that clicking lowered Side-by-side button
> will give me unidiff view.

I replaced the "Side by side" button with a "Unidiff" button which makes more sense since side by side is the default. Also, I changed the shortcut key to "Ctrl-U". Thanks for the feedback.

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

I like new variant. I have some doubts about using 3-panel icon for Unidiff button now, but I have no good suggestions.

Also I found that External Diff button does not work. Have you tested it?

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

Dorin Scutarașu пишет:
>> I see you have added Ignore whitespace changes option. Does it related to this
>> merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
>> whitespace/+merge/35921 ?
>
> Yes. Looks like the other branch has similar changes except that the UI is different: I added a menu item to toggle whitespace changes, the other branch uses a command line parameter.

@Dorin, can you merge the changes from the other branch, so I can land
both branches soon? Or I can land the other branch first and you will
update your patch later?

@Glen, can you help Dorin to merge your patches, or do you prefer to
land your patch first?

Maybe you guys can collaborate on this feature?

Revision history for this message
Glen Mailer (glenjamin) wrote :

I think the best approach will be to merge my command line changes stuff into this branch - I can have a go at that this weekend.

Interestingly my first approach to whitespace removal was the regular expression substitution, but I replaced it with string.whitespace and string.translate after seeing Dorin's approach - meanwhile Dorin appears to have started with string.whitespace and moved to regular expression substitution.

Any ideas which is preferrable?

Revision history for this message
Dorin Scutarașu (dorins) wrote :

On 7 octombrie 2010, 13:43, Glen Mailer <email address hidden> wrote:
> I think the best approach will be to merge my command line changes stuff into this branch - I can have a go at that this weekend.
>

Sounds like a plan.

> Interestingly my first approach to whitespace removal was the regular expression substitution, but I replaced it with string.whitespace and string.translate after seeing Dorin's approach - meanwhile Dorin appears to have started with string.whitespace and moved to regular expression substitution.
>
> Any ideas which is preferrable?
> --
> https://code.launchpad.net/~dorins/qbzr/qdiff-changes/+merge/34710
> You are the owner of lp:~dorins/qbzr/qdiff-changes.
>

I made some tests and it looks like string.translate is fastest. I
switched to using regular expresion substitution because I had some
problems with string.translate:

* python >= 2.6 accepts None as the first parameter, but older python
  versions don't.

* string.translate delegates to either str.translate(s, table,
  delchars=None) or unicode.translate(s, table), so it crashes for unicode
  strings when passing delchars argument.

I switched to regular expressions at the time thinking that I'll get back
to it and figure out how to use 'translate' safely, but I didn't manage to
do that so far.

lp:~dorins/qbzr/qdiff-changes updated
1318. By Dorin Scutarașu

Fixed "External Diff" toolbar button.

1319. By Dorin Scutarașu

Add shortcut keys: Alt+V pops up the view menu, Alt+E pops up the "External Diff" menu.

The shortcut keys are appended to the respective tool tips.
Also, "Complete" action is now accessible using "Alt+V,C" and "Ignore Whitespace changes" is accessible using "Alt+V,I".

1320. By Dorin Scutarașu

Merge with lp:~glenjamin/qbzr/qdiff-ignore-whitespace.
Adds --ignore-whitespace option in qdiff.

1321. By Dorin Scutarașu

Merge trunk.

Revision history for this message
Dorin Scutarașu (dorins) wrote :

> Also I found that External Diff button does not work. Have you tested it?

I missed that somehow. Anyway, I fixed it today.

> Dorin Scutarașu пишет:
> > > I see you have added Ignore whitespace changes option. Does it related to this
> > > merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
> > > whitespace/+merge/35921 ?
> >
> > Yes. Looks like the other branch has similar changes except that the
> > UI is different: I added a menu item to toggle whitespace changes,
> > the other branch uses a command line parameter.

> @Dorin, can you merge the changes from the other branch, so I can land
> both branches soon? Or I can land the other branch first and you will
> update your patch later?

I just merged the changes from this merge proposal:
https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-whitespace/+merge/35921
, which exposes an --ignore-whitespace option to qdiff.

lp:~dorins/qbzr/qdiff-changes updated
1322. By Dorin Scutarașu

Cleanup.

Revision history for this message
Glen Mailer (glenjamin) wrote :

> > Also I found that External Diff button does not work. Have you tested it?
>
> I missed that somehow. Anyway, I fixed it today.
>
> > Dorin Scutarașu пишет:
> > > > I see you have added Ignore whitespace changes option. Does it related
> to this
> > > > merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
> > > > whitespace/+merge/35921 ?
> > >
> > > Yes. Looks like the other branch has similar changes except that the
> > > UI is different: I added a menu item to toggle whitespace changes,
> > > the other branch uses a command line parameter.
>
> > @Dorin, can you merge the changes from the other branch, so I can land
> > both branches soon? Or I can land the other branch first and you will
> > update your patch later?
>
> I just merged the changes from this merge proposal:
> https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
> whitespace/+merge/35921
> , which exposes an --ignore-whitespace option to qdiff.

Excellent! I was just about to take a look at this :)

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

Glen Mailer пишет:
>>> Also I found that External Diff button does not work. Have you tested it?
>> I missed that somehow. Anyway, I fixed it today.
>>
>>> Dorin Scutarașu пишет:
>>>>> I see you have added Ignore whitespace changes option. Does it related
>> to this
>>>>> merge proposal: https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
>>>>> whitespace/+merge/35921 ?
>>>> Yes. Looks like the other branch has similar changes except that the
>>>> UI is different: I added a menu item to toggle whitespace changes,
>>>> the other branch uses a command line parameter.
>>> @Dorin, can you merge the changes from the other branch, so I can land
>>> both branches soon? Or I can land the other branch first and you will
>>> update your patch later?
>> I just merged the changes from this merge proposal:
>> https://code.launchpad.net/~glenjamin/qbzr/qdiff-ignore-
>> whitespace/+merge/35921
>> , which exposes an --ignore-whitespace option to qdiff.
>
> Excellent! I was just about to take a look at this :)

Thank you, guys! I will review it ASAP and I hope to land it soon.

--
All the dude wanted was his rug back

Revision history for this message
Dorin Scutarașu (dorins) wrote :

Could someone review this please? Is there anything I can do to speed things up?

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

Dorin Scutarașu пишет:
> Could someone review this please? Is there anything I can do to speed things up?

I'm very very very sorry, but it seems your patch misses our deadline
for 0.20 final to be in sync with bzr 2.3.
We will merge it as soon as 0.20 will be ready.

Sorry for the delay :-/

--
All the dude wanted was his rug back

Revision history for this message
Dorin Scutarașu (dorins) wrote :

> Sorry for the delay :-/

No problem. I was just curious as to what's holding this up. I was thinking about adding line numbers and "go to line" function, and wanted to work on top of this. I guess I need to figure out how the pipeline plug-in works.

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

I was very busy last months, sorry. I'm going to merge it now. I think there is nothing we need to change or improve, and just need merge it, right?

Gary, are you have any comments on this patch?

review: Needs Information
Revision history for this message
Dorin Scutarașu (dorins) wrote :

> I was very busy last months, sorry. I'm going to merge it now. I think there
> is nothing we need to change or improve, and just need merge it, right?

Yes, as far as I know.

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

Dorin, can you merge the trunk into your branch and resolve conflicts, please? There are some conflicted changes that look trivial, but I'm not quite sure about them. That will help me to do final review.

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

> Dorin, can you merge the trunk into your branch and resolve conflicts, please?
> There are some conflicted changes that look trivial, but I'm not quite sure
> about them. That will help me to do final review.

I did it.

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

Find is not intuitive because it search only on the left pane, I have to click on right pane to force it search there. I'd rather expect it searches both panes

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

I've tested new qdiff but I haven't inspected every single line of your changes.

In the future please avoid unnecessary whitespace-only changes in contribution to QBzr. It breaks annotations and makes the review (without qdiff -w) much harder.

Also I wonder if we want to save state of "Ignore whitespace" knob in some config file (maybe in qbzr.conf or branch.conf) but I'm not sure yet. If you have any opinion on this we can discuss it in our google group ML.

Resume: many thanks for great work to you and Glenjamin. I'm going to land it to trunk and will release 0.21 beta1 soon so many people will have a chance to test it in the action.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/22x22/system-run.png'
2Binary files data/22x22/system-run.png 1970-01-01 00:00:00 +0000 and data/22x22/system-run.png 2010-10-16 08:18:41 +0000 differ
3=== added file 'data/22x22/view-split-left-right.png'
4Binary files data/22x22/view-split-left-right.png 1970-01-01 00:00:00 +0000 and data/22x22/view-split-left-right.png 2010-10-16 08:18:41 +0000 differ
5=== modified file 'data/qbzr.qrc'
6--- data/qbzr.qrc 2009-12-22 22:04:05 +0000
7+++ data/qbzr.qrc 2010-10-16 08:18:41 +0000
8@@ -32,6 +32,8 @@
9 <file>22x22/go-jump.png</file>
10 <file>22x22/go-next.png</file>
11 <file>22x22/go-previous.png</file>
12+ <file>22x22/view-split-left-right.png</file>
13+ <file>22x22/system-run.png</file>
14
15 </qresource>
16-</RCC>
17\ No newline at end of file
18+</RCC>
19
20=== modified file 'lib/commands.py'
21--- lib/commands.py 2010-10-11 13:05:30 +0000
22+++ lib/commands.py 2010-10-16 08:18:41 +0000
23@@ -144,7 +144,7 @@
24 self.main_window should be instance of QBzrWindow or QBzrDialog
25 with attribute "return_code" set to 0 or 1.
26 """
27-
28+
29 @install_gettext
30 @report_missing_pyqt
31 def run(self, *args, **kwargs):
32@@ -156,11 +156,11 @@
33 std_ui_factory = ui.ui_factory
34 try:
35 ui.ui_factory = QUIFactory()
36-
37+
38 # Set up global exception handling.
39 from bzrlib.plugins.qbzr.lib.trace import excepthook
40 sys.excepthook = excepthook
41-
42+
43 try:
44 try:
45 ret_code = self._qbzr_run(*args, **kwargs)
46@@ -251,7 +251,7 @@
47 else:
48 tree = branch.repository.revision_tree(
49 revision_id = revision[0].in_history(branch).rev_id)
50-
51+
52 file_id = tree.path2id(relpath)
53 if file_id is None:
54 raise errors.NotVersionedError(filename)
55@@ -288,7 +288,7 @@
56 """GUI for adding files or directories."""
57 takes_args = ['selected*']
58 takes_options = [ui_mode_option]
59-
60+
61 def _qbzr_run(self, selected_list=None, ui_mode=False):
62 tree, selected_list = builtins.tree_files(selected_list)
63 if selected_list == ['']:
64@@ -387,6 +387,8 @@
65 Option('modified', short_name='M',
66 help='Show diff for modified files.'),
67 Option('renamed', short_name='R', help='Show diff for renamed files.'),
68+ Option('ignore-whitespace', short_name='w',
69+ help="Ignore whitespace when finding differences"),
70 bzr_option('diff', 'old'),
71 bzr_option('diff', 'new'),
72 ]
73@@ -395,24 +397,26 @@
74 aliases = ['qdi']
75
76 def get_diff_window_args(self, processEvents, add_cleanup):
77+ args = {}
78 try:
79 from bzrlib.diff import get_trees_and_branches_to_diff_locked
80 except ImportError:
81 from bzrlib.diff import get_trees_and_branches_to_diff
82- (old_tree, new_tree,
83- old_branch, new_branch,
84- specific_files, extra_trees) = \
85+ (args["old_tree"], args["new_tree"],
86+ args["old_branch"], args["new_branch"],
87+ args["specific_files"], _) = \
88 get_trees_and_branches_to_diff(
89 self.file_list, self.revision, self.old, self.new)
90 else:
91- (old_tree, new_tree,
92- old_branch, new_branch,
93- specific_files, extra_trees) = \
94+ (args["old_tree"], args["new_tree"],
95+ args["old_branch"], args["new_branch"],
96+ args["specific_files"], _) = \
97 get_trees_and_branches_to_diff_locked(
98 self.file_list, self.revision, self.old, self.new,
99 add_cleanup)
100- return old_tree, new_tree, old_branch, new_branch, specific_files
101-
102+ args["ignore_whitespace"] = self.ignore_whitespace
103+ return args
104+
105 def get_ext_diff_args(self, processEvents):
106 args = []
107 if self.revision and len(self.revision) == 1:
108@@ -425,14 +429,14 @@
109 args.append("--new=%s" % self.new)
110 if self.old and not self.old == CUR_DIR:
111 args.append("--old=%s" % self.old)
112-
113+
114 if self.file_list:
115 args.extend(self.file_list)
116-
117- return None, args
118+
119+ return None, args
120
121 def _qbzr_run(self, revision=None, file_list=None, complete=False,
122- encoding=None,
123+ encoding=None, ignore_whitespace=False,
124 added=None, deleted=None, modified=None, renamed=None,
125 old=None, new=None, ui_mode=False):
126
127@@ -445,11 +449,12 @@
128 if not (added or deleted or modified or renamed):
129 # if no filter option used then turn all on
130 filter_options.all_enable()
131-
132+
133 self.revision = revision
134 self.file_list = file_list
135 self.old = old
136 self.new = new
137+ self.ignore_whitespace = ignore_whitespace
138
139 window = DiffWindow(self,
140 complete=complete,
141@@ -464,7 +469,7 @@
142 """Show log of a repository, branch, file, or directory in a Qt window.
143
144 By default show the log of the branch containing the working directory.
145-
146+
147 If multiple files are speciffied, they must be from the same branch.
148
149 :Examples:
150@@ -618,7 +623,7 @@
151
152 if directory is None:
153 directory = CUR_DIR
154-
155+
156 try:
157 tree_to = WorkingTree.open_containing(directory)[0]
158 branch_to = tree_to.branch
159@@ -705,7 +710,7 @@
160 tree_merger = self.merger.make_merger()
161 self.tt = tree_merger.make_preview_transform()
162 result_tree = self.tt.get_preview_tree()
163- return self.merger.this_tree, result_tree, None, None, None
164+ return {"old_tree": self.merger.this_tree, "new_tree": result_tree}
165
166 @install_gettext
167 @report_missing_pyqt
168@@ -713,7 +718,7 @@
169 # Set up global execption handeling.
170 from bzrlib.plugins.qbzr.lib.trace import excepthook
171 sys.excepthook = excepthook
172-
173+
174 self.merger = merger
175 try:
176 window = DiffWindow(self, encoding=self._encoding)
177@@ -761,12 +766,12 @@
178 # bzr qannotate commands.py -r1117
179
180 class cmd_qsubprocess(Command):
181- """Run some bzr command as subprocess.
182+ """Run some bzr command as subprocess.
183 Used with most of subprocess-based dialogs of QBzr.
184-
185+
186 If CMD argument starts with @ characters then it used as name of file with
187 actual cmd string (in utf-8).
188-
189+
190 With --bencode option cmd string interpreted as bencoded list of utf-8
191 strings. This is the recommended way to launch qsubprocess.
192 """
193@@ -929,7 +934,7 @@
194
195 takes_args = ['submit_branch?', 'public_branch?']
196 takes_options = [ui_mode_option]
197-
198+
199 def _qbzr_run(self, submit_branch=CUR_DIR, public_branch=None, ui_mode=False):
200 branch = Branch.open_containing(submit_branch)[0]
201 window = SendWindow(branch, ui_mode)
202@@ -939,74 +944,74 @@
203
204 class cmd_qswitch(QBzrCommand):
205 """Set the branch of a checkout and update."""
206-
207+
208 takes_args = ['location?']
209 takes_options = [ui_mode_option]
210-
211+
212 def _qbzr_run(self, location=None, ui_mode=False):
213 from bzrlib.plugins.qbzr.lib.switch import QBzrSwitchWindow
214-
215+
216 branch = Branch.open_containing(CUR_DIR)[0]
217 bzrdir = BzrDir.open_containing(CUR_DIR)[0]
218 self.main_window = QBzrSwitchWindow(branch, bzrdir, location, ui_mode)
219 self.main_window.show()
220- self._application.exec_()
221+ self._application.exec_()
222
223
224 class cmd_qunbind(QBzrCommand):
225 """Convert the current checkout into a regular branch."""
226 takes_options = [ui_mode_option, execute_option]
227-
228+
229 def _qbzr_run(self, ui_mode=False, execute=False):
230 from bzrlib.plugins.qbzr.lib.unbind import QBzrUnbindDialog
231-
232+
233 branch = Branch.open_containing(CUR_DIR)[0]
234 if branch.get_bound_location() == None:
235 raise errors.BzrCommandError("This branch is not bound.")
236-
237+
238 self.main_window = QBzrUnbindDialog(branch, ui_mode, execute)
239 self.main_window.show()
240- self._application.exec_()
241+ self._application.exec_()
242
243
244 class cmd_qexport(QBzrCommand):
245 """Export current or past revision to a destination directory or archive.
246-
247+
248 DEST is the destination file or dir where the branch will be exported.
249 If BRANCH_OR_SUBDIR is omitted then the branch containing the current working
250 directory will be used.
251 """
252-
253+
254 takes_args = ['dest?','branch_or_subdir?']
255 takes_options = [ui_mode_option]
256-
257+
258 def _qbzr_run(self, dest=None, branch_or_subdir=None, ui_mode=False):
259 from bzrlib.plugins.qbzr.lib.export import QBzrExportDialog
260-
261+
262 if branch_or_subdir == None:
263 branch = Branch.open_containing(CUR_DIR)[0]
264 else:
265 branch = Branch.open_containing(branch_or_subdir)[0]
266-
267+
268 window = QBzrExportDialog(dest, branch, ui_mode)
269 window.show()
270- self._application.exec_()
271+ self._application.exec_()
272
273
274 class cmd_qbind(QBzrCommand):
275 """Convert the current branch into a checkout of the supplied branch.
276-
277+
278 LOCATION is the branch where you want to bind your current branch.
279 """
280-
281+
282 takes_args = ['location?']
283 takes_options = [ui_mode_option]
284-
285+
286 def _qbzr_run(self, location=None, ui_mode=False):
287 from bzrlib.plugins.qbzr.lib.bind import QBzrBindDialog
288-
289+
290 branch = Branch.open_containing(CUR_DIR)[0]
291-
292+
293 self.main_window = QBzrBindDialog(branch, location, ui_mode)
294 self.main_window.show()
295 self._application.exec_()
296
297=== modified file 'lib/diff_arg.py'
298--- lib/diff_arg.py 2010-05-05 12:40:43 +0000
299+++ lib/diff_arg.py 2010-10-16 08:18:41 +0000
300@@ -27,25 +27,30 @@
301 class DiffArgProvider (object):
302 """Contract class to pass arguments to either builtin diff window, or
303 external diffs"""
304-
305+
306 def get_diff_window_args(self, processEvents, add_cleanup):
307 """Returns the arguments for the builtin diff window.
308-
309- :return: (tree1, tree2, branch1, branch2, specific_files)
310+
311+ :return: {"old_tree": old_tree,
312+ "new_tree": new_tree,
313+ "old_branch": old_branch, (optional)
314+ "new_branch": new_branch, (optional)
315+ "specific_files": specific_files, (optional)
316+ "ignore_whitespace": True or False} (optional)
317 """
318 raise NotImplementedError()
319-
320+
321 def get_ext_diff_args(self, processEvents):
322 """Returns the command line arguments for running an ext diff window.
323-
324+
325 :return: (dir, List of command line arguments).
326- """
327+ """
328 raise NotImplementedError()
329
330
331 class InternalDiffArgProvider(DiffArgProvider):
332 """Use for passing arguments from internal source."""
333-
334+
335 def __init__(self, old_revid, new_revid, old_branch, new_branch,
336 specific_files=None, specific_file_ids=None):
337 self.old_revid = old_revid
338@@ -57,21 +62,21 @@
339
340 self.old_tree = None
341 self.new_tree = None
342-
343+
344 def need_to_load_paths(self):
345 return self.specific_file_ids is not None \
346 and self.specific_files is None
347-
348+
349 def load_old_tree(self):
350 if not self.old_tree:
351 self.old_tree = \
352 self.old_branch.repository.revision_tree(self.old_revid)
353-
354+
355 def load_new_tree_and_paths(self):
356 if not self.new_tree:
357 self.new_tree = \
358 self.new_branch.repository.revision_tree(self.new_revid)
359-
360+
361 if self.need_to_load_paths():
362 self.new_tree.lock_read()
363 try:
364@@ -85,14 +90,16 @@
365 processEvents()
366 self.load_new_tree_and_paths()
367 processEvents()
368-
369- return (self.old_tree, self.new_tree,
370- self.old_branch, self.new_branch,
371- self.specific_files)
372-
373+
374+ return {"old_tree": self.old_tree,
375+ "new_tree": self.new_tree,
376+ "old_branch": self.old_branch,
377+ "new_branch": self.new_branch,
378+ "specific_files": self.specific_files}
379+
380 def get_revspec(self):
381 return "-rrevid:%s..revid:%s" % (self.old_revid, self.new_revid)
382-
383+
384 def get_ext_diff_args(self, processEvents):
385 from bzrlib import urlutils
386 from bzrlib import errors
387@@ -101,46 +108,46 @@
388 revspec = self.get_revspec()
389 if revspec:
390 args.append(revspec)
391-
392+
393 from bzrlib.workingtree import WorkingTree
394 def get_base(branch, tree):
395 if tree and isinstance(tree, WorkingTree):
396 return urlutils.local_path_to_url(tree.basedir)
397 return branch.base
398-
399+
400 old_base = get_base(self.old_branch, self.old_tree)
401 new_base = get_base(self.new_branch, self.new_tree)
402-
403+
404 # We need to avoid using --new and --old because diff tools
405 # does not support it. There are however some cases where
406 # this is not possilble.
407 need_old = False
408 if not self.old_branch.base == self.new_branch.base:
409 need_old = True
410-
411+
412 try:
413 dir = urlutils.local_path_from_url(new_base)
414 except errors.InvalidURL:
415 dir = ""
416 args.append("--new=%s" % new_base)
417 need_old = True
418-
419+
420 if need_old:
421 args.append("--old=%s" % old_base)
422-
423+
424 if self.need_to_load_paths():
425 self.load_new_tree_and_paths()
426 processEvents()
427 if self.specific_files:
428 args.extend(self.specific_files)
429-
430+
431 return dir, args
432
433
434 class InternalWTDiffArgProvider(InternalDiffArgProvider):
435 """Use for passing arguments from internal source where the new tree is
436 the working tree."""
437-
438+
439 def __init__(self, old_revid, new_tree, old_branch, new_branch,
440 specific_files=None):
441 self.old_revid = old_revid
442@@ -148,7 +155,7 @@
443 self.old_branch = old_branch
444 self.new_branch = new_branch
445 self.specific_files = specific_files
446-
447+
448 self.old_tree = None
449
450 def load_old_tree(self):
451@@ -161,16 +168,18 @@
452 def get_diff_window_args(self, processEvents, add_cleanup):
453 self.load_old_tree()
454 processEvents()
455-
456- return (self.old_tree, self.new_tree,
457- self.old_branch, self.new_branch,
458- self.specific_files)
459+
460+ return {"old_tree": self.old_tree,
461+ "new_tree": self.new_tree,
462+ "old_branch": self.old_branch,
463+ "new_branch": self.new_branch,
464+ "specific_files": self.specific_files}
465
466 def get_revspec(self):
467 if self.old_revid is not None:
468 return "-rrevid:%s" % (self.old_revid,)
469 else:
470 return None
471-
472+
473 def need_to_load_paths(self):
474 return False
475
476=== modified file 'lib/diffwindow.py'
477--- lib/diffwindow.py 2010-05-05 12:40:43 +0000
478+++ lib/diffwindow.py 2010-10-16 08:18:41 +0000
479@@ -22,6 +22,7 @@
480
481 import errno
482 import time
483+import string
484
485 from PyQt4 import QtCore, QtGui
486
487@@ -47,19 +48,20 @@
488
489 from bzrlib.plugins.qbzr.lib.i18n import gettext, ngettext, N_
490 from bzrlib.plugins.qbzr.lib.util import (
491- BTN_CLOSE, BTN_REFRESH,
492 FilterOptions,
493 QBzrWindow,
494- ThrobberWidget,
495- StandardButton,
496+ ToolBarThrobberWidget,
497 get_set_encoding,
498 is_binary_content,
499 run_in_loading_queue,
500- runs_in_loading_queue
501+ runs_in_loading_queue,
502+ FindToolbar,
503+ get_icon,
504+ show_shortcut_hint
505 )
506 from bzrlib.plugins.qbzr.lib.uifactory import ui_current_widget
507 from bzrlib.plugins.qbzr.lib.trace import reports_exception
508-from bzrlib.plugins.qbzr.lib.encoding_selector import EncodingSelector
509+from bzrlib.plugins.qbzr.lib.encoding_selector import EncodingMenuSelector
510
511 try:
512 from bzrlib.errors import FileTimestampUnavailable
513@@ -81,13 +83,13 @@
514 branch_title = ""
515 if None not in (branch, other_branch) and branch.base != other_branch.base:
516 branch_title = branch.nick
517-
518+
519 if isinstance(tree, WorkingTree):
520 if branch_title:
521 return gettext("Working Tree for %s") % branch_title
522 else:
523 return gettext("Working Tree")
524-
525+
526 elif isinstance(tree, (RevisionTree, DirStateRevisionTree)):
527 # revision_id_to_revno is faster, but only works on mainline rev
528 revid = tree.get_revision_id()
529@@ -117,7 +119,7 @@
530 elif isinstance(tree, _PreviewTree):
531 return gettext('Merge Preview')
532
533- # XXX I don't know what other cases we need to handle
534+ # XXX I don't know what other cases we need to handle
535 return 'Unknown tree'
536
537
538@@ -138,9 +140,9 @@
539 if filter_options is None:
540 self.filter_options = FilterOptions(all_enable=True)
541 self.complete = complete
542+ self.ignore_whitespace = False
543+ self.delayed_signal_connections = []
544
545- self.throbber = ThrobberWidget(self)
546-
547 self.diffview = SidebySideDiffView(self)
548 self.sdiffview = SimpleDiffView(self)
549 self.views = (self.diffview, self.sdiffview)
550@@ -148,74 +150,163 @@
551 self.stack = QtGui.QStackedWidget(self.centralwidget)
552 self.stack.addWidget(self.diffview)
553 self.stack.addWidget(self.sdiffview)
554-
555 vbox = QtGui.QVBoxLayout(self.centralwidget)
556- vbox.addWidget(self.throbber)
557 vbox.addWidget(self.stack)
558
559- diffsidebyside = QtGui.QRadioButton(gettext("Side by side"),
560- self.centralwidget)
561- self.connect(diffsidebyside,
562- QtCore.SIGNAL("clicked(bool)"),
563- self.click_diffsidebyside)
564- diffsidebyside.setChecked(True);
565-
566- unidiff = QtGui.QRadioButton(gettext("Unidiff"), self.centralwidget)
567- self.connect(unidiff,
568- QtCore.SIGNAL("clicked(bool)"),
569- self.click_unidiff)
570+ for browser in self.diffview.browsers:
571+ browser.installEventFilter(self)
572+
573+ self.create_main_toolbar()
574+ self.addToolBarBreak()
575+ self.find_toolbar = FindToolbar(self, self.diffview.browsers[0],
576+ self.show_find)
577+ self.find_toolbar.hide()
578+ self.addToolBar(self.find_toolbar)
579+
580+ def connect_later(self, *args, **kwargs):
581+ """Schedules a signal to be connected after loading CLI arguments.
582+
583+ Accepts the same arguments as QObject.connect method.
584+ """
585+ self.delayed_signal_connections.append((args, kwargs))
586+
587+ def process_delayed_connections(self):
588+ for (args, kwargs) in self.delayed_signal_connections:
589+ self.connect(*args, **kwargs)
590+
591+ def create_main_toolbar(self):
592+ toolbar = self.addToolBar(gettext("Diff"))
593+ toolbar.setMovable (False)
594+ toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
595+
596+ self.show_find = self.create_find_action()
597+ toolbar.addAction(self.show_find)
598+ toolbar.addAction(self.create_toggle_view_mode())
599+ self.view_refresh = self.create_refresh_action()
600+ toolbar.addAction(self.view_refresh)
601+
602+ if has_ext_diff():
603+ show_ext_diff_menu = self.create_ext_diff_action()
604+ toolbar.addAction(show_ext_diff_menu)
605+ widget = toolbar.widgetForAction(show_ext_diff_menu)
606+ widget.setPopupMode(QtGui.QToolButton.InstantPopup)
607+ widget.setShortcut("Alt+E")
608+ show_shortcut_hint(widget)
609+
610+ show_view_menu = self.create_view_menu()
611+ toolbar.addAction(show_view_menu)
612+ widget = toolbar.widgetForAction(show_view_menu)
613+ widget.setPopupMode(QtGui.QToolButton.InstantPopup)
614+ widget.setShortcut("Alt+V")
615+ show_shortcut_hint(widget)
616+
617+ spacer = QtGui.QWidget()
618+ spacer.setSizePolicy(QtGui.QSizePolicy.Expanding,
619+ QtGui.QSizePolicy.Expanding)
620+ toolbar.addWidget(spacer)
621+
622+ self.throbber = ToolBarThrobberWidget(self)
623+ toolbar.addWidget(self.throbber)
624+ return toolbar
625+
626+ def create_find_action(self):
627+ action = QtGui.QAction(get_icon("edit-find"),
628+ gettext("&Find"), self)
629+ action.setShortcut(QtGui.QKeySequence.Find)
630+ action.setToolTip(gettext("Find on active panel"))
631+ show_shortcut_hint(action)
632+ action.setCheckable(True)
633+ return action
634+
635+ def create_toggle_view_mode(self):
636+ action = QtGui.QAction(get_icon("view-split-left-right"),
637+ gettext("Unidiff"), self)
638+ action.setToolTip(
639+ gettext("Toggle between Side by side and Unidiff view modes"))
640+ action.setShortcut("Ctrl+U")
641+ show_shortcut_hint(action)
642+ action.setCheckable(True)
643+ action.setChecked(False);
644+ self.connect(action,
645+ QtCore.SIGNAL("toggled (bool)"),
646+ self.click_toggle_view_mode)
647+ return action
648+
649+ def create_refresh_action(self):
650+ action = QtGui.QAction(get_icon("view-refresh"),
651+ gettext("&Refresh"), self)
652+ action.setShortcut("Ctrl+R")
653+ show_shortcut_hint(action)
654+ self.connect(action,
655+ QtCore.SIGNAL("triggered (bool)"),
656+ self.click_refresh)
657+ return action
658+
659+ def create_ext_diff_action(self):
660+ action = QtGui.QAction(get_icon("system-run"),
661+ gettext("&External Diff"), self)
662+ action.setToolTip(
663+ gettext("Launch an external diff application"))
664+ ext_diff_menu = ExtDiffMenu(parent=self, include_builtin = False)
665+ action.setMenu(ext_diff_menu)
666+ self.connect(ext_diff_menu,
667+ QtCore.SIGNAL("triggered(QString)"),
668+ self.ext_diff_triggered)
669+ return action
670+
671+
672+ def create_view_menu(self):
673+ show_view_menu = QtGui.QAction(get_icon("document-properties"), gettext("&View Options"), self)
674+ view_menu = QtGui.QMenu(gettext('View Options'), self)
675+ show_view_menu.setMenu(view_menu)
676+
677+ view_complete = QtGui.QAction(gettext("&Complete"), self)
678+ view_complete.setCheckable(True)
679+ self.connect(view_complete,
680+ QtCore.SIGNAL("toggled (bool)"),
681+ self.click_complete)
682+ view_menu.addAction(view_complete)
683+
684+ self.ignore_whitespace_action = self.create_ignore_ws_action()
685+ view_menu.addAction(self.ignore_whitespace_action)
686
687 def on_left_encoding_changed(encoding):
688 if self.branches:
689 get_set_encoding(encoding, self.branches[0])
690 self.click_refresh()
691- self.encoding_selector_left = EncodingSelector(encoding,
692- gettext("Left side encoding:"),
693- on_left_encoding_changed)
694+
695+ self.encoding_selector_left = EncodingMenuSelector(self.encoding,
696+ gettext("Left side encoding"),
697+ on_left_encoding_changed)
698+ view_menu.addMenu(self.encoding_selector_left)
699
700 def on_right_encoding_changed(encoding):
701 if self.branches:
702 get_set_encoding(encoding, self.branches[1])
703 self.click_refresh()
704- self.encoding_selector_right = EncodingSelector(encoding,
705- gettext("Right side encoding:"),
706- on_right_encoding_changed)
707-
708-
709- complete = QtGui.QCheckBox (gettext("Complete"),
710- self.centralwidget)
711- self.connect(complete,
712- QtCore.SIGNAL("clicked(bool)"),
713- self.click_complete)
714- complete.setChecked(self.complete);
715-
716- if has_ext_diff():
717- self.menu = ExtDiffMenu(include_builtin = False)
718- ext_diff_button = QtGui.QPushButton(gettext('Using'), self)
719- ext_diff_button.setMenu(self.menu)
720- self.connect(self.menu, QtCore.SIGNAL("triggered(QString)"),
721- self.ext_diff_triggered)
722-
723- buttonbox = self.create_button_box(BTN_CLOSE)
724-
725- refresh = StandardButton(BTN_REFRESH)
726- refresh.setEnabled(self.can_refresh())
727- buttonbox.addButton(refresh, QtGui.QDialogButtonBox.ActionRole)
728- self.connect(refresh,
729- QtCore.SIGNAL("clicked()"),
730- self.click_refresh)
731- self.refresh_button = refresh
732-
733- hbox = QtGui.QHBoxLayout()
734- hbox.addWidget(diffsidebyside)
735- hbox.addWidget(unidiff)
736- hbox.addWidget(complete)
737- if has_ext_diff():
738- hbox.addWidget(ext_diff_button)
739- hbox.addWidget(self.encoding_selector_left)
740- hbox.addWidget(self.encoding_selector_right)
741- hbox.addWidget(buttonbox)
742- vbox.addLayout(hbox)
743+
744+ self.encoding_selector_right = EncodingMenuSelector(self.encoding,
745+ gettext("Right side encoding"),
746+ on_right_encoding_changed)
747+ view_menu.addMenu(self.encoding_selector_right)
748+ return show_view_menu
749+
750+ def create_ignore_ws_action(self):
751+ action = QtGui.QAction(gettext("&Ignore whitespace changes"), self)
752+ action.setCheckable(True)
753+ action.setChecked(self.ignore_whitespace);
754+ self.connect_later(action,
755+ QtCore.SIGNAL("toggled (bool)"),
756+ self.click_ignore_whitespace)
757+ return action
758+
759+ def eventFilter(self, object, event):
760+ if event.type() == QtCore.QEvent.FocusIn:
761+ if object in self.diffview.browsers:
762+ self.find_toolbar.text_edit = object
763+ return QBzrWindow.eventFilter(self, object, event)
764+ # Why doesn't this work?
765+ #return super(DiffWindow, self).eventFilter(object, event)
766
767 def show(self):
768 QBzrWindow.show(self)
769@@ -233,33 +324,33 @@
770 self.throbber.show()
771 op.add_cleanup(self.throbber.hide)
772 op.run()
773-
774+
775 def _initial_load(self, op):
776- (tree1, tree2,
777- branch1, branch2,
778- specific_files) = self.arg_provider.get_diff_window_args(
779- self.processEvents, op.add_cleanup)
780-
781- self.trees = (tree1, tree2)
782- self.branches = (branch1, branch2)
783- self.specific_files = specific_files
784-
785+ args = self.arg_provider.get_diff_window_args(self.processEvents, op.add_cleanup)
786+
787+ self.trees = (args["old_tree"], args["new_tree"])
788+ self.branches = (args.get("old_branch", None), args.get("new_branch",None))
789+ self.specific_files = args.get("specific_files", None)
790+ self.ignore_whitespace = args.get("ignore_whitespace", False)
791+ self.ignore_whitespace_action.setChecked(self.ignore_whitespace)
792+
793+ self.process_delayed_connections()
794 self.load_branch_info()
795 self.load_diff()
796-
797+
798 def load_branch_info(self):
799 self.set_diff_title()
800-
801+
802 self.encoding_selector_left.encoding = get_set_encoding(self.encoding, self.branches[0])
803 self.encoding_selector_right.encoding = get_set_encoding(self.encoding, self.branches[1])
804 self.processEvents()
805-
806+
807 def set_diff_title(self):
808 rev1_title = get_title_for_tree(self.trees[0], self.branches[0],
809 self.branches[1])
810 rev2_title = get_title_for_tree(self.trees[1], self.branches[1],
811 self.branches[0])
812-
813+
814 title = [gettext("Diff"), "%s..%s" % (rev1_title, rev2_title)]
815
816 if self.specific_files:
817@@ -277,7 +368,7 @@
818 self.processEvents()
819
820 def load_diff(self):
821- self.refresh_button.setEnabled(False)
822+ self.view_refresh.setEnabled(False)
823 for tree in self.trees: tree.lock_read()
824 self.processEvents()
825 try:
826@@ -337,7 +428,7 @@
827 # ghosts around us (see Bug #513096)
828 dates[ix] = 0 # using 1970/1/1 instead
829
830- properties_changed = []
831+ properties_changed = []
832 if bool(executable[0]) != bool(executable[1]):
833 descr = {True: "+x", False: "-x", None: None}
834 properties_changed.append((descr[executable[0]],
835@@ -374,12 +465,7 @@
836 elif versioned == (False, True):
837 groups = [[('insert', 0, 0, 0, len(lines[1]))]]
838 else:
839- matcher = SequenceMatcher(None, lines[0], lines[1])
840- self.processEvents()
841- if self.complete:
842- groups = list([matcher.get_opcodes()])
843- else:
844- groups = list(matcher.get_grouped_opcodes())
845+ groups = self.difference_groups(lines[0], lines[1])
846 ulines = []
847 for l, encoding in zip(lines, [self.encoding_selector_left.encoding,
848 self.encoding_selector_right.encoding]):
849@@ -416,18 +502,34 @@
850 QtGui.QMessageBox.information(self, gettext('Diff'),
851 gettext('No changes found.'),
852 gettext('&OK'))
853- self.refresh_button.setEnabled(self.can_refresh())
854-
855- def click_unidiff(self, checked):
856- if checked:
857- self.sdiffview.rewind()
858- self.stack.setCurrentIndex(1)
859-
860- def click_diffsidebyside(self, checked):
861- if checked:
862- self.diffview.rewind()
863- self.stack.setCurrentIndex(0)
864-
865+ self.view_refresh.setEnabled(self.can_refresh())
866+
867+ def difference_groups(self, left, right):
868+ if self.ignore_whitespace:
869+ table = string.maketrans("", "")
870+ strip = lambda l : l.translate(table, string.whitespace)
871+ left = (line.translate(table, string.whitespace) for line in left)
872+ right = (line.translate(table, string.whitespace) for line in right)
873+ matcher = SequenceMatcher(None, left, right)
874+ self.processEvents()
875+ if self.complete:
876+ groups = list([matcher.get_opcodes()])
877+ else:
878+ groups = list(matcher.get_grouped_opcodes())
879+
880+ return groups
881+
882+ def click_toggle_view_mode(self, checked):
883+ if checked:
884+ view = self.sdiffview
885+ self.find_toolbar.text_edit = view
886+ else:
887+ view = self.diffview
888+ self.find_toolbar.text_edit = view.browsers[0]
889+ view.rewind()
890+ index = self.stack.indexOf(view)
891+ self.stack.setCurrentIndex(index)
892+
893 def click_complete(self, checked ):
894 self.complete = checked
895 #Has the side effect of refreshing...
896@@ -448,7 +550,15 @@
897 if isinstance(tree1, MutableTree) or isinstance(tree2, MutableTree):
898 return True
899 return False
900-
901+
902 def ext_diff_triggered(self, ext_diff):
903 """@param ext_diff: path to external diff executable."""
904 show_diff(self.arg_provider, ext_diff=ext_diff, parent_window = self)
905+
906+ def click_ignore_whitespace(self, checked ):
907+ self.ignore_whitespace = checked
908+ #Has the side effect of refreshing...
909+ self.diffview.clear()
910+ self.sdiffview.clear()
911+ run_in_loading_queue(self.load_diff)
912+
913
914=== modified file 'lib/resources.py'
915--- lib/resources.py 2009-12-22 22:04:05 +0000
916+++ lib/resources.py 2010-10-16 08:18:41 +0000
917@@ -2,8 +2,8 @@
918
919 # Resource object code
920 #
921-# Created: Fri Dec 18 15:04:38 2009
922-# by: The Resource Compiler for PyQt (Qt v4.5.2)
923+# Created: Ma aug. 31 02:22:47 2010
924+# by: The Resource Compiler for PyQt (Qt v4.7.0)
925 #
926 # WARNING! All changes made in this file will be lost!
927
928@@ -323,6 +323,111 @@
929 \x62\x92\x6e\xdf\x1c\xb8\x35\x76\xd9\x24\xeb\x89\x72\x63\xe8\xfd\
930 \xc4\xfa\x07\x16\xd6\x69\xc5\x45\xde\xc7\x7f\x00\x00\x00\x00\x49\
931 \x45\x4e\x44\xae\x42\x60\x82\
932+\x00\x00\x05\x0c\
933+\x89\
934+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
935+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
936+\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
937+\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\
938+\x1b\xaf\x01\x5e\x1a\x91\x1c\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
939+\xd7\x0c\x1c\x0b\x31\x3b\x67\xd3\x82\x66\x00\x00\x04\x99\x49\x44\
940+\x41\x54\x78\xda\xa5\x55\x5d\x48\x64\x65\x18\x7e\xe6\xcc\x9f\xff\
941+\x4e\x88\xbf\xad\x4e\xce\xe8\xec\x68\xe9\x62\x20\x76\xb1\x26\x95\
942+\xe0\xb6\x5d\x2d\x6d\xc4\xae\x17\xe1\x55\x14\xe6\x85\x8a\x46\x17\
943+\xe2\x7a\x25\x4a\x48\x17\x11\x0a\x09\x11\x11\xc4\x8a\x11\x2b\xe5\
944+\x4f\xcb\x6a\x8b\xcb\x48\x6a\xd6\xd8\x34\xea\xe8\x8e\xab\xe3\xff\
945+\xfc\xff\x9e\x99\x39\xa7\xf7\x3b\x71\x16\xd4\xc2\xa2\x07\x1e\xe6\
946+\xcc\xf9\xbe\x79\xbf\xf7\x7d\xde\xe7\x7b\x47\x81\x7f\x81\xf1\xf1\
947+\xf1\xb7\xd2\xd3\xd3\xcb\x95\x4a\x25\xf6\xf7\xf7\xd7\x9a\x9b\x9b\
948+\xef\xe2\xff\xa2\xba\xba\x5a\x65\xb1\x58\x62\xa1\x50\x48\x64\x5c\
949+\x58\x58\x88\xd5\xd6\xd6\xaa\x70\x01\x38\x9c\x41\x4f\x4f\x4f\xfd\
950+\xd0\xd0\x50\x93\xfc\xbd\xb0\xb0\xb0\x88\xb2\x55\xb3\x6c\x19\xd3\
951+\xd2\xd2\xd4\x45\x04\x79\x7d\x72\x72\xf2\xda\xe8\xe8\x68\x3d\xce\
952+\xe0\x94\x14\x7d\x7d\x7d\xb7\x08\x5f\xa8\x54\x2a\x6e\x6c\x6c\xec\
953+\x4e\x59\x59\x59\xa5\xc9\x64\xba\x51\x52\x52\xa2\x05\x41\x14\x45\
954+\x89\xbb\xbb\xbb\x31\x87\xc3\x31\xae\xd1\x68\x6c\x54\x51\x4f\x22\
955+\x91\x10\xa6\xa7\xa7\xdf\x69\x69\x69\xf9\x1a\x67\xd1\xde\xde\x5e\
956+\xbf\xba\xba\xca\xfb\x7c\x3e\x51\x2e\x3b\x1c\x0e\x4b\x9f\xc1\x60\
957+\x50\x0c\x04\x02\xa2\xdf\xef\x17\xbd\x5e\xaf\xe8\xf1\x78\x44\xb7\
958+\xdb\x2d\x9e\x9c\x9c\x88\xc7\xc7\xc7\x22\xe9\x2e\xda\xed\x76\xbe\
959+\xbb\xbb\xfb\xaa\x1c\xef\xa9\x56\x54\x6e\x1a\x65\xc3\x45\x22\x11\
960+\x64\x64\x64\x80\xb2\x06\x43\x38\x1c\x81\xc3\xe9\x82\x3f\x18\x41\
961+\x32\x29\x20\x3d\x55\x03\xfd\xb3\xb9\xd0\x68\xd4\x2c\x7b\x7a\x97\
962+\x04\xcf\xf3\xa0\x24\x38\x42\x86\x1c\x4f\x29\x3f\xcc\xcd\xcd\x39\
963+\x8c\x46\x23\xca\xcb\xcb\x5f\x11\x04\x01\xa9\xa9\xa9\xb0\x3b\xb6\
964+\x61\x59\x71\x20\x29\x72\x10\x88\x7c\x42\xc0\x89\x37\x8c\xe5\xdf\
965+\xb7\xc0\x21\x89\x67\xb2\x33\x10\x8b\xc5\x58\x50\x4c\x4c\x4c\xdc\
966+\xe9\xed\xed\xfd\xfc\x5c\xc6\x0c\x59\x59\x59\x2f\x50\x50\x69\xf3\
967+\xe2\x8a\x0d\x6b\xce\x13\x6a\x56\x0a\x3c\xbe\x20\xe2\x89\xa4\x44\
968+\x9e\x4f\xd0\x01\x22\xee\x2f\x6c\x20\xc6\xc7\x71\x29\x5f\xc7\xf6\
969+\xb3\x2a\xcd\x90\x21\x67\x5c\x57\x57\xa7\x22\x16\x37\x36\x36\x7e\
970+\x9a\x9d\x9d\xad\x64\x25\xff\x68\xb1\xb3\xde\x4a\x52\x94\x17\xeb\
971+\x00\x21\x86\x9d\x7d\x2f\x42\x31\x01\x5e\x7f\x08\xc1\x50\x04\x36\
972+\x87\x0b\x95\x86\x5c\x30\x68\xb5\x5a\x33\xf5\xe7\x4b\x9d\x4e\x17\
973+\xa4\xe6\x0a\x8a\xe1\xe1\xe1\x9b\x55\x55\x55\x5f\x69\x48\x34\x5a\
974+\x54\x30\x6d\x1f\xbb\xdc\x78\xb8\xb4\x05\x25\x3d\xd7\x3c\x6f\xc4\
975+\xeb\x2f\x57\x81\x9a\x08\xb7\xc7\x83\x9f\x7f\xdd\x80\xc5\xea\xc2\
976+\x91\x3b\x80\x60\x30\x84\xdb\xd7\x6b\x70\xd9\x50\x28\x59\x31\x1a\
977+\x8d\x8a\xe4\x90\x38\x79\xbd\x99\xa3\xee\x9a\x48\x74\x0d\x4b\x8f\
978+\x35\x82\xf1\xf1\xce\x31\xf6\x0e\x3d\xf0\xf8\xa3\x88\x0b\xdc\xd3\
979+\x26\x69\x35\x1a\xbc\x76\xf5\x45\xbc\x7f\xfb\x55\x7a\xaf\x80\xeb\
980+\xd0\x0d\xdb\xd6\x01\x0b\x2a\xad\x2b\xfe\x82\x86\x1c\x64\xe2\x98\
981+\x3e\xf1\x78\x1c\x74\x12\xa3\xb4\xe1\xe0\xd8\x8b\xbb\xdf\x3f\xc2\
982+\xdc\xd2\x26\x5c\x27\x61\xc8\x20\xfd\xa5\x75\x97\x3b\x86\x95\xb5\
983+\x3d\xd8\x37\x5d\x14\x8c\x63\xef\xe5\xdf\xb3\x58\x8c\x0a\x15\x95\
984+\xe8\x20\x2f\xc6\xc9\x6e\xaa\xcc\xcc\x4c\x05\x08\xa6\xd2\x02\x29\
985+\xcb\x48\x94\x47\x30\x92\x80\x0c\x7f\x8c\xc3\xec\xe2\x21\x7e\x98\
986+\xfb\x4d\xd2\x9f\xb6\xe0\x32\xed\x95\x03\x32\xaf\x53\xbc\x04\xf9\
987+\x7e\x43\x35\x38\x38\xf8\x4d\x4e\x4e\xce\x77\x15\x15\x15\x97\x3a\
988+\x3b\x3b\xad\xf9\xf9\xf9\x1a\xf3\x73\xb9\x30\x96\xe4\xe1\xd0\xe7\
989+\xc3\x4f\xcb\x5b\x28\x2b\x2d\x86\x36\x2d\x0b\xf6\x9d\x04\x9c\x4f\
990+\xfc\xa4\x65\x04\xa1\x80\x0f\x65\xfa\x3c\x98\xf4\xb9\xe4\x94\x18\
991+\x0e\x0e\x0e\xf8\xfe\xfe\xfe\x6a\x9b\xcd\xf6\x84\x9a\x18\x91\x5c\
992+\x41\x97\x22\xb1\xbd\xbd\xed\x6e\x68\x68\xb8\x92\x97\x97\x57\x09\
993+\xc2\x15\xb3\x1e\xf7\xee\x2f\x92\x2b\xa2\xd8\xf7\x09\xf0\x47\x15\
994+\xf0\xf9\x03\x70\x3a\x9d\xd8\x5c\xb7\x21\x1a\xf2\xe2\xe3\x0f\x6f\
995+\x21\x3d\x85\x93\x32\x5e\x5f\x5f\x1f\x1f\x19\x19\xf9\x8c\xa4\x8d\
996+\x9f\xf3\x31\x5d\x51\x2b\x2d\xdc\x64\x37\x29\x37\x5b\x8d\x4f\x3e\
997+\x7a\x1b\x83\xa3\x53\x78\x34\x37\x03\xeb\x2f\x3a\x30\x04\xfc\x3e\
998+\xe8\x0b\xb3\x31\x3c\xf4\x01\xcc\x86\x02\x96\xa9\x14\x98\xe4\xb4\
999+\xfe\xed\x10\xa2\xd3\x9a\xe8\xd6\x4d\xa8\xd5\x6a\x25\x81\x5d\x69\
1000+\x89\x6a\x72\xc2\x1f\x9b\xfb\x58\x77\x1e\x82\x53\x28\x60\x36\x16\
1001+\x51\x35\x25\xcc\x01\x60\x60\x49\xd0\xfc\x00\xe9\x9a\x5c\x5a\x5a\
1002+\x7a\xa3\xa3\xa3\x63\xf2\x54\xc6\x54\x4a\xc2\x60\x30\x88\x34\x16\
1003+\x21\x8f\x48\xb2\x21\x44\xea\xb8\xb9\x34\x9f\x91\x05\x63\x64\xd2\
1004+\x9d\x72\x0a\x25\xc3\xdc\x22\xba\x5c\xae\xc4\xb9\x59\x31\x3f\x3f\
1005+\xbf\x45\xe3\xd1\xa5\xd7\xeb\xaf\xd3\x66\x91\x66\xc7\x20\x35\x61\
1006+\x2f\x25\x25\xc5\x48\x73\x43\xc5\x02\xca\x81\x8e\x8e\x8e\xa2\x56\
1007+\xab\xf5\xdb\xe5\xe5\xe5\x7b\xd4\x93\x97\xe8\x20\x61\x66\x66\xe6\
1008+\xbd\x81\x81\x81\x31\xfc\x13\xda\xda\xda\x9a\xba\xba\xba\x6e\x30\
1009+\x99\x18\x6b\x6a\x6a\x4c\xb3\xb3\xb3\x02\x8d\x54\x91\xf1\xc1\x83\
1010+\x07\x02\x7b\x27\xaf\x53\xe9\x6f\xb6\xb6\xb6\x5e\xc3\x7f\x45\x41\
1011+\x41\x81\x76\x6a\x6a\x8a\x27\x1b\x89\x8c\xf4\x8f\xc1\xd3\x1f\x88\
1012+\x16\x17\x40\x85\x0b\x40\x43\x9c\xa7\x8c\xdf\xa5\x60\x26\x10\x48\
1013+\xc7\x35\x22\x8f\x0b\xf0\x27\x9b\x2f\xb2\xa4\xb3\x87\x63\xc7\x00\
1014+\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
1015+\x00\x00\x01\x3c\
1016+\x89\
1017+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
1018+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
1019+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
1020+\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
1021+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\
1022+\x1e\x75\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x0c\x1c\
1023+\x14\x18\x23\xd6\xd5\xd3\x43\x00\x00\x00\xbc\x49\x44\x41\x54\x38\
1024+\xcb\xed\x95\xc1\x0a\x82\x40\x14\x45\xcf\xe8\xe4\x62\x92\x90\x96\
1025+\x05\xf5\x0b\xd1\xb7\x4b\xbf\xd1\x1f\x08\xba\x6a\x6d\xe5\x62\xe6\
1026+\x4d\xb6\x28\xb4\x85\x88\x81\x42\x90\x77\x75\x07\xce\x3b\x0c\xbc\
1027+\xc5\x53\xbc\xa2\x18\x37\xb5\x02\x56\xc0\x1e\x58\x8c\x24\x75\x40\
1028+\xae\x81\x5d\x55\x55\xe7\xc7\xa3\x0e\xc7\xb0\x06\x81\xf2\xc6\x98\
1029+\x83\x06\xa2\xb2\xbc\x86\x5a\x6b\x00\x6e\xb7\x7b\xef\x60\x1c\x2f\
1030+\x1b\xae\xab\x8b\x48\x08\x44\xfa\xfd\xa0\x28\x72\x00\x92\x64\xdd\
1031+\x2b\xce\xb2\x4b\xc3\x75\xf5\xcd\x66\x0b\x80\x06\x70\x4e\x30\x26\
1032+\x06\xc0\x5a\xdb\x2b\xfe\xe4\xba\xba\x73\xd2\x8a\xbd\x17\x44\x64\
1033+\x94\xcd\x79\xdf\x7a\x8e\xf5\xc0\xa4\xe9\x69\x10\x07\x1c\x83\xef\
1034+\x36\x3e\x1c\x9f\xc5\xb3\xf8\x0f\xc5\xfc\xc6\x8f\xed\x04\x62\x3b\
1035+\xd9\x69\x52\x53\x1d\xd3\x27\xd3\xf0\x95\x3a\x8b\x52\x56\x44\x00\
1036+\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
1037 \x00\x00\x02\x90\
1038 \x89\
1039 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
1040@@ -1714,6 +1819,15 @@
1041 \x00\x68\x15\xe7\
1042 \x00\x62\
1043 \x00\x7a\x00\x72\x00\x2d\x00\x33\x00\x32\x00\x2e\x00\x70\x00\x6e\x00\x67\
1044+\x00\x0e\
1045+\x09\x14\x31\x07\
1046+\x00\x73\
1047+\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x2d\x00\x72\x00\x75\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
1048+\x00\x19\
1049+\x01\x7d\x34\xe7\
1050+\x00\x76\
1051+\x00\x69\x00\x65\x00\x77\x00\x2d\x00\x73\x00\x70\x00\x6c\x00\x69\x00\x74\x00\x2d\x00\x6c\x00\x65\x00\x66\x00\x74\x00\x2d\x00\x72\
1052+\x00\x69\x00\x67\x00\x68\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
1053 \x00\x11\
1054 \x01\x82\x9d\x27\
1055 \x00\x69\
1056@@ -1824,36 +1938,38 @@
1057
1058 qt_resource_struct = "\
1059 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x01\
1060-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x10\x00\x00\x00\x0f\
1061-\x00\x00\x00\x10\x00\x02\x00\x00\x00\x09\x00\x00\x00\x06\
1062+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x10\x00\x00\x00\x11\
1063+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x0b\x00\x00\x00\x06\
1064 \x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x09\xe9\
1065 \x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x79\
1066 \x00\x00\x00\x20\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
1067+\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x18\x35\
1068+\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x19\x75\
1069+\x00\x00\x01\x10\x00\x00\x00\x00\x00\x01\x00\x00\x20\x4f\
1070+\x00\x00\x01\xca\x00\x00\x00\x00\x00\x01\x00\x00\x36\x18\
1071+\x00\x00\x01\x84\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x68\
1072+\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x30\xc0\
1073 \x00\x00\x00\x6e\x00\x00\x00\x00\x00\x01\x00\x00\x13\x25\
1074-\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x19\xff\
1075-\x00\x00\x01\x70\x00\x00\x00\x00\x00\x01\x00\x00\x2f\xc8\
1076-\x00\x00\x01\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x24\x18\
1077-\x00\x00\x01\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x70\
1078-\x00\x00\x00\x96\x00\x00\x00\x00\x00\x01\x00\x00\x15\xb9\
1079-\x00\x00\x01\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x20\x72\
1080-\x00\x00\x01\x90\x00\x00\x00\x00\x00\x01\x00\x00\x36\x2f\
1081-\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\x1c\xb3\
1082-\x00\x00\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x42\xe2\
1083-\x00\x00\x03\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x63\x38\
1084-\x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x40\x66\
1085-\x00\x00\x03\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x55\xd4\
1086-\x00\x00\x01\xac\x00\x00\x00\x00\x00\x01\x00\x00\x3a\x51\
1087-\x00\x00\x03\x68\x00\x00\x00\x00\x00\x01\x00\x00\x5b\x14\
1088-\x00\x00\x01\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x5c\xd3\
1089-\x00\x00\x02\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x4c\x2b\
1090-\x00\x00\x03\x3c\x00\x00\x00\x00\x00\x01\x00\x00\x58\x40\
1091-\x00\x00\x02\xde\x00\x00\x00\x00\x00\x01\x00\x00\x51\x0a\
1092-\x00\x00\x02\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x49\xac\
1093-\x00\x00\x02\x16\x00\x00\x00\x00\x00\x01\x00\x00\x44\x4f\
1094-\x00\x00\x02\x42\x00\x00\x00\x00\x00\x01\x00\x00\x47\x0a\
1095-\x00\x00\x03\x86\x00\x00\x00\x00\x00\x01\x00\x00\x60\x67\
1096-\x00\x00\x02\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x4e\x89\
1097-\x00\x00\x02\xf8\x00\x00\x00\x00\x00\x01\x00\x00\x53\x00\
1098+\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x09\
1099+\x00\x00\x01\x68\x00\x00\x00\x00\x00\x01\x00\x00\x26\xc2\
1100+\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x7f\
1101+\x00\x00\x01\x44\x00\x00\x00\x00\x00\x01\x00\x00\x23\x03\
1102+\x00\x00\x02\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x49\x32\
1103+\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x69\x88\
1104+\x00\x00\x02\x32\x00\x00\x00\x00\x00\x01\x00\x00\x46\xb6\
1105+\x00\x00\x03\x78\x00\x00\x00\x00\x00\x01\x00\x00\x5c\x24\
1106+\x00\x00\x02\x06\x00\x00\x00\x00\x00\x01\x00\x00\x40\xa1\
1107+\x00\x00\x03\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x61\x64\
1108+\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x63\x23\
1109+\x00\x00\x02\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x52\x7b\
1110+\x00\x00\x03\x96\x00\x00\x00\x00\x00\x01\x00\x00\x5e\x90\
1111+\x00\x00\x03\x38\x00\x00\x00\x00\x00\x01\x00\x00\x57\x5a\
1112+\x00\x00\x02\xc4\x00\x00\x00\x00\x00\x01\x00\x00\x4f\xfc\
1113+\x00\x00\x02\x70\x00\x00\x00\x00\x00\x01\x00\x00\x4a\x9f\
1114+\x00\x00\x02\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x4d\x5a\
1115+\x00\x00\x03\xe0\x00\x00\x00\x00\x00\x01\x00\x00\x66\xb7\
1116+\x00\x00\x03\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x54\xd9\
1117+\x00\x00\x03\x52\x00\x00\x00\x00\x00\x01\x00\x00\x59\x50\
1118 "
1119
1120 def qInitResources():
1121
1122=== modified file 'lib/util.py'
1123--- lib/util.py 2010-09-06 09:13:15 +0000
1124+++ lib/util.py 2010-10-16 08:18:41 +0000
1125@@ -745,6 +745,15 @@
1126 done.add(item)
1127 combo.addItem(item)
1128
1129+def show_shortcut_hint(action):
1130+ """Show this action's shortcut, if any, as part of the tooltip.
1131+
1132+ Make sure to set the shortcut and tooltip *before* calling this.
1133+ """
1134+ shortcut = action.shortcut()
1135+ if shortcut and shortcut.toString():
1136+ toolTip = action.toolTip()
1137+ action.setToolTip("%s (%s)" % (toolTip, shortcut.toString()))
1138
1139 def iter_saved_pull_locations():
1140 """ Iterate the 'pull' locations we have previously saved for the user.
1141@@ -1022,9 +1031,11 @@
1142
1143 prev = self.addAction(get_icon("go-previous"), gettext("Previous"))
1144 prev.setShortcut(QtGui.QKeySequence.FindPrevious)
1145+ show_shortcut_hint(prev)
1146
1147 next = self.addAction(get_icon("go-next"), gettext("Next"))
1148 next.setShortcut(QtGui.QKeySequence.FindNext)
1149+ show_shortcut_hint(next)
1150
1151 self.case_sensitive = QtGui.QCheckBox(gettext("Case sensitive"), self)
1152 self.addWidget(self.case_sensitive)
1153@@ -1088,7 +1099,7 @@
1154 self.find(self.text_edit.textCursor().selectionStart(), 0,
1155 self.find_get_flags())
1156
1157- def find_next(self, state):
1158+ def find_next(self):
1159 self.find(self.text_edit.textCursor().selectionEnd(), 0,
1160 self.find_get_flags())
1161
1162@@ -1112,6 +1123,10 @@
1163 else:
1164 self.text_edit.setTextCursor(cursor)
1165
1166+ def set_text_edit(self, new_text_edit):
1167+ if self.text_edit:
1168+ self.text_edit.setTextCursor(QtGui.QTextCursor())
1169+ self.text_edit = new_text_edit
1170
1171 class InfoWidget(QtGui.QFrame):
1172 def __init__(self, parent=None):

Subscribers

People subscribed via source and target branches