Merge lp:~saccadic-masking/qbrz/qbrz into lp:qbrz

Proposed by Robert Ladyman
Status: Merged
Merge reported by: Jelmer Vernooij
Merged at revision: not available
Proposed branch: lp:~saccadic-masking/qbrz/qbrz
Merge into: lp:qbrz
Diff against target: 88946 lines (+72905/-4332)
156 files modified
.bzrignore (+7/-2)
MakeLiterate (+86/-0)
Makefile (+234/-20)
__init__.py (+11/-3)
docs/Makefile (+4/-3)
docs/literate/pycco.css (+191/-0)
docs/pycco.css (+191/-0)
extras/__init__.py (+7/-7)
extras/build_mo.py (+12/-11)
extras/build_pot.py (+23/-17)
extras/build_ui.py (+3/-2)
extras/check_py24.py (+1/-1)
extras/check_utf8.py (+1/-1)
extras/en_po.py (+1/-6)
extras/import_po.py (+1/-1)
installer/qbrz-setup.iss (+33/-33)
iscc (+5/-0)
lib/__init__.py (+6/-4)
lib/add.py (+58/-61)
lib/annotate.py (+114/-119)
lib/autocomplete.py (+2/-2)
lib/bind.py (+1/-1)
lib/branch.py (+5/-5)
lib/browse.py (+2/-2)
lib/bugs.py (+2/-2)
lib/cat.py (+11/-10)
lib/cleanup.py (+184/-0)
lib/commands.py (+81/-114)
lib/commit.py (+102/-96)
lib/commit_data.py (+5/-5)
lib/conditional_dataview.py (+3/-3)
lib/config.py (+115/-120)
lib/conflicts.py (+14/-14)
lib/decorators.py (+2/-2)
lib/diff.py (+72/-68)
lib/diffview.py (+51/-58)
lib/diffwindow.py (+24/-21)
lib/encoding_selector.py (+11/-9)
lib/export.py (+8/-8)
lib/extra/bugurl.py (+4/-7)
lib/extra/isignored.py (+2/-2)
lib/extra/isversioned.py (+2/-2)
lib/fake_branch.py (+1/-1)
lib/getnew.py (+6/-6)
lib/getupdates.py (+4/-4)
lib/html_log.py (+15/-4)
lib/i18n.py (+5/-2)
lib/ignore.py (+8/-8)
lib/info.py (+3/-3)
lib/init.py (+5/-5)
lib/lazycachedrevloader.py (+3/-3)
lib/log.py (+207/-190)
lib/loggraphviz.py (+269/-269)
lib/logmodel.py (+24/-24)
lib/logwidget.py (+118/-141)
lib/main.py (+57/-61)
lib/plugins.py (+2/-4)
lib/pull.py (+11/-14)
lib/resources.py (+3/-3)
lib/revert.py (+25/-29)
lib/revisionmessagebrowser.py (+59/-57)
lib/revtreeview.py (+45/-58)
lib/run.py (+45/-72)
lib/send.py (+7/-7)
lib/shelvewindow.py (+8/-13)
lib/spellcheck.py (+1/-1)
lib/spellcheck_enchant.py (+1/-1)
lib/statuscache.py (+20/-17)
lib/subprocess.py (+410/-245)
lib/switch.py (+3/-3)
lib/syntaxhighlighter.py (+1/-1)
lib/sysinfo.py (+6/-7)
lib/sysinfo_data.py (+6/-6)
lib/tag.py (+7/-7)
lib/tests/__init__.py (+11/-6)
lib/tests/mock.py (+6/-6)
lib/tests/modeltest.py (+86/-32)
lib/tests/test_annotate.py (+19/-19)
lib/tests/test_autocomplete.py (+2/-3)
lib/tests/test_bugs.py (+31/-29)
lib/tests/test_cat.py (+6/-1)
lib/tests/test_commit.py (+4/-0)
lib/tests/test_commit_data.py (+9/-13)
lib/tests/test_decorator.py (+1/-1)
lib/tests/test_diffview.py (+11/-11)
lib/tests/test_extdiff.py (+24/-32)
lib/tests/test_extra_isignored.py (+5/-4)
lib/tests/test_extra_isversioned.py (+4/-4)
lib/tests/test_guidebar.py (+50/-32)
lib/tests/test_i18n.py (+6/-4)
lib/tests/test_log.py (+21/-33)
lib/tests/test_loggraphviz.py (+394/-396)
lib/tests/test_logmodel.py (+10/-19)
lib/tests/test_revisionmessagebrowser.py (+2/-2)
lib/tests/test_spellcheck.py (+7/-7)
lib/tests/test_subprocess.py (+78/-61)
lib/tests/test_treewidget.py (+176/-155)
lib/tests/test_util.py (+110/-109)
lib/texteditannotate.py (+4/-4)
lib/trace.py (+45/-48)
lib/tree_branch.py (+1/-1)
lib/treewidget.py (+599/-508)
lib/ui_bookmark.py (+27/-16)
lib/ui_branch.py (+20/-14)
lib/ui_info.py (+21/-12)
lib/ui_init.py (+65/-54)
lib/ui_merge.py (+36/-25)
lib/ui_merge_config.py (+32/-20)
lib/ui_new_tree.py (+81/-70)
lib/ui_pull.py (+34/-23)
lib/ui_push.py (+2/-1)
lib/ui_run.py (+49/-39)
lib/ui_sysinfo.py (+75/-84)
lib/ui_tag.py (+52/-35)
lib/ui_update_branch.py (+48/-31)
lib/ui_update_checkout.py (+36/-25)
lib/ui_verify_signatures.py (+11/-3)
lib/uifactory.py (+1/-1)
lib/uncommit.py (+12/-24)
lib/util.py (+102/-85)
lib/verify_signatures.py (+16/-29)
lib/widgets/shelve.py (+7/-7)
lib/widgets/shelvelist.py (+3/-3)
lib/widgets/tab_width_selector.py (+4/-4)
lib/widgets/texteditaccessory.py (+3/-3)
lib/win32util.py (+2/-2)
po/qbrz-ar.po (+2380/-0)
po/qbrz-cs.po (+2379/-0)
po/qbrz-da.po (+2406/-0)
po/qbrz-de.po (+2543/-0)
po/qbrz-en.po (+2435/-0)
po/qbrz-en_GB.po (+2532/-0)
po/qbrz-es.po (+2522/-0)
po/qbrz-et.po (+2516/-0)
po/qbrz-fr.po (+2434/-0)
po/qbrz-gl.po (+2385/-0)
po/qbrz-he.po (+2394/-0)
po/qbrz-hu.po (+2391/-0)
po/qbrz-it.po (+2514/-0)
po/qbrz-ja.po (+2508/-0)
po/qbrz-nl.po (+2481/-0)
po/qbrz-pl.po (+2496/-0)
po/qbrz-pt_BR.po (+2436/-0)
po/qbrz-ru.po (+2514/-0)
po/qbrz-sk.po (+2386/-0)
po/qbrz-sl.po (+2380/-0)
po/qbrz-sr.po (+2380/-0)
po/qbrz-sv.po (+2382/-0)
po/qbrz-th.po (+2379/-0)
po/qbrz-tr.po (+2411/-0)
po/qbrz-uk.po (+2396/-0)
po/qbrz.pot (+2375/-0)
qbrz-0.23.2-20191027brz1531-fix_pyqt412.patch (+3923/-0)
run-tests.sh (+2/-1)
setup.py (+20/-7)
ui/sysinfo.ui (+67/-66)
To merge this branch: bzr merge lp:~saccadic-masking/qbrz/qbrz
Reviewer Review Type Date Requested Status
Robert Ladyman Approve
Breezy developers Pending
Review via email: mp+387526@code.launchpad.net

Commit message

Updated to work with Python3: still using PyQt4. Applied Olaf Seibert's and Yasuyuki Furukawa's suggested changes. Note that, for me, qmain, qverify-signatures and qhelp did not work with bzr, so have not been fully updated.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Awesome, this is great to see!

I'm not entirely sure how to go about reviewing this since it's so large - it exceeds the 5000 line limit from Launchpad. I don't think it's realistic to review everything in detail so perhaps we can just stick to the higher level bits.

Are you the author of all of the files that are being added, including e.g. the css files?

Revision history for this message
Robert Ladyman (saccadic-masking) wrote :

Dear Jelmer,

It's the old code updated. I have taken the code changes by Olaf Seibert
(He ran 2 to 3 to convert to Python3), applied (partially) the patch
from Yasuyuki Furukawa to slightly update the PyQt4 calls:

(https://bugs.launchpad.net/qbrz/+bug/1850054/comments/5)

and then worked at it all to get the tests to pass and then to test each
command (as the tests often passed even if the code failed). My hair is
now even more grey.

If it's too big to merge, it might be easier to replace trunk with this
(the old trunk doesn't work in Python 3 anyway). Almost every file has
been changed, including Makefiles: I managed to use the old translation
files without change, so it also works in the other languages (although
they will need QBzr / Bazaar changed to QBrz / Breezy, which I can do)
and have updated the release mechanism so there is an .exe as well as a
.tar.gz (I can't test the .exe though).

I have not updated all the brz references nor the Author / Readme files
yet: wasn't certain it would be accepted or work well enough.

I'll update it with the textual changes, etc. I expect that there are
the odd bits that are still broken, but I am using this now every day
and about to rewrite two of our own tools (EasyBreezy and bzr-xmpp) for
Breezy: I will apply bug-fixes as I go.

I cannot test it on Windows, as I've discovered, so am now looking at
the brz code, which I note has a whole tools/win32 section with the old
bazaar Makefiles, etc., in it, to get a working Breezy .exe to install.

Regards,
RJL

P.S. the literate documentation is produced by pycco, which sometimes
gets things horribly wrong. I'll fix pycco later and re-run it then.
Another project.

On 16/07/2020 21:08, Jelmer Vernooij wrote:
> Awesome, this is great to see!
>
> I'm not entirely sure how to go about reviewing this since it's so large - it exceeds the 5000 line limit from Launchpad. I don't think it's realistic to review everything in detail so perhaps we can just stick to the higher level bits.
>
> Are you the author of all of the files that are being added, including e.g. the css files?
>

--
Robert Ladyman
HunterBirnie
Tel: +44 (0) 1828 898 158
Mobile: +44 (0) 7732 771 649
http://www.hunterbirnie.com
PGP: E40A2EE2AA9991E7
*************************************************************
HunterBirnie is a trading name of File-Away Limited
Registered in Scotland, Company Number: SC222086
Registered address: 30 Church St, Newtyle PH128TZ

Revision history for this message
Robert Ladyman (saccadic-masking) wrote :

To add: pycco creates the CSS files.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Yeah, replacing trunk with your branch is probably the best option.

I don't think I'll have time to do a meaningful review, and if I did do that I'm not sure whether that would be a valuable use of your or my time. I also don't have a good way of running qbrz myself, since python3-pyqt4 is no longer available on Debian.

Let me create a new team for qbrz and add you to that, and then we can pull your changes into trunk. I'm happy to review incremental changes on top of this branch if you think that would be useful, but otherwise feel free to just directly push to trunk.

Revision history for this message
Robert Ladyman (saccadic-masking) wrote :

OK, that seems easiest: plus it means I can fix any lurking problems that I find as I use it and keep it in step with breezy itself. The patches will be smaller in future.

Revision history for this message
Robert Ladyman (saccadic-masking) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-10-11 15:20:54 +0000
3+++ .bzrignore 2020-07-16 14:28:25 +0000
4@@ -2,6 +2,11 @@
5 ./build
6 ./docs/**/*.html
7 ./launchpad-export.tar.gz
8-./locale
9-./MANIFEST
10 tags
11+*.tar.gz
12+*.tar.gz.asc
13+.vscode/bookmarks.json
14+.vscode
15+qbrz-setup-iss.log
16+*.exe
17+*.exe.asc
18
19=== added file 'MakeLiterate'
20--- MakeLiterate 1970-01-01 00:00:00 +0000
21+++ MakeLiterate 2020-07-16 14:28:25 +0000
22@@ -0,0 +1,86 @@
23+# RJL: This will make literate documents via pycco in docs/literate
24+# Run this makefile via
25+#
26+# make -f MakeLiterate...
27+#
28+# You should note that pycco gets confused sometimes and its output
29+# can be a little garbled, but it can help to understand other
30+# people's code more easily.
31+
32+MAKEFLAGS += --warn-undefined-variables
33+MAKEFLAGS += --no-builtin-rules
34+
35+RST2HTML := rst2html5.py --initial-header-level=2 --footnote-references=superscript --smart-quotes=yes -g -d -t
36+PDOC := pdoc --html --overwrite --all-submodules --html-dir
37+
38+# Updated by RJL 13th May with more sensible behaviour
39+# For some reason it won't generate SQL files
40+
41+# We build or rebuild the documentation with pycco - shorthand for the command here in PYCCO_ALL variable
42+# This one builds the index.html file
43+PYCCO_ALL := pycco --generate_index --paths -s --directory
44+
45+# This one does NOT build the index file - otherwise, if you pass a single file
46+# it will be the ONLY one in the index. Do'h!
47+PYCCO_ONE := pycco --paths -s --directory
48+
49+
50+# We want to look at all the .py files in the Code directory (where we start)
51+# in case any have changed. The makefile is in /Code so we just use './'
52+# the shell for 'this directory that we are in' - so the following means
53+# 'all the files ending in "py" in this directory'
54+PYSOURCES=$(wildcard *.py)
55+
56+PYSUBSOURCES=$(wildcard lib/*.py)
57+PYTESTSOURCES=$(wildcard lib/tests/*.py)
58+PYWIDGESTSOURCES=$(wildcard lib/widgets/*.py)
59+PYEXTRASOURCES=$(wildcard lib/extra/*.py)
60+
61+ALL_SOURCES=$(PYSOURCES) $(PYSUBSOURCES) $(PYTESTSOURCES) $(PYWIDGESTSOURCES) $(PYEXTRASOURCES)
62+
63+# This is how we extract an html file-name for each changed python file-name
64+# It basically reads: for each .py file in the source directory (PYSOURCES),
65+# there should be a matching .html file in Code_Documentation.
66+# The % means the stem, for example world.py has a stem of 'world' so we
67+# make world.html from world.py
68+DOCUMENTS_NEEDED_BASE=$(PYSOURCES:%.py=docs/literate/%.html)
69+
70+# For subdirectories, we'll get the subdirectory as a prefix
71+# for example, lib/widgets
72+DOCUMENTS_NEEDED_SUB=$(PYSUBSOURCES:%.py=docs/literate/%.html)
73+
74+# What to do if we just type 'make' without any parameters - we generate the docs
75+.DEFAULT_GOAL := all
76+
77+# No such file as all so mark it as a phony
78+.PHONY: all
79+.PHONY: base
80+.PHONY: svrsub
81+
82+.PHONY: sqlfiles
83+
84+base: $(DOCUMENTS_NEEDED_BASE)
85+svrsub: $(DOCUMENTS_NEEDED_SUB)
86+
87+all: sqlfiles base svrsub
88+
89+# The html file in docs/literate (and its cousins) depends upon the py file of the same name
90+# If the html file is missing or older than the python one, run the pycco command
91+# for the file (in $<)
92+
93+docs/literate/lib/%.html: %.py
94+ $(PYCCO_ONE) ./docs/literate $<
95+
96+docs/literate/%.html: %.py
97+ $(PYCCO_ONE) ./docs/literate $<
98+
99+# Call 'make index' to make the full documentation
100+.PHONY: index
101+index:
102+ make clean
103+ $(PYCCO_ALL) ./docs/literate $(ALL_SOURCES)
104+
105+.PHONY: clean
106+clean:
107+ rm -rf docs/literate
108+
109
110=== modified file 'Makefile'
111--- Makefile 2018-01-31 22:46:16 +0000
112+++ Makefile 2020-07-16 14:28:25 +0000
113@@ -1,3 +1,4 @@
114+
115 all:
116 @echo Targets:
117 @echo test - run tests
118@@ -8,36 +9,42 @@
119 @echo docs - build htmls for texts in docs/ directory
120 @echo epydoc - build API docs with epydoc
121 @echo ui - compile UI files
122+ @echo inno - compile exe (pass RELEASE=X.Y.Z)
123 @echo
124 @echo To build release run:
125 @echo make release RELEASE=X.Y.Z
126
127 .PHONY: test pot mo clean tags docs ui
128
129-check: test
130- BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz selftest -s bp.qbrz
131-
132-test:
133- brz selftest -s bp.qbzr
134-
135-pot:
136- python setup.py build_pot -N -d.
137+# Making pot files is disabled for now - no translators!
138+# pot:
139+# python3 setup.py build_pot -N -d.
140+
141+.check-env-vars:
142+ @test $${RELEASE?RELEASE is undefined. To build release run make release with RELEASE=X.Y.Z}
143
144 mo:
145- python setup.py build_mo -f
146-
147-tarball:
148- bzr export --root=qbzr qbzr-$(RELEASE).tar.gz
149- gpg -ab qbzr-$(RELEASE).tar.gz
150-
151-inno: mo
152- iscc installer/qbzr-setup.iss
153- gpg -ab qbzr-setup-$(RELEASE).exe
154-
155+ python3 setup.py build_mo -f --verbose
156+
157+tarball: .check-env-vars
158+ brz export --root=qbrz qbrz-$(RELEASE).tar.gz
159+ rm -f qbrz-$(RELEASE).tar.gz.asc
160+ gpg2 -ab qbrz-$(RELEASE).tar.gz
161+
162+# RJL needs to come back in
163+# inno: mo
164+# ./iscc installer/qbrz-setup.iss
165+# gpg -ab qbrz-setup-$(RELEASE).exe
166+inno: .check-env-vars
167+ ./iscc installer/qbrz-setup.iss
168+ rm -f qbrz-setup-$(RELEASE).exe.asc
169+ gpg2 -ab qbrz-setup-$(RELEASE).exe
170+
171+# release: tarball inno
172 release: tarball inno
173
174 clean:
175- python setup.py clean -a
176+ python3 setup.py clean -a
177
178 tags:
179 ctags *.py lib/*.py lib/extra/*.py lib/tests/*.py
180@@ -49,4 +56,211 @@
181 $(MAKE) -C docs
182
183 ui:
184- python setup.py build_ui
185+ python3 setup.py build_ui
186+
187+
188+# === Tests beyond this point ===
189+
190+check: test
191+ BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz selftest -s bp.qbrz -x TestTreeFilterProxyModel
192+
193+# Stop on first error, ignore TestTreeFilterProxyModel for now
194+
195+checkone: test
196+ BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz selftest -v --one -s bp.qbrz -x TestTreeFilterProxyModel
197+
198+# Test specific item - e.g. for internationalisation, use:
199+#
200+# BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz selftest --one --strict -s bp.qbrz TestI18n
201+checkspecific: test
202+ BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz selftest --one --strict -s bp.qbrz TestBencode
203+
204+# Rather than running the test_ suite, this lets you run the actual plugin - note
205+# that the tests can often pass but the code fails in actual use.
206+qtest:
207+# You can test on qbrz itself like this (qlog in this example):
208+#
209+ BRZ_PLUGINS_AT=qbrz@$(shell pwd) brz qdiff
210+#
211+# If you have a test directory you wish to use, you can cd to it, run the code, cd back from it.
212+# In this example, we have a test dir of ``~/pythonstuff/bzr_test_dir/sopsteward`` - we have
213+# to ``cd`` to it (note the semi-colon) THEN execute the plugin code we want:
214+#
215+# cd ~/pythonstuff/bzr_test_dir/sopsteward; BRZ_PLUGINS_AT=qbrz@/home/rjl/pythonstuff/fix-python-etc brz qdiff
216+
217+test:
218+ brz selftest -s bp.qbrz
219+
220+
221+# Fully working: (note, qcheckout-ala-explorer is qgetn).
222+# qlog
223+# qadd
224+# qannotate, qblame
225+# qcommit
226+# qbrowse
227+# qcat, qviewer
228+# qversion
229+# qplugins
230+# qinit
231+# qbranch
232+# qbind
233+# qunbind
234+# qignore
235+# qinfo
236+# qupdate
237+# quncommit
238+# qpull
239+# qshelve
240+# qunshelve
241+# qtag
242+# qgetn
243+# qrevert
244+# qpush
245+# qsend
246+# qmerge
247+# qconflicts
248+# qresolve
249+# qswitch
250+# qcmd
251+# qsubprocess
252+# qdiff
253+# qconfig
254+
255+
256+# === qmain ===
257+
258+# qmain fails in bzr
259+
260+
261+# === qverify-signatures ===
262+
263+# qverify-signatures fails in bzr
264+
265+
266+# === qhelp ===
267+
268+# qhelp doesn't work for me even in bzr
269+
270+
271+# === Items in Plug-ins ===
272+
273+# NOT working
274+# qinit-workspace, qnew also unknown - they appear to be from the 'explorer' plugin
275+
276+
277+# === Literate documentation, etc ===
278+
279+# This uses pycco to generate the literal documentation.
280+# To rebuild all of it, with an index.html file, use:
281+#
282+# make literate_index
283+#
284+# To just update (although new files won't be added to index.html), use:
285+#
286+# make literate_docs
287+#
288+# otherwise, you can just make the base, lib, or whatever using (for example):
289+#
290+# make widget_docs
291+#
292+# Output goes into docs/literate/... mirroring the source-code locations (e.g.
293+# lib/widgets/... go into docs/literate/lib/widgets
294+#
295+# pycco isn't brilliant, but it tries its best
296+
297+# We build or rebuild the documentation with pycco - shorthand for the command here in PYCCO_ALL variable
298+# This one builds the index.html file
299+PYCCO_ALL := pycco --generate_index --paths -s --directory
300+
301+# This one does NOT build the index file - otherwise, if you pass a single file
302+# it will be the ONLY one in the index. Do'h!
303+PYCCO_ONE := pycco --paths -s --directory
304+
305+# We want to look at all the .py files in the Code directory (where we start)
306+# in case any have changed. The makefile is in /Code so we just use './'
307+# the shell for 'this directory that we are in' - so the following means
308+# 'all the files ending in "py" in this directory'
309+PYMAINSOURCES=$(wildcard ./*.py)
310+# The lib sources
311+PYLIBSOURCES=$(wildcard ./lib/*.py)
312+# extras and tests
313+PYEXTRASOURCES=$(wildcard ./lib/extra/*.py)
314+PYEXTRASSOURCES=$(wildcard ./extras/*.py)
315+PYTESTSSOURCES=$(wildcard ./lib/tests/*.py)
316+PYWIDGETSOURCES=$(wildcard ./lib/widgets/*.py)
317+
318+# So now add them all together
319+PYSOURCES=$(PYMAINSOURCES) $(PYLIBSOURCES) $(PYEXTRASOURCES) $(PYEXTRASSOURCES) $(PYTESTSSOURCES) $(PYWIDGETSOURCES)
320+
321+# This is how we extract an html file-name for each changed python file-name
322+# It basically reads: for each .py file in the source directory (PYSOURCES),
323+# there should be a matching .html file in Code_Documentation.
324+# The % means the stem, for example world.py has a stem of 'world' so we
325+# make world.html from world.py
326+DOCUMENTS_NEEDED_BASE=$(PYSOURCES:%.py=docs/literate/%.html)
327+
328+# For subdirectories, we'll get the subdirectory as a prefix
329+# for example, svrsub/svrconfig
330+DOCUMENTS_NEEDED_LIB=$(PYLIBSOURCES:%.py=docs/literate/%.html)
331+DOCUMENTS_NEEDED_EXTRA=$(PYEXTRASOURCES:%.py=docs/literate/%.html)
332+DOCUMENTS_NEEDED_EXTRAS=$(PYEXTRASSOURCES:%.py=docs/literate/%.html)
333+DOCUMENTS_NEEDED_TEST=$(PYTESTSSOURCES:%.py=docs/literate/%.html)
334+DOCUMENTS_NEEDED_WIDGETS=$(PYWIDGETSOURCES:%.py=docs/literate/%.html)
335+
336+.PHONY: literate_docs
337+# No such file as all so mark it as a phony
338+.PHONY: base_docs
339+.PHONY: lib_docs
340+.PHONY: extra_docs
341+.PHONY: extras_docs
342+.PHONY: test_docs
343+.PHONY: widget_docs
344+
345+base_docs: $(DOCUMENTS_NEEDED_BASE)
346+lib_docs: $(DOCUMENTS_NEEDED_LIB)
347+extra_docs: $(DOCUMENTS_NEEDED_EXTRA)
348+extras_docs: $(DOCUMENTS_NEEDED_EXTRAS)
349+test_docs: $(DOCUMENTS_NEEDED_TEST)
350+widget_docs: $(DOCUMENTS_NEEDED_WIDGETS)
351+
352+literate_docs: base_docs lib_docs extra_docs extras_docs test_docs widget_docs
353+
354+# The html file in docs/literate (and its cousins) depends upon the py file of the same name
355+# If the html file is missing or older than the python one, run the pycco command
356+# for the file (in $<)
357+
358+
359+
360+docs/literate/%.html: %.py
361+ $(PYCCO_ONE) ./docs/literate $<
362+
363+
364+docs/literate/extras/%.html: %.py
365+ $(PYCCO_ONE) ./docs/literate $<
366+
367+docs/literate/lib/%.html: %.py
368+ $(PYCCO_ONE) ./docs/literate $<
369+
370+
371+docs/literate/lib/data/%.html: %.py
372+ $(PYCCO_ONE) ./docs/literate $<
373+
374+docs/literate/lib/extra/%.html: %.py
375+ $(PYCCO_ONE) ./docs/literate $<
376+
377+docs/literate/lib/test/%.html: %.py
378+ $(PYCCO_ONE) ./docs/literate $<
379+
380+docs/literate/lib/widgets/%.html: %.py
381+ $(PYCCO_ONE) ./docs/literate $<
382+
383+# Call 'make index' to make the full documentation
384+.PHONY: literate_index
385+literate_index:
386+ make literate_clean
387+ $(PYCCO_ALL) ./docs/literate $(PYSOURCES)
388+
389+.PHONY: literate_clean
390+literate_clean:
391+ rm -rf docs/literate/
392+
393
394=== modified file '__init__.py'
395--- __init__.py 2017-09-11 06:53:22 +0000
396+++ __init__.py 2020-07-16 14:28:25 +0000
397@@ -1,3 +1,4 @@
398+#!/usr/bin/python3 -bb
399 # -*- coding: utf-8 -*-
400 #
401 # QBzr - Qt frontend to Bazaar commands
402@@ -70,11 +71,19 @@
403 Miscellaneous:
404
405 * bug-url - print full URL to a specific bug, or open it in your browser.
406+
407+RJL 2020:
408+This is the updated version for QBrz
409 """
410
411-from __future__ import absolute_import
412+# RJL to speed development, retain Qt4 for now: use ``sip.setapi`` to request
413+# version 1 behaviour for ``QVariant`` (otherwise it's not available for python3)
414+import sip
415+sip.setapi('QVariant', 2)
416
417-version_info = (0,23,2,'final',0)
418+# RJL: set to 0,3,1 to match br
419+# version_info = (0,23,2,'final',0)
420+version_info = (0,3,1,'dev',0)
421 __version__ = '.'.join(map(str, version_info))
422
423
424@@ -82,7 +91,6 @@
425
426 from breezy.commands import plugin_cmds
427
428-
429 # merge --qpreview disabled for 0.14 because it makes qbrz incompatible with bzr-pipeline plugin
430 # see bug https://bugs.launchpad.net/bugs/395817
431 #register_lazy_command('breezy.plugins.qbrz.lib.commands', 'cmd_merge', [], decorate=True) # provides merge --qpreview
432
433=== modified file 'docs/Makefile'
434--- docs/Makefile 2010-05-12 12:20:13 +0000
435+++ docs/Makefile 2020-07-16 14:28:25 +0000
436@@ -2,13 +2,14 @@
437
438 all: html
439
440-rst2html := python rst2html.py
441+# rst2html := python rst2html.py
442+RST2HTML := rst2html5.py --initial-header-level=2 --footnote-references=superscript --smart-quotes=yes -g -d -t
443
444 %.html: %.txt
445- $(rst2html) $< $@
446+ $(RST2HTML) $< $@
447
448 %.html: ../%.txt
449- $(rst2html) $< $@
450+ $(RST2HTML) $< $@
451
452 html: index.html gettext_usage.html make_release.html \
453 slot-signal-mini-tutorial/slot-signal-mini-tutorial.html \
454
455=== added directory 'docs/literate'
456=== added directory 'docs/literate/extras'
457=== added directory 'docs/literate/lib'
458=== added directory 'docs/literate/lib/extra'
459=== added directory 'docs/literate/lib/tests'
460=== added directory 'docs/literate/lib/widgets'
461=== added file 'docs/literate/pycco.css'
462--- docs/literate/pycco.css 1970-01-01 00:00:00 +0000
463+++ docs/literate/pycco.css 2020-07-16 14:28:25 +0000
464@@ -0,0 +1,191 @@
465+/*--------------------- Layout and Typography ----------------------------*/
466+body {
467+ font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
468+ font-size: 16px;
469+ line-height: 24px;
470+ color: #252519;
471+ margin: 0; padding: 0;
472+ background: #f5f5ff;
473+}
474+a {
475+ color: #261a3b;
476+}
477+ a:visited {
478+ color: #261a3b;
479+ }
480+p {
481+ margin: 0 0 15px 0;
482+}
483+h1, h2, h3, h4, h5, h6 {
484+ margin: 40px 0 15px 0;
485+}
486+h2, h3, h4, h5, h6 {
487+ margin-top: 0;
488+ }
489+#container {
490+ background: white;
491+ }
492+#container, div.section {
493+ position: relative;
494+}
495+#background {
496+ position: absolute;
497+ top: 0; left: 580px; right: 0; bottom: 0;
498+ background: #f5f5ff;
499+ border-left: 1px solid #e5e5ee;
500+ z-index: 0;
501+}
502+#jump_to, #jump_page {
503+ background: white;
504+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
505+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
506+ font: 10px Arial;
507+ text-transform: uppercase;
508+ cursor: pointer;
509+ text-align: right;
510+}
511+#jump_to, #jump_wrapper {
512+ position: fixed;
513+ right: 0; top: 0;
514+ padding: 5px 10px;
515+}
516+ #jump_wrapper {
517+ padding: 0;
518+ display: none;
519+ }
520+ #jump_to:hover #jump_wrapper {
521+ display: block;
522+ }
523+ #jump_page {
524+ padding: 5px 0 3px;
525+ margin: 0 0 25px 25px;
526+ }
527+ #jump_page .source {
528+ display: block;
529+ padding: 5px 10px;
530+ text-decoration: none;
531+ border-top: 1px solid #eee;
532+ }
533+ #jump_page .source:hover {
534+ background: #f5f5ff;
535+ }
536+ #jump_page .source:first-child {
537+ }
538+div.docs {
539+ float: left;
540+ max-width: 500px;
541+ min-width: 500px;
542+ min-height: 5px;
543+ padding: 10px 25px 1px 50px;
544+ vertical-align: top;
545+ text-align: left;
546+}
547+ .docs pre {
548+ margin: 15px 0 15px;
549+ padding-left: 15px;
550+ overflow-y: scroll;
551+ }
552+ .docs p tt, .docs p code {
553+ background: #f8f8ff;
554+ border: 1px solid #dedede;
555+ font-size: 12px;
556+ padding: 0 0.2em;
557+ }
558+ .octowrap {
559+ position: relative;
560+ }
561+ .octothorpe {
562+ font: 12px Arial;
563+ text-decoration: none;
564+ color: #454545;
565+ position: absolute;
566+ top: 3px; left: -20px;
567+ padding: 1px 2px;
568+ opacity: 0;
569+ -webkit-transition: opacity 0.2s linear;
570+ }
571+ div.docs:hover .octothorpe {
572+ opacity: 1;
573+ }
574+div.code {
575+ margin-left: 580px;
576+ padding: 14px 15px 16px 50px;
577+ vertical-align: top;
578+}
579+ .code pre, .docs p code {
580+ font-size: 12px;
581+ }
582+ pre, tt, code {
583+ line-height: 18px;
584+ font-family: Monaco, Consolas, "Lucida Console", monospace;
585+ margin: 0; padding: 0;
586+ }
587+div.clearall {
588+ clear: both;
589+}
590+
591+
592+/*---------------------- Syntax Highlighting -----------------------------*/
593+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
594+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
595+body .hll { background-color: #ffffcc }
596+body .c { color: #408080; font-style: italic } /* Comment */
597+body .err { border: 1px solid #FF0000 } /* Error */
598+body .k { color: #954121 } /* Keyword */
599+body .o { color: #666666 } /* Operator */
600+body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
601+body .cp { color: #BC7A00 } /* Comment.Preproc */
602+body .c1 { color: #408080; font-style: italic } /* Comment.Single */
603+body .cs { color: #408080; font-style: italic } /* Comment.Special */
604+body .gd { color: #A00000 } /* Generic.Deleted */
605+body .ge { font-style: italic } /* Generic.Emph */
606+body .gr { color: #FF0000 } /* Generic.Error */
607+body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
608+body .gi { color: #00A000 } /* Generic.Inserted */
609+body .go { color: #808080 } /* Generic.Output */
610+body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
611+body .gs { font-weight: bold } /* Generic.Strong */
612+body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
613+body .gt { color: #0040D0 } /* Generic.Traceback */
614+body .kc { color: #954121 } /* Keyword.Constant */
615+body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
616+body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
617+body .kp { color: #954121 } /* Keyword.Pseudo */
618+body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
619+body .kt { color: #B00040 } /* Keyword.Type */
620+body .m { color: #666666 } /* Literal.Number */
621+body .s { color: #219161 } /* Literal.String */
622+body .na { color: #7D9029 } /* Name.Attribute */
623+body .nb { color: #954121 } /* Name.Builtin */
624+body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
625+body .no { color: #880000 } /* Name.Constant */
626+body .nd { color: #AA22FF } /* Name.Decorator */
627+body .ni { color: #999999; font-weight: bold } /* Name.Entity */
628+body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
629+body .nf { color: #0000FF } /* Name.Function */
630+body .nl { color: #A0A000 } /* Name.Label */
631+body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
632+body .nt { color: #954121; font-weight: bold } /* Name.Tag */
633+body .nv { color: #19469D } /* Name.Variable */
634+body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
635+body .w { color: #bbbbbb } /* Text.Whitespace */
636+body .mf { color: #666666 } /* Literal.Number.Float */
637+body .mh { color: #666666 } /* Literal.Number.Hex */
638+body .mi { color: #666666 } /* Literal.Number.Integer */
639+body .mo { color: #666666 } /* Literal.Number.Oct */
640+body .sb { color: #219161 } /* Literal.String.Backtick */
641+body .sc { color: #219161 } /* Literal.String.Char */
642+body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
643+body .s2 { color: #219161 } /* Literal.String.Double */
644+body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
645+body .sh { color: #219161 } /* Literal.String.Heredoc */
646+body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
647+body .sx { color: #954121 } /* Literal.String.Other */
648+body .sr { color: #BB6688 } /* Literal.String.Regex */
649+body .s1 { color: #219161 } /* Literal.String.Single */
650+body .ss { color: #19469D } /* Literal.String.Symbol */
651+body .bp { color: #954121 } /* Name.Builtin.Pseudo */
652+body .vc { color: #19469D } /* Name.Variable.Class */
653+body .vg { color: #19469D } /* Name.Variable.Global */
654+body .vi { color: #19469D } /* Name.Variable.Instance */
655+body .il { color: #666666 } /* Literal.Number.Integer.Long */
656
657=== added file 'docs/pycco.css'
658--- docs/pycco.css 1970-01-01 00:00:00 +0000
659+++ docs/pycco.css 2020-07-16 14:28:25 +0000
660@@ -0,0 +1,191 @@
661+/*--------------------- Layout and Typography ----------------------------*/
662+body {
663+ font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
664+ font-size: 16px;
665+ line-height: 24px;
666+ color: #252519;
667+ margin: 0; padding: 0;
668+ background: #f5f5ff;
669+}
670+a {
671+ color: #261a3b;
672+}
673+ a:visited {
674+ color: #261a3b;
675+ }
676+p {
677+ margin: 0 0 15px 0;
678+}
679+h1, h2, h3, h4, h5, h6 {
680+ margin: 40px 0 15px 0;
681+}
682+h2, h3, h4, h5, h6 {
683+ margin-top: 0;
684+ }
685+#container {
686+ background: white;
687+ }
688+#container, div.section {
689+ position: relative;
690+}
691+#background {
692+ position: absolute;
693+ top: 0; left: 580px; right: 0; bottom: 0;
694+ background: #f5f5ff;
695+ border-left: 1px solid #e5e5ee;
696+ z-index: 0;
697+}
698+#jump_to, #jump_page {
699+ background: white;
700+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
701+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
702+ font: 10px Arial;
703+ text-transform: uppercase;
704+ cursor: pointer;
705+ text-align: right;
706+}
707+#jump_to, #jump_wrapper {
708+ position: fixed;
709+ right: 0; top: 0;
710+ padding: 5px 10px;
711+}
712+ #jump_wrapper {
713+ padding: 0;
714+ display: none;
715+ }
716+ #jump_to:hover #jump_wrapper {
717+ display: block;
718+ }
719+ #jump_page {
720+ padding: 5px 0 3px;
721+ margin: 0 0 25px 25px;
722+ }
723+ #jump_page .source {
724+ display: block;
725+ padding: 5px 10px;
726+ text-decoration: none;
727+ border-top: 1px solid #eee;
728+ }
729+ #jump_page .source:hover {
730+ background: #f5f5ff;
731+ }
732+ #jump_page .source:first-child {
733+ }
734+div.docs {
735+ float: left;
736+ max-width: 500px;
737+ min-width: 500px;
738+ min-height: 5px;
739+ padding: 10px 25px 1px 50px;
740+ vertical-align: top;
741+ text-align: left;
742+}
743+ .docs pre {
744+ margin: 15px 0 15px;
745+ padding-left: 15px;
746+ overflow-y: scroll;
747+ }
748+ .docs p tt, .docs p code {
749+ background: #f8f8ff;
750+ border: 1px solid #dedede;
751+ font-size: 12px;
752+ padding: 0 0.2em;
753+ }
754+ .octowrap {
755+ position: relative;
756+ }
757+ .octothorpe {
758+ font: 12px Arial;
759+ text-decoration: none;
760+ color: #454545;
761+ position: absolute;
762+ top: 3px; left: -20px;
763+ padding: 1px 2px;
764+ opacity: 0;
765+ -webkit-transition: opacity 0.2s linear;
766+ }
767+ div.docs:hover .octothorpe {
768+ opacity: 1;
769+ }
770+div.code {
771+ margin-left: 580px;
772+ padding: 14px 15px 16px 50px;
773+ vertical-align: top;
774+}
775+ .code pre, .docs p code {
776+ font-size: 12px;
777+ }
778+ pre, tt, code {
779+ line-height: 18px;
780+ font-family: Monaco, Consolas, "Lucida Console", monospace;
781+ margin: 0; padding: 0;
782+ }
783+div.clearall {
784+ clear: both;
785+}
786+
787+
788+/*---------------------- Syntax Highlighting -----------------------------*/
789+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
790+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
791+body .hll { background-color: #ffffcc }
792+body .c { color: #408080; font-style: italic } /* Comment */
793+body .err { border: 1px solid #FF0000 } /* Error */
794+body .k { color: #954121 } /* Keyword */
795+body .o { color: #666666 } /* Operator */
796+body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
797+body .cp { color: #BC7A00 } /* Comment.Preproc */
798+body .c1 { color: #408080; font-style: italic } /* Comment.Single */
799+body .cs { color: #408080; font-style: italic } /* Comment.Special */
800+body .gd { color: #A00000 } /* Generic.Deleted */
801+body .ge { font-style: italic } /* Generic.Emph */
802+body .gr { color: #FF0000 } /* Generic.Error */
803+body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
804+body .gi { color: #00A000 } /* Generic.Inserted */
805+body .go { color: #808080 } /* Generic.Output */
806+body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
807+body .gs { font-weight: bold } /* Generic.Strong */
808+body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
809+body .gt { color: #0040D0 } /* Generic.Traceback */
810+body .kc { color: #954121 } /* Keyword.Constant */
811+body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
812+body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
813+body .kp { color: #954121 } /* Keyword.Pseudo */
814+body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
815+body .kt { color: #B00040 } /* Keyword.Type */
816+body .m { color: #666666 } /* Literal.Number */
817+body .s { color: #219161 } /* Literal.String */
818+body .na { color: #7D9029 } /* Name.Attribute */
819+body .nb { color: #954121 } /* Name.Builtin */
820+body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
821+body .no { color: #880000 } /* Name.Constant */
822+body .nd { color: #AA22FF } /* Name.Decorator */
823+body .ni { color: #999999; font-weight: bold } /* Name.Entity */
824+body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
825+body .nf { color: #0000FF } /* Name.Function */
826+body .nl { color: #A0A000 } /* Name.Label */
827+body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
828+body .nt { color: #954121; font-weight: bold } /* Name.Tag */
829+body .nv { color: #19469D } /* Name.Variable */
830+body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
831+body .w { color: #bbbbbb } /* Text.Whitespace */
832+body .mf { color: #666666 } /* Literal.Number.Float */
833+body .mh { color: #666666 } /* Literal.Number.Hex */
834+body .mi { color: #666666 } /* Literal.Number.Integer */
835+body .mo { color: #666666 } /* Literal.Number.Oct */
836+body .sb { color: #219161 } /* Literal.String.Backtick */
837+body .sc { color: #219161 } /* Literal.String.Char */
838+body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
839+body .s2 { color: #219161 } /* Literal.String.Double */
840+body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
841+body .sh { color: #219161 } /* Literal.String.Heredoc */
842+body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
843+body .sx { color: #954121 } /* Literal.String.Other */
844+body .sr { color: #BB6688 } /* Literal.String.Regex */
845+body .s1 { color: #219161 } /* Literal.String.Single */
846+body .ss { color: #19469D } /* Literal.String.Symbol */
847+body .bp { color: #954121 } /* Name.Builtin.Pseudo */
848+body .vc { color: #19469D } /* Name.Variable.Class */
849+body .vg { color: #19469D } /* Name.Variable.Global */
850+body .vi { color: #19469D } /* Name.Variable.Instance */
851+body .il { color: #666666 } /* Literal.Number.Integer.Long */
852
853=== modified file 'extras/__init__.py'
854--- extras/__init__.py 2009-10-31 09:35:48 +0000
855+++ extras/__init__.py 2020-07-16 14:28:25 +0000
856@@ -18,13 +18,13 @@
857 # along with this program; if not, write to the Free Software
858 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
859
860-from build_docs import build_docs
861-from build_mo import build_mo
862-from build_pot import build_pot
863-from build_ui import build_ui
864-from check_py24 import check_py24
865-from check_utf8 import check_utf8
866-from import_po import import_po
867+from .build_docs import build_docs
868+from .build_mo import build_mo
869+from .build_pot import build_pot
870+from .build_ui import build_ui
871+from .check_py24 import check_py24
872+from .check_utf8 import check_utf8
873+from .import_po import import_po
874
875
876 cmdclass = {
877
878=== modified file 'extras/build_mo.py'
879--- extras/build_mo.py 2010-08-03 13:39:49 +0000
880+++ extras/build_mo.py 2020-07-16 14:28:25 +0000
881@@ -17,6 +17,7 @@
882 # You should have received a copy of the GNU General Public License
883 # along with this program; if not, write to the Free Software
884 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
885+# RJLRJL: breezy converted
886
887 """build_mo command for setup.py"""
888
889@@ -28,7 +29,7 @@
890 import os
891 import re
892
893-from en_po import regenerate_en
894+from .en_po import regenerate_en
895
896
897 class build_mo(Command):
898@@ -44,8 +45,7 @@
899 ('output-base=', 'o', 'mo-files base name'),
900 ('source-dir=', None, 'Directory with sources po files'),
901 ('force', 'f', 'Force creation of mo files'),
902- ('lang=', None, 'Comma-separated list of languages '
903- 'to process'),
904+ ('lang=', None, 'Comma-separated list of languages to process'),
905 ]
906
907 boolean_options = ['force']
908@@ -89,14 +89,15 @@
909 log.warn("Skip compiling po files.")
910 return
911
912- if 'en' in self.lang:
913- if find_executable('msginit') is None:
914- log.warn("GNU gettext msginit utility not found!")
915- log.warn("Skip creating English PO file.")
916- else:
917- log.info('Creating English PO file...')
918- pot = (self.prj_name or 'messages') + '.pot'
919- regenerate_en(self.prj_name, self.source_dir, pot, self.spawn)
920+ # RJLRJL: TODO: by-passed for now: we don't want to shred what we have
921+ # if 'en' in self.lang:
922+ # if find_executable('msginit') is None:
923+ # log.warn("GNU gettext msginit utility not found!")
924+ # log.warn("Skip creating English PO file.")
925+ # else:
926+ # log.info('Creating English PO file...')
927+ # pot = (self.prj_name or 'messages') + '.pot'
928+ # regenerate_en(self.prj_name, self.source_dir, pot, self.spawn)
929
930 basename = self.output_base
931 if not basename.endswith('.mo'):
932
933=== modified file 'extras/build_pot.py'
934--- extras/build_pot.py 2011-08-03 06:03:19 +0000
935+++ extras/build_pot.py 2020-07-16 14:28:25 +0000
936@@ -25,7 +25,7 @@
937 from distutils.core import Command
938 from distutils.errors import DistutilsOptionError
939
940-from en_po import regenerate_en
941+from .en_po import regenerate_en
942
943
944 class build_pot(Command):
945@@ -39,8 +39,7 @@
946 # - help string.
947 user_options = [('build-dir=', 'd', 'Directory to put POT file'),
948 ('output=', 'o', 'POT filename'),
949- ('lang=', None, 'Comma-separated list of languages '
950- 'to update po-files'),
951+ ('lang=', None, 'Comma-separated list of languages to update po-files'),
952 ('no-lang', 'N', "Don't update po-files"),
953 ('english', 'E', 'Regenerate English PO file'),
954 ]
955@@ -57,12 +56,11 @@
956 if self.build_dir is None:
957 self.build_dir = 'po'
958 if not self.output:
959- self.output = (self.distribution.get_name() or 'messages')+'.pot'
960+ self.output = (self.distribution.get_name() or 'messages')+ '.pot'
961 if self.lang is not None:
962 self.lang = [i.strip() for i in self.lang.split(',') if i.strip()]
963 if self.lang and self.no_lang:
964- raise DistutilsOptionError("You can't use options "
965- "--lang=XXX and --no-lang in the same time.")
966+ raise DistutilsOptionError("You can't use options --lang=XXX and --no-lang in the same time.")
967
968 def _force_LF(self, src, dst=None):
969 f = open(src, 'rU')
970@@ -93,27 +91,35 @@
971 if not os.path.isdir(self.build_dir):
972 log.info('Make directory: ' + self.build_dir)
973 os.makedirs(self.build_dir)
974- self.spawn(['xgettext',
975- '--keyword=N_',
976- '-p', self.build_dir,
977- '-o', self.output,
978- '__init__.py',
979- ]
980- + glob.glob('lib/*.py')
981- + glob.glob('lib/widgets/*.py')
982- )
983- self._force_LF(fullname)
984+
985+
986+ # RJLRJL: TODO: bypassed for now, to not shred what we have
987+ # self.spawn(['xgettext',
988+ # '--keyword=N_',
989+ # '-p', self.build_dir,
990+ # '-o', self.output,
991+ # '__init__.py',
992+ # ] + glob.glob('lib/*.py') + glob.glob('lib/widgets/*.py')
993+ # )
994+ # self._force_LF(fullname)
995+
996 # regenerate english PO
997+ print('self.english is ', self.english, 'project is ', prj_name)
998 if self.english:
999 log.info('Regenerating English PO file...')
1000+ log.info(' project: {0}, build_dir {1}, output {2}'.format(prj_name, self.build_dir, self.output))
1001+ print('Regenerating English PO file...')
1002+ print(' project: {0}, build_dir {1}, output {2}'.format(prj_name, self.build_dir, self.output))
1003 regenerate_en(prj_name, self.build_dir, self.output, self.spawn)
1004 # search and update all po-files
1005 if self.no_lang:
1006+ print('No language: stopping')
1007 return
1008 for po in glob.glob(os.path.join(self.build_dir,'*.po')):
1009+ print('\tworking on ', po)
1010 if self.lang is not None:
1011 po_lang = os.path.splitext(os.path.basename(po))[0]
1012- if prj_name and po_lang.startswith(prj_name+'-'):
1013+ if prj_name and po_lang.startswith(prj_name + '-'):
1014 po_lang = po_lang[5:]
1015 if po_lang not in self.lang:
1016 continue
1017
1018=== modified file 'extras/build_ui.py'
1019--- extras/build_ui.py 2017-09-11 06:53:22 +0000
1020+++ extras/build_ui.py 2020-07-16 14:28:25 +0000
1021@@ -21,7 +21,7 @@
1022 from distutils import log
1023 from distutils.core import Command
1024 from distutils.dep_util import newer
1025-from StringIO import StringIO
1026+from io import StringIO
1027 import glob
1028 import os
1029 import re
1030@@ -65,6 +65,7 @@
1031 source = source.replace("from PyQt4 import QtCore, QtGui",
1032 "from PyQt4 import QtCore, QtGui\n"
1033 "from breezy.plugins.%s.lib.i18n import gettext\n" % prj_name)
1034- f = open(pyfile, "wb")
1035+ # f = open(pyfile, "wb")
1036+ f = open(pyfile, "w")
1037 f.write(source)
1038 f.close()
1039
1040=== modified file 'extras/check_py24.py'
1041--- extras/check_py24.py 2009-02-27 12:42:38 +0000
1042+++ extras/check_py24.py 2020-07-16 14:28:25 +0000
1043@@ -58,7 +58,7 @@
1044 f.close()
1045 try:
1046 compile(content, fullname, 'exec')
1047- except SyntaxError, e:
1048+ except SyntaxError as e:
1049 log.error(str(e))
1050 if self.verbose:
1051 traceback.print_exc(0)
1052
1053=== modified file 'extras/check_utf8.py'
1054--- extras/check_utf8.py 2009-02-02 03:09:46 +0000
1055+++ extras/check_utf8.py 2020-07-16 14:28:25 +0000
1056@@ -54,7 +54,7 @@
1057 f.close()
1058 try:
1059 content.decode('utf-8')
1060- except UnicodeDecodeError, e:
1061+ except UnicodeDecodeError as e:
1062 log.error(fullname + ': ' + str(e))
1063 # skip some directories
1064 for dname in dirs[:]:
1065
1066=== modified file 'extras/en_po.py'
1067--- extras/en_po.py 2010-08-03 13:39:49 +0000
1068+++ extras/en_po.py 2020-07-16 14:28:25 +0000
1069@@ -28,12 +28,7 @@
1070 else:
1071 en_po = 'en.po'
1072 en_po_path = os.path.join(po_dir, en_po)
1073- spawn(['msginit',
1074- '--no-translator',
1075- '-l', 'en',
1076- '-i', os.path.join(po_dir, pot_file),
1077- '-o', en_po_path,
1078- ])
1079+ spawn(['msginit', '--no-translator', '-l', 'en', '-i', os.path.join(po_dir, pot_file), '-o', en_po_path, ])
1080 # normalize line-endings in en.po file (to LF)
1081 f = open(en_po_path, 'rU')
1082 s = f.read()
1083
1084=== modified file 'extras/import_po.py'
1085--- extras/import_po.py 2010-08-03 13:39:49 +0000
1086+++ extras/import_po.py 2020-07-16 14:28:25 +0000
1087@@ -23,7 +23,7 @@
1088 from distutils.core import Command
1089 from distutils.spawn import find_executable
1090
1091-from en_po import regenerate_en
1092+from .en_po import regenerate_en
1093
1094
1095 class import_po(Command):
1096
1097=== renamed file 'installer/qbzr-setup.iss' => 'installer/qbrz-setup.iss'
1098--- installer/qbzr-setup.iss 2013-10-15 10:11:40 +0000
1099+++ installer/qbrz-setup.iss 2020-07-16 14:28:25 +0000
1100@@ -5,17 +5,17 @@
1101 ; NOTE: The value of AppId uniquely identifies this application.
1102 ; Do not use the same AppId value in installers for other applications.
1103 ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
1104-AppId=QBzr
1105+AppId=QBrz
1106
1107-AppName= QBzr
1108-AppVerName= QBzr 0.23.2
1109-OutputBaseFilename=qbzr-setup-0.23.2
1110+AppName= QBrz
1111+AppVerName= QBrz 0.3.1
1112+OutputBaseFilename=qbrz-setup-0.3.1
1113
1114 SourceDir="..\"
1115 OutputDir="."
1116-OutputManifestFile=qbzr-setup-iss.log
1117+OutputManifestFile=qbrz-setup-iss.log
1118
1119-AppPublisher=QBzr Developers
1120+AppPublisher=QBrz Developers
1121 AppPublisherURL=http://launchpad.net/qbzr
1122 AppSupportURL=http://groups.google.com/group/qbzr
1123 AppUpdatesURL=http://launchpad.net/qbzr/+download
1124@@ -70,26 +70,26 @@
1125 Type: files; Name: {app}\lib\widgets\*.pyo
1126
1127 [Registry]
1128-Root: HKLM; Subkey: "Software\QBzr"; Flags: uninsdeletekey
1129-Root: HKLM; Subkey: "Software\QBzr"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"
1130+Root: HKLM; Subkey: "Software\QBrz"; Flags: uninsdeletekey
1131+Root: HKLM; Subkey: "Software\QBrz"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"
1132
1133 [Code]
1134-{Function detects system-wide installation of bzr: either bzr.exe or python-based}
1135-function GetBzrPath(): String;
1136+{Function detects system-wide installation of brz: either brz.exe or python-based}
1137+function GetBrzPath(): String;
1138 var
1139- BzrPath: String;
1140+ BrzPath: String;
1141 PythonVersions: TArrayOfString;
1142 Ix: Integer;
1143 PythonKey: String;
1144 PythonPath: String;
1145- BzrlibPath: String;
1146+ BrzlibPath: String;
1147 Path: String;
1148 begin
1149- {Check bzr.exe presence}
1150- if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Bazaar', 'InstallPath', BzrPath) then begin
1151- Result := BzrPath;
1152+ {Check brz.exe presence}
1153+ if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Breezy', 'InstallPath', BrzPath) then begin
1154+ Result := BrzPath;
1155 end else begin
1156- BzrlibPath := '';
1157+ BrzlibPath := '';
1158 {Get list of all installed python versions}
1159 if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, 'Software\Python\PythonCore', PythonVersions) then begin
1160 {Iterate over installed pythons and check if there is installed bzrlib}
1161@@ -98,39 +98,39 @@
1162 if RegQueryStringValue(HKEY_LOCAL_MACHINE, PythonKey, '', PythonPath) then begin
1163 Path := AddBackslash(PythonPath) + 'Lib\site-packages\bzrlib'
1164 if DirExists(Path) then begin
1165- BzrlibPath := Path;
1166+ BrzlibPath := Path;
1167 break;
1168 end;
1169 end;
1170 end;
1171 end;
1172- Result := BzrlibPath;
1173+ Result := BrzlibPath;
1174 end;
1175 end;
1176
1177-{Function determines best possible PATH to install QBzr.
1178- At first it tries to find system-wide installation (either bzr.exe or python-based)
1179- then checks BZR_PLUGIN_PATH,
1180- if all above fails then it suggests install to %APPDATA%\bazaar\2.0
1181+{Function determines best possible PATH to install QBrz.
1182+ At first it tries to find system-wide installation (either brz.exe or python-based)
1183+ then checks BRZ_PLUGIN_PATH,
1184+ if all above fails then it suggests install to %APPDATA%\Breezy\2.0
1185 }
1186 function GetDirName(Param: String): String;
1187 var
1188 Path: String;
1189- BzrPath: String;
1190- EnvBzrPluginPath: String;
1191+ BrzPath: String;
1192+ EnvBrzPluginPath: String;
1193 Ix: Integer;
1194 begin
1195- Path := ExpandConstant('{userappdata}\bazaar\2.0\plugins\qbzr');
1196- BzrPath := GetBzrPath();
1197- if BzrPath <> '' then begin
1198- Path := AddBackslash(BzrPath) + 'plugins\qbzr';
1199+ Path := ExpandConstant('{userappdata}\Breezy\2.0\plugins\qbzr');
1200+ BrzPath := GetBrzPath();
1201+ if BrzPath <> '' then begin
1202+ Path := AddBackslash(BrzPath) + 'plugins\qbzr';
1203 end else begin
1204- EnvBzrPluginPath := GetEnv('BZR_PLUGIN_PATH')
1205- Ix := Pos(';', EnvBzrPluginPath)
1206+ EnvBrzPluginPath := GetEnv('BRZ_PLUGIN_PATH')
1207+ Ix := Pos(';', EnvBrzPluginPath)
1208 if Ix > 0 then
1209- EnvBzrPluginPath := Copy(EnvBzrPluginPath, 1, Ix-1)
1210- if EnvBzrPluginPath <> '' then
1211- Path := AddBackslash(EnvBzrPluginPath) + 'qbzr';
1212+ EnvBrzPluginPath := Copy(EnvBrzPluginPath, 1, Ix-1)
1213+ if EnvBrzPluginPath <> '' then
1214+ Path := AddBackslash(EnvBrzPluginPath) + 'qbzr';
1215 end;
1216 Result := Path;
1217 end;
1218
1219=== added file 'iscc'
1220--- iscc 1970-01-01 00:00:00 +0000
1221+++ iscc 2020-07-16 14:28:25 +0000
1222@@ -0,0 +1,5 @@
1223+#!/bin/sh
1224+unset DISPLAY
1225+scriptname=$1
1226+[ -f "$scriptname" ] && scriptname=$(winepath -w "$scriptname")
1227+wine "C:\Program Files (x86)\Inno Setup 5\ISCC.exe" "$scriptname" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
1228
1229=== modified file 'lib/__init__.py'
1230--- lib/__init__.py 2012-02-19 23:50:27 +0000
1231+++ lib/__init__.py 2020-07-16 14:28:25 +0000
1232@@ -1,4 +1,6 @@
1233-# -*- coding: utf-8 -*-
1234+#!/usr/bin/python3 -bb
1235+# # -*- coding: utf-8 -*-
1236+
1237 #
1238 # QBzr - Qt frontend to Bazaar commands
1239 # Copyright (C) 2006-2008 Lukáš Lalinský <lalinsky@gmail.com>
1240@@ -34,9 +36,9 @@
1241 return True
1242 return False
1243
1244- import __builtin__
1245- __builtin__.all = _all_2_4_compat
1246- __builtin__.any = _any_2_4_compat
1247+ import builtins
1248+ builtins.all = _all_2_4_compat
1249+ builtins.any = _any_2_4_compat
1250
1251 # Special constant
1252 MS_WINDOWS = (sys.platform == 'win32')
1253
1254=== modified file 'lib/add.py'
1255--- lib/add.py 2017-09-11 06:53:22 +0000
1256+++ lib/add.py 2020-07-16 14:28:25 +0000
1257@@ -40,79 +40,71 @@
1258 def __init__(self, tree, selected_list, dialog=True, ui_mode=True, parent=None, local=None, message=None):
1259 self.tree = tree
1260 self.initial_selected_list = selected_list
1261-
1262+ # print('*^*^*^^ tree is', self.tree, 'initial_selected', selected_list)
1263+
1264 super(AddWindow, self).__init__(
1265- gettext("Add"),
1266- name = "add",
1267- default_size = (400, 400),
1268- ui_mode = ui_mode,
1269- dialog = dialog,
1270- parent = parent,
1271- hide_progress=True,
1272- )
1273-
1274+ gettext("Add"),
1275+ name = "add",
1276+ default_size = (400, 400),
1277+ ui_mode = ui_mode,
1278+ dialog = dialog,
1279+ parent = parent,
1280+ hide_progress=True,
1281+ )
1282+
1283 self.throbber = ThrobberWidget(self)
1284
1285 # Display the list of unversioned files
1286 groupbox = QtGui.QGroupBox(gettext("Unversioned Files"), self)
1287 vbox = QtGui.QVBoxLayout(groupbox)
1288
1289- self.filelist = TreeWidget(groupbox)
1290- self.filelist.throbber = self.throbber
1291- self.filelist.tree_model.is_item_in_select_all = lambda item: (
1292+ self.filelist_widget = TreeWidget(groupbox)
1293+ self.filelist_widget.throbber = self.throbber
1294+
1295+ self.filelist_widget.tree_model.is_item_in_select_all = lambda item: (
1296 # Is in select all. - Not versioned, and not Ignored
1297- item.change is not None and
1298- item.change.is_ignored() is None and
1299- not item.change.is_versioned(),
1300-
1301+ item.change is not None and item.change.is_ignored() is None and not item.change.is_versioned(),
1302 # look at children. - Not ignored
1303- item.change is not None and item.change.is_ignored() is None or
1304- item.change is None
1305+ item.change is not None and item.change.is_ignored() is None or item.change is None
1306 )
1307-
1308+
1309 def filter_context_menu():
1310- items = self.filelist.get_selection_items()
1311+ items = self.filelist_widget.get_selection_items()
1312 selection_len = len(items)
1313 single_file = (selection_len == 1 and items[0].item.kind == "file")
1314- single_item_in_tree = (selection_len == 1 and
1315- (items[0].change is None or items[0].change[6][1] is not None))
1316-
1317- self.filelist.action_open_file.setEnabled(True)
1318- self.filelist.action_open_file.setVisible(True)
1319- self.filelist.action_show_file.setEnabled(single_file)
1320- self.filelist.action_show_file.setVisible(True)
1321- self.filelist.action_show_annotate.setVisible(False)
1322- self.filelist.action_show_log.setVisible(False)
1323- self.filelist.action_show_diff.setVisible(False)
1324- self.filelist.action_add.setVisible(False)
1325- self.filelist.action_revert.setVisible(False)
1326- self.filelist.action_merge.setVisible(False)
1327- self.filelist.action_resolve.setVisible(False)
1328- self.filelist.action_rename.setVisible(True)
1329- self.filelist.action_rename.setEnabled(single_item_in_tree)
1330- self.filelist.action_remove.setVisible(False)
1331- self.filelist.action_mark_move.setVisible(False)
1332-
1333- self.filelist.filter_context_menu = filter_context_menu
1334-
1335- vbox.addWidget(self.filelist)
1336-
1337- selectall_checkbox = SelectAllCheckBox(self.filelist, groupbox)
1338+ single_item_in_tree = (selection_len == 1 and (items[0].change is None or items[0].change[6][1] is not None))
1339+
1340+ self.filelist_widget.action_open_file.setEnabled(True)
1341+ self.filelist_widget.action_open_file.setVisible(True)
1342+ self.filelist_widget.action_show_file.setEnabled(single_file)
1343+ self.filelist_widget.action_show_file.setVisible(True)
1344+ self.filelist_widget.action_show_annotate.setVisible(False)
1345+ self.filelist_widget.action_show_log.setVisible(False)
1346+ self.filelist_widget.action_show_diff.setVisible(False)
1347+ self.filelist_widget.action_add.setVisible(False)
1348+ self.filelist_widget.action_revert.setVisible(False)
1349+ self.filelist_widget.action_merge.setVisible(False)
1350+ self.filelist_widget.action_resolve.setVisible(False)
1351+ self.filelist_widget.action_rename.setVisible(True)
1352+ self.filelist_widget.action_rename.setEnabled(single_item_in_tree)
1353+ self.filelist_widget.action_remove.setVisible(False)
1354+ self.filelist_widget.action_mark_move.setVisible(False)
1355+
1356+ self.filelist_widget.filter_context_menu = filter_context_menu
1357+
1358+ vbox.addWidget(self.filelist_widget)
1359+
1360+ selectall_checkbox = SelectAllCheckBox(self.filelist_widget, groupbox)
1361 vbox.addWidget(selectall_checkbox)
1362 selectall_checkbox.setCheckState(QtCore.Qt.Checked)
1363 selectall_checkbox.setEnabled(True)
1364
1365- self.show_ignored_checkbox = QtGui.QCheckBox(
1366- gettext("Show ignored files"),
1367- groupbox)
1368+ self.show_ignored_checkbox = QtGui.QCheckBox(gettext("Show ignored files"), groupbox)
1369 vbox.addWidget(self.show_ignored_checkbox)
1370 self.connect(self.show_ignored_checkbox, QtCore.SIGNAL("toggled(bool)"), self.show_ignored)
1371-
1372+
1373 # groupbox gets disabled as we are executing.
1374- QtCore.QObject.connect(self,
1375- QtCore.SIGNAL("disableUi(bool)"),
1376- groupbox,
1377- QtCore.SLOT("setDisabled(bool)"))
1378+ QtCore.QObject.connect(self, QtCore.SIGNAL("disableUi(bool)"), groupbox, QtCore.SLOT("setDisabled(bool)"))
1379
1380 self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
1381 self.splitter.addWidget(groupbox)
1382@@ -134,17 +126,21 @@
1383 @ui_current_widget
1384 @reports_exception()
1385 def initial_load(self):
1386- self.filelist.tree_model.checkable = True
1387- fmodel = self.filelist.tree_filter_model
1388+ # print('*** initial_load called')
1389+ self.filelist_widget.tree_model.checkable = True
1390+ fmodel = self.filelist_widget.tree_filter_model
1391 fmodel.setFilter(fmodel.CHANGED, False)
1392 fmodel.setFilter(fmodel.UNCHANGED, False)
1393- self.filelist.set_tree(self.tree, changes_mode = True,
1394+ self.filelist_widget.set_tree(self.tree, changes_mode = True,
1395 initial_checked_paths=self.initial_selected_list,
1396 change_load_filter=lambda c:not c.is_versioned())
1397 self.throbber.hide()
1398+ # print('leaving initial_load ***')
1399
1400 def _get_files_to_add(self):
1401- return [ref.path for ref in self.filelist.tree_model.iter_checked()]
1402+ # print('==== getting files ====')
1403+ # OK pressed
1404+ return [ref.path for ref in self.filelist_widget.tree_model.iter_checked()]
1405
1406 def validate(self):
1407 if not self._get_files_to_add():
1408@@ -154,15 +150,16 @@
1409
1410 def do_start(self):
1411 """Add the files."""
1412+ # print('\tdo_start entry')
1413 files = self._get_files_to_add()
1414- self.process_widget.do_start(self.tree.basedir, "add", "--no-recurse",
1415- *files)
1416+ self.process_widget.do_start(self.tree.basedir, "add", "--no-recurse", *files)
1417+ # print('\tdo_start EXIT')
1418
1419 def show_ignored(self, state):
1420 """Show/hide ignored files."""
1421- fmodel = self.filelist.tree_filter_model
1422+ fmodel = self.filelist_widget.tree_filter_model
1423 fmodel.setFilter(fmodel.IGNORED, state)
1424- #self.filelist.update_selectall_state(None, None)
1425+ # self.filelist_widget.update_selectall_state(None, None)
1426
1427 def _saveSize(self, config):
1428 SubProcessDialog._saveSize(self, config)
1429
1430=== modified file 'lib/annotate.py'
1431--- lib/annotate.py 2017-11-13 23:31:28 +0000
1432+++ lib/annotate.py 2020-07-16 14:28:25 +0000
1433@@ -64,23 +64,23 @@
1434 from breezy.plugins.qbrz.lib.revtreeview import paint_revno, get_text_color
1435 from breezy.plugins.qbrz.lib import logmodel
1436 from breezy.plugins.qbrz.lib.loggraphviz import BranchInfo
1437-from breezy.patiencediff import PatienceSequenceMatcher as SequenceMatcher
1438+from patiencediff import PatienceSequenceMatcher as SequenceMatcher
1439 ''')
1440
1441 class AnnotateBar(AnnotateBarBase):
1442-
1443+
1444 def __init__(self, edit, parent, get_revno):
1445 super(AnnotateBar, self).__init__(edit, parent)
1446-
1447+
1448 self.get_revno = get_revno
1449 self.annotate = None
1450 self.rev_colors = {}
1451 self._highlight_revids = set()
1452 self.highlight_lines = []
1453-
1454+
1455 self.splitter = None
1456 self.adjustWidth(1, 999)
1457-
1458+
1459 self.connect(edit,
1460 QtCore.SIGNAL("cursorPositionChanged()"),
1461 self.edit_cursorPositionChanged)
1462@@ -118,22 +118,22 @@
1463 fm = self.fontMetrics()
1464 text_margin = self.style().pixelMetric(
1465 QtGui.QStyle.PM_FocusFrameHMargin, None, self) + 1
1466-
1467- self.line_number_width = fm.width(unicode(lines))
1468+
1469+ self.line_number_width = fm.width(str(lines))
1470 self.line_number_width += (text_margin * 2)
1471-
1472- self.revno_width = fm.width(unicode(max_revno)+".8.88")
1473- self.max_mainline_digits = len(unicode(max_revno))
1474+
1475+ self.revno_width = fm.width(str(max_revno)+".8.88")
1476+ self.max_mainline_digits = len(str(max_revno))
1477 self.revno_width += (text_margin * 2)
1478-
1479+
1480 if self.splitter:
1481 if 0: self.splitter = QtGui.QSplitter
1482 width = (self.line_number_width + self.revno_width +
1483 fm.width("Joe I have a Long Name"))
1484 self.splitter.setSizes([width, 1000])
1485-
1486+
1487 self.setMinimumWidth(self.line_number_width + self.revno_width)
1488-
1489+
1490 def paint_line(self, painter, rect, line_number, is_current):
1491 fm = self.fontMetrics()
1492 painter.save()
1493@@ -146,26 +146,26 @@
1494 painter.fillRect(rect, QtGui.QBrush(option.palette.highlight()))
1495 style.drawPrimitive(QtGui.QStyle.PE_PanelItemViewItem,
1496 option, painter, self)
1497-
1498+
1499 painter.setPen(get_text_color(option, style))
1500 elif self.annotate and line_number-1 < len(self.annotate):
1501 revid, is_top = self.annotate[line_number - 1]
1502 if revid in self.rev_colors:
1503 painter.fillRect(rect, self.rev_colors[revid])
1504-
1505+
1506 text_margin = self.style().pixelMetric(
1507 QtGui.QStyle.PM_FocusFrameHMargin, None, self) + 1
1508-
1509+
1510 if 0: rect = QtCore.QRect
1511 line_number_rect = QtCore.QRect(
1512 rect.left() + text_margin,
1513 rect.top(),
1514 self.line_number_width - (2 * text_margin),
1515 rect.height())
1516-
1517+
1518 painter.drawText(line_number_rect, QtCore.Qt.AlignRight,
1519- unicode(line_number))
1520-
1521+ str(line_number))
1522+
1523 if self.annotate and line_number-1 < len(self.annotate):
1524 revid, is_top = self.annotate[line_number - 1]
1525 if is_top:
1526@@ -173,16 +173,16 @@
1527 font = painter.font()
1528 font.setBold(True)
1529 painter.setFont(font)
1530-
1531+
1532 revno_rect = QtCore.QRect(
1533 rect.left() + self.line_number_width + text_margin,
1534 rect.top(),
1535 self.revno_width - (2 * text_margin),
1536 rect.height())
1537 paint_revno(painter, revno_rect,
1538- QtCore.QString(self.get_revno(revid)),
1539+ str(self.get_revno(revid)),
1540 self.max_mainline_digits)
1541-
1542+
1543 if revid in cached_revisions:
1544 rev = cached_revisions[revid]
1545 author_rect = QtCore.QRect(
1546@@ -191,10 +191,10 @@
1547 rect.top(),
1548 rect.right() - revno_rect.right() - (2 * text_margin),
1549 rect.height())
1550- author = QtCore.QString(get_apparent_author_name(rev))
1551+ author = get_apparent_author_name(rev)
1552 if fm.width(author) > author_rect.width():
1553 author= fm.elidedText(author, QtCore.Qt.ElideRight,
1554- author_rect.width())
1555+ author_rect.width())
1556 painter.drawText(author_rect, 0, author)
1557 painter.restore()
1558
1559@@ -208,7 +208,7 @@
1560 block = self.firstVisibleBlock()
1561 painter = QtGui.QPainter(self.viewport())
1562 painter.setClipRect(event.rect())
1563-
1564+
1565 line_count = block.blockNumber()
1566 # Iterate over all visible text blocks in the document.
1567 while block.isValid():
1568@@ -217,21 +217,21 @@
1569 # area.
1570 rect = self.blockBoundingGeometry(block)
1571 rect = rect.translated(self.contentOffset())
1572-
1573+
1574 if not block.isVisible() or rect.top() >= event.rect().bottom():
1575 break
1576-
1577+
1578 if line_count - 1 >= len(self.annotate):
1579 break
1580-
1581+
1582 revid, is_top = self.annotate[line_count - 1]
1583 if revid in self.rev_colors:
1584 painter.fillRect(rect, self.rev_colors[revid])
1585-
1586+
1587 block = block.next()
1588 del painter
1589 QtGui.QPlainTextEdit.paintEvent(self, event)
1590-
1591+
1592 def get_positions(self):
1593 """Returns the charator positons for the selection start,
1594 selection end, center of the viewport, an the number of lines from
1595@@ -240,11 +240,11 @@
1596 old_center = self.cursorForPosition(QtCore.QPoint(0, self.height() / 2))
1597 lines_to_center = (old_center.block().blockNumber() -
1598 self.verticalScrollBar().value())
1599-
1600+
1601 return (old_cursor.selectionStart(),
1602 old_cursor.selectionEnd(),
1603 old_center.position()) , lines_to_center
1604-
1605+
1606 def set_positions(self, new_positions, lines_to_center):
1607 new_start, new_end, new_center = new_positions
1608 if new_center:
1609@@ -252,7 +252,7 @@
1610 new_center_cursor.setPosition(new_center)
1611 new_scroll = new_center_cursor.block().blockNumber() - lines_to_center
1612 self.verticalScrollBar().setValue(new_scroll)
1613-
1614+
1615 new_selection_cursor = QtGui.QTextCursor(self.document())
1616 new_selection_cursor.movePosition(QtGui.QTextCursor.Right,
1617 QtGui.QTextCursor.MoveAnchor,
1618@@ -260,7 +260,7 @@
1619 new_selection_cursor.movePosition(QtGui.QTextCursor.Right,
1620 QtGui.QTextCursor.KeepAnchor,
1621 new_end - new_start)
1622- self.setTextCursor(new_selection_cursor)
1623+ self.setTextCursor(new_selection_cursor)
1624
1625
1626 class AnnotateWindow(QBzrWindow):
1627@@ -280,13 +280,13 @@
1628 self.branch = branch
1629 self.annotate_tree = annotate_tree
1630 self.working_tree = working_tree
1631- if (self.working_tree is None and
1632+ if (self.working_tree is None and
1633 isinstance(annotate_tree, WorkingTree)):
1634 self.working_tree = annotate_tree
1635-
1636+
1637 self.no_graph = no_graph
1638 self.old_lines = None
1639-
1640+
1641 self.fileId = fileId
1642 self.path = path
1643 self.encoding = encoding
1644@@ -294,7 +294,7 @@
1645 self.loader_args = loader_args
1646
1647 self.throbber = ToolBarThrobberWidget(self)
1648-
1649+
1650 self.text_edit_frame = AnnotateEditerFrameBase(self)
1651 self.text_edit = AnnotatedTextEdit(self)
1652 self.text_edit.setFrameStyle(QtGui.QFrame.NoFrame)
1653@@ -302,7 +302,7 @@
1654 QtCore.Qt.TextSelectableByMouse|
1655 QtCore.Qt.TextSelectableByKeyboard)
1656 self.text_edit.setLineWrapMode(QtGui.QPlainTextEdit.NoWrap)
1657-
1658+
1659 self.text_edit.document().setDefaultFont(get_monospace_font())
1660
1661 self.guidebar_panel = GuideBarPanel(self.text_edit, parent=self)
1662@@ -313,26 +313,26 @@
1663 annotate_spliter.addWidget(self.guidebar_panel)
1664 self.annotate_bar.splitter = annotate_spliter
1665 self.text_edit_frame.hbox.addWidget(annotate_spliter)
1666-
1667+
1668 self.connect(self.text_edit,
1669 QtCore.SIGNAL("cursorPositionChanged()"),
1670- self.edit_cursorPositionChanged)
1671+ self.edit_cursorPositionChanged)
1672 self.connect(self.annotate_bar,
1673 QtCore.SIGNAL("cursorPositionChanged()"),
1674 self.edit_cursorPositionChanged)
1675 self.connect(self.text_edit,
1676 QtCore.SIGNAL("documentChangeFinished()"),
1677 self.edit_documentChangeFinished)
1678-
1679+
1680 self.log_list = AnnotateLogList(self.processEvents, self.throbber, self)
1681 self.log_list.header().hideSection(logmodel.COL_DATE)
1682 self.log_list.parent_annotate_window = self
1683 self.log_branch_loaded = False
1684-
1685+
1686 self.connect(self.log_list.selectionModel(),
1687 QtCore.SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
1688 self.log_list_selectionChanged)
1689-
1690+
1691 self.message = LogListRevisionMessageBrowser(self.log_list, self)
1692
1693 self.encoding_selector = EncodingMenuSelector(self.encoding,
1694@@ -361,15 +361,15 @@
1695 self.show_find = QtGui.QAction(get_icon("edit-find"), gettext("Find"), self)
1696 self.show_find.setShortcuts(QtGui.QKeySequence.Find)
1697 self.show_find.setCheckable(True)
1698-
1699+
1700 self.show_goto_line = QtGui.QAction(get_icon("go-jump"), gettext("Goto Line"), self)
1701 self.show_goto_line.setShortcuts((QtCore.Qt.CTRL + QtCore.Qt.Key_L,))
1702 self.show_goto_line.setCheckable(True)
1703-
1704+
1705 show_view_menu = QtGui.QAction(get_icon("document-properties"), gettext("&View Options"), self)
1706 view_menu = QtGui.QMenu(gettext('View Options'), self)
1707 show_view_menu.setMenu(view_menu)
1708-
1709+
1710 word_wrap = QtGui.QAction(gettext("Word Wrap"), self)
1711 word_wrap.setCheckable(True)
1712 self.connect(word_wrap,
1713@@ -382,28 +382,28 @@
1714 self.tab_width_selector = TabWidthMenuSelector(get_set_tab_width_chars(branch=branch),
1715 gettext("Tab Width"),
1716 setTabStopWidth)
1717-
1718+
1719 view_menu.addMenu(self.tab_width_selector)
1720 view_menu.addMenu(self.encoding_selector)
1721 view_menu.addAction(word_wrap)
1722-
1723+
1724 toolbar = self.addToolBar(gettext("Annotate"))
1725 toolbar.setMovable (False)
1726 toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
1727-
1728+
1729 #self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
1730 toolbar.addAction(self.show_find)
1731 toolbar.addAction(self.show_goto_line)
1732 toolbar.addAction(show_view_menu)
1733 toolbar.widgetForAction(show_view_menu).setPopupMode(QtGui.QToolButton.InstantPopup)
1734-
1735+
1736 spacer = QtGui.QWidget()
1737 spacer.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
1738- toolbar.addWidget(spacer)
1739+ toolbar.addWidget(spacer)
1740 toolbar.addWidget(self.throbber)
1741-
1742+
1743 self.addToolBarBreak()
1744-
1745+
1746 self.find_toolbar = FindToolbar(self, self.text_edit, self.show_find)
1747 self.find_toolbar.hide()
1748 self.addToolBar(self.find_toolbar)
1749@@ -411,11 +411,11 @@
1750 QtCore.SIGNAL("toggled (bool)"),
1751 self.show_find_toggle)
1752 setup_guidebar_for_find(self.guidebar_panel, self.find_toolbar, index=1)
1753-
1754+
1755 self.goto_line_toolbar = GotoLineToolbar(self, self.show_goto_line)
1756 self.goto_line_toolbar.hide()
1757 self.addToolBar(self.goto_line_toolbar)
1758-
1759+
1760 self.connect(self.show_goto_line,
1761 QtCore.SIGNAL("toggled (bool)"),
1762 self.show_goto_line_toggle )
1763@@ -479,7 +479,7 @@
1764 self.set_title_and_icon([gettext("Annotate"), self.path,
1765 gettext("Revision %s") % revno])
1766 return
1767-
1768+
1769 self.set_title_and_icon([gettext("Annotate"), self.path])
1770
1771 def get_revno(self, revid):
1772@@ -488,7 +488,7 @@
1773 revid in gv.revid_rev):
1774 return gv.revid_rev[revid].revno_str
1775 return ""
1776-
1777+
1778 def annotate(self, annotate_tree, fileId, path):
1779 self.now = time.time()
1780 self.rev_indexes = {}
1781@@ -498,40 +498,40 @@
1782 ordered_revids = []
1783
1784 self.processEvents()
1785- for revid, text in annotate_tree.annotate_iter(path, file_id=fileId):
1786+ for revid, text in annotate_tree.annotate_iter(path):
1787 if revid == CURRENT_REVISION:
1788- revid = CURRENT_REVISION + annotate_tree.basedir
1789-
1790+ revid = CURRENT_REVISION + annotate_tree.basedir.encode("utf-8")
1791+
1792 text = text.decode(self.encoding, 'replace')
1793-
1794+
1795 lines.append(text)
1796-
1797+
1798 text = text.rstrip()
1799 if revid not in self.rev_indexes:
1800 self.rev_indexes[revid]=[]
1801 ordered_revids.append(revid)
1802 self.rev_indexes[revid].append(len(annotate))
1803-
1804+
1805 is_top = last_revid != revid
1806 last_revid = revid
1807-
1808+
1809 annotate.append((revid, is_top))
1810 if len(annotate) % 100 == 0:
1811 self.processEvents()
1812 annotate.append((None, False)) # because the view has one more line
1813-
1814+
1815 new_positions = None
1816 if self.old_lines:
1817 # Try keep the scroll, and selection stable.
1818 old_positions, lines_to_center = self.text_edit.get_positions()
1819 new_positions = self.translate_positions(
1820 self.old_lines, lines, old_positions)
1821-
1822+
1823 self.text_edit.annotate = None
1824 self.text_edit.setPlainText("".join(lines))
1825 if new_positions:
1826 self.text_edit.set_positions(new_positions, lines_to_center)
1827-
1828+
1829 self.old_lines = lines
1830 self.annotate_bar.adjustWidth(len(lines), 999)
1831 self.annotate_bar.annotate = annotate
1832@@ -539,9 +539,9 @@
1833 self.annotate_bar.show_current_line = False
1834
1835 self.text_edit.emit(QtCore.SIGNAL("documentChangeFinished()"))
1836-
1837+
1838 self.processEvents()
1839-
1840+
1841 just_loaded_log = False
1842 if not self.log_branch_loaded:
1843 self.log_branch_loaded = True
1844@@ -549,22 +549,22 @@
1845 self.log_list.load(
1846 (bi,), bi, [self.fileId], self.no_graph,
1847 logmodel.WithWorkingTreeGraphVizLoader)
1848-
1849+
1850 gv = self.log_list.log_model.graph_viz
1851 self.annotate_bar.adjustWidth(len(lines),
1852 gv.revisions[0].revno_sequence[0])
1853-
1854+
1855 just_loaded_log = True
1856-
1857+
1858 # Show the revisions the we know about from the annotate.
1859 filter = self.log_list.log_model.file_id_filter
1860 changed_revs = []
1861- for revid in self.rev_indexes.keys():
1862+ for revid in list(self.rev_indexes.keys()):
1863 rev = gv.revid_rev[revid]
1864 filter.filter_file_id[rev.index] = True
1865 changed_revs.append(rev)
1866 filter.filter_changed_callback(changed_revs, last_call=True)
1867-
1868+
1869 self.processEvents()
1870 highlight_document(self.text_edit, path)
1871 self.processEvents()
1872@@ -572,15 +572,15 @@
1873 revisions_loaded = self.revisions_loaded,
1874 pass_prev_loaded_rev = True)
1875 self.processEvents()
1876-
1877+
1878 if just_loaded_log:
1879 # Check for any other revisions we don't know about
1880-
1881+
1882 filter = self.log_list.log_model.file_id_filter
1883 revids = [rev.revid for rev in gv.revisions
1884 if rev.revid not in self.rev_indexes]
1885 filter.load(revids)
1886-
1887+
1888 def translate_positions(self, old_lines, new_lines, old_positions):
1889 sm = SequenceMatcher(None, old_lines, new_lines)
1890 opcodes = sm.get_opcodes()
1891@@ -614,13 +614,13 @@
1892 return new_positions
1893
1894 def revisions_loaded(self, revisions, last_call):
1895- for rev in revisions.itervalues():
1896+ for rev in revisions.values():
1897 authors = rev.get_apparent_authors()
1898- emails = map(self._maybe_extract_email, authors)
1899+ emails = list(map(self._maybe_extract_email, authors))
1900 author_id = ';'.join(emails)
1901
1902 if rev.timestamp is None:
1903- days = sys.maxint
1904+ days = sys.maxsize
1905 elif self.now < rev.timestamp:
1906 days = 0
1907 else:
1908@@ -628,7 +628,7 @@
1909
1910 alpha = 0.5/((days/50) + 1)
1911 h_sh = self._get_hash(author_id)
1912- hue = 1-float(h_sh) / sys.maxint
1913+ hue = 1-float(h_sh) / sys.maxsize
1914 color = QtGui.QColor.fromHsvF(hue, 1, 1, alpha)
1915 brush = QtGui.QBrush(color)
1916
1917@@ -679,7 +679,7 @@
1918 try:
1919 self.branch.lock_read()
1920 try:
1921- revid = str(self.log_list.currentIndex().data(logmodel.RevIdRole).toString())
1922+ revid = self.log_list.currentIndex().data(logmodel.RevIdRole)
1923 if revid.startswith(CURRENT_REVISION):
1924 rev = cached_revisions[revid]
1925 self.annotate_tree = self.working_tree
1926@@ -707,13 +707,13 @@
1927 self.branch.unlock()
1928 finally:
1929 self.throbber.hide()
1930-
1931+
1932 def log_list_selectionChanged(self, selected, deselected):
1933 revids = self.log_list.get_selection_and_merged_revids()
1934 self.annotate_bar.highlight_revids = revids
1935 self.guidebar_panel.update_data(annotate=self.annotate_bar.highlight_lines)
1936 self.annotate_bar.update()
1937-
1938+
1939 def show_find_toggle(self, state):
1940 if state:
1941 self.show_goto_line.setChecked(False)
1942@@ -725,7 +725,7 @@
1943 self.show_find.setChecked(False)
1944 else:
1945 self.goto_line_toolbar.line_edit.setText('')
1946-
1947+
1948 def word_wrap_toggle(self, state):
1949 if state:
1950 self.text_edit.setLineWrapMode(QtGui.QPlainTextEdit.WidgetWidth)
1951@@ -741,14 +741,17 @@
1952
1953
1954 # QIntValidator did not work on vila's setup, so this is a workaround.
1955+# RJLRJL QIntValidator seems to be working in 2020, whereas this isn't
1956+# so ignored for now.
1957 class IntValidator(QtGui.QValidator):
1958 def validate (self, input, pos):
1959 if input == '':
1960 return (QtGui.QValidator.Intermediate, pos)
1961- try:
1962+ try:
1963 i = int(input)
1964 except ValueError:
1965 return (QtGui.QValidator.Invalid, pos)
1966+
1967 if i > 0:
1968 return (QtGui.QValidator.Acceptable, pos)
1969 else:
1970@@ -756,50 +759,46 @@
1971
1972
1973 class GotoLineToolbar(QtGui.QToolBar):
1974-
1975+
1976 def __init__(self, anotate_window, show_action):
1977 QtGui.QToolBar.__init__(self, gettext("Goto Line"), anotate_window)
1978 self.anotate_window = anotate_window
1979 if 0: self.anotate_window = AnnotateWindow()
1980 self.show_action = show_action
1981-
1982+
1983 self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
1984 self.setMovable (False)
1985-
1986+
1987 label = QtGui.QLabel(gettext("Goto Line: "), self)
1988 self.addWidget(label)
1989-
1990+
1991 self.line_edit = QtGui.QLineEdit(self)
1992- self.line_edit.setValidator(IntValidator(self.line_edit))
1993+ # QIntValidator is working in python3, so we'll use that
1994+ # self.line_edit.setValidator(IntValidator(self.line_edit))
1995+ self.line_edit.setValidator(QtGui.QIntValidator())
1996 self.addWidget(self.line_edit)
1997 label.setBuddy(self.line_edit)
1998-
1999+
2000 go = self.addAction(get_icon("go-next"), gettext("Go"))
2001-
2002+
2003 spacer = QtGui.QWidget()
2004- spacer.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
2005+ spacer.setSizePolicy(QtGui.QSizePolicy.Expanding,
2006+ QtGui.QSizePolicy.Expanding)
2007 self.addWidget(spacer)
2008-
2009+
2010 close = QtGui.QAction(self)
2011- close.setIcon(self.style().standardIcon(
2012- QtGui.QStyle.SP_DialogCloseButton))
2013+ close.setIcon(self.style().standardIcon(QtGui.QStyle.SP_DialogCloseButton))
2014 self.addAction(close)
2015 close.setShortcut((QtCore.Qt.Key_Escape))
2016 close.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
2017 close.setStatusTip(gettext("Close Goto Line"))
2018- self.connect(close,
2019- QtCore.SIGNAL("triggered(bool)"),
2020- self.close_triggered)
2021- self.connect(go,
2022- QtCore.SIGNAL("triggered(bool)"),
2023- self.go_triggered)
2024- self.connect(self.line_edit,
2025- QtCore.SIGNAL("returnPressed()"),
2026- self.go_triggered)
2027-
2028+ self.connect(close, QtCore.SIGNAL("triggered(bool)"), self.close_triggered)
2029+ self.connect(go, QtCore.SIGNAL("triggered(bool)"), self.go_triggered)
2030+ self.connect(self.line_edit, QtCore.SIGNAL("returnPressed()"), self.go_triggered)
2031+
2032 def close_triggered(self, state):
2033 self.show_action.setChecked(False)
2034-
2035+
2036 def go_triggered(self, state=True):
2037 try:
2038 line = int(str(self.line_edit.text()))
2039@@ -811,19 +810,15 @@
2040
2041
2042 class AnnotateLogList(LogList):
2043-
2044+
2045 parent_annotate_window = None
2046-
2047+
2048 def create_context_menu(self):
2049 LogList.create_context_menu(self, diff_is_default_action=False)
2050- set_rev_action = QtGui.QAction(gettext("&Annotate this revision"),
2051- self.context_menu)
2052- self.connect(set_rev_action, QtCore.SIGNAL('triggered()'),
2053- self.parent_annotate_window.set_annotate_revision)
2054- self.context_menu.insertAction(
2055- self.context_menu.actions()[0],
2056- set_rev_action)
2057+ set_rev_action = QtGui.QAction(gettext("&Annotate this revision"), self.context_menu)
2058+ self.connect(set_rev_action, QtCore.SIGNAL('triggered()'), self.parent_annotate_window.set_annotate_revision)
2059+ self.context_menu.insertAction(self.context_menu.actions()[0], set_rev_action)
2060 self.context_menu.setDefaultAction(set_rev_action)
2061-
2062+
2063 def default_action(self, index=None):
2064 self.parent_annotate_window.set_annotate_revision()
2065
2066=== modified file 'lib/autocomplete.py'
2067--- lib/autocomplete.py 2008-11-04 15:15:48 +0000
2068+++ lib/autocomplete.py 2020-07-16 14:28:25 +0000
2069@@ -68,7 +68,7 @@
2070
2071 def compile_regexes(self):
2072 if self.compiled_regexes is None:
2073- self.compiled_regexes = map(re.compile, self.regexes)
2074+ self.compiled_regexes = list(map(re.compile, self.regexes))
2075
2076 def iter_words(self, file):
2077 self.compile_regexes()
2078@@ -77,7 +77,7 @@
2079 for result in regex.findall(line):
2080 if not isinstance(result, tuple):
2081 result = (result,)
2082- for word in filter(None, result):
2083+ for word in [_f for _f in result if _f]:
2084 yield word
2085
2086
2087
2088=== modified file 'lib/bind.py'
2089--- lib/bind.py 2017-09-11 06:53:22 +0000
2090+++ lib/bind.py 2020-07-16 14:28:25 +0000
2091@@ -113,7 +113,7 @@
2092 self.branch_combo.setCurrentIndex(0)
2093
2094 def _get_location(self):
2095- return unicode(self.branch_combo.currentText())
2096+ return str(self.branch_combo.currentText())
2097
2098 def validate(self):
2099 if not self._get_location():
2100
2101=== modified file 'lib/branch.py'
2102--- lib/branch.py 2017-09-11 06:53:22 +0000
2103+++ lib/branch.py 2020-07-16 14:28:25 +0000
2104@@ -49,7 +49,7 @@
2105 # Unless instructed otherwise, use the current directory as
2106 # the parent directory.
2107 if parent_dir is None:
2108- parent_dir = os.getcwdu()
2109+ parent_dir = os.getcwd()
2110 self.parent_dir = parent_dir
2111
2112 # Layout the form, adding the subprocess widgets
2113@@ -68,7 +68,7 @@
2114
2115 # Initialise the fields
2116 fill_combo_with(self.ui.from_location,
2117- u'',
2118+ '',
2119 iter_saved_pull_locations())
2120 if from_location:
2121 self.ui.from_location.setEditText(from_location)
2122@@ -96,7 +96,7 @@
2123 self.ui.from_location.setFocus()
2124
2125 def from_changed(self, from_location):
2126- to_location = self._default_to_location(unicode(from_location))
2127+ to_location = self._default_to_location(str(from_location))
2128 if to_location is not None:
2129 self.ui.to_location.setEditText(to_location)
2130
2131@@ -129,7 +129,7 @@
2132 def get_to_location(self):
2133 """The path the branch was created in."""
2134 # This is used by explorer to find the location to open on completion
2135- return unicode(self.ui.to_location.currentText())
2136+ return str(self.ui.to_location.currentText())
2137
2138 def do_start(self):
2139 args = []
2140@@ -139,7 +139,7 @@
2141 if revision:
2142 args.append('--revision')
2143 args.append(revision)
2144- from_location = unicode(self.ui.from_location.currentText())
2145+ from_location = str(self.ui.from_location.currentText())
2146 to_location = self.get_to_location()
2147 if 'use-existing-dir' in self.cmd_branch_options:
2148 # always use this options because it should be mostly harmless
2149
2150=== modified file 'lib/browse.py'
2151--- lib/browse.py 2017-09-11 06:53:22 +0000
2152+++ lib/browse.py 2020-07-16 14:28:25 +0000
2153@@ -214,7 +214,7 @@
2154
2155 @ui_current_widget
2156 def reload_tree(self):
2157- revstr = unicode(self.revision_edit.text())
2158+ revstr = str(self.revision_edit.text())
2159 if not revstr:
2160 if self.workingtree is not None:
2161 self.revision_spec = "wt:"
2162@@ -231,7 +231,7 @@
2163 else:
2164 try:
2165 revspec = RevisionSpec.from_string(revstr)
2166- except errors.NoSuchRevisionSpec, e:
2167+ except errors.NoSuchRevisionSpec as e:
2168 QtGui.QMessageBox.warning(self,
2169 gettext("Browse"), str(e),
2170 QtGui.QMessageBox.Ok)
2171
2172=== modified file 'lib/bugs.py'
2173--- lib/bugs.py 2017-09-11 06:53:22 +0000
2174+++ lib/bugs.py 2020-07-16 14:28:25 +0000
2175@@ -91,7 +91,7 @@
2176 else:
2177 branch = FakeBranchForBugs()
2178 # try to convert bug urls to tag:id values
2179- for k,n in urls_dict.iteritems():
2180+ for k,n in urls_dict.items():
2181 for tag in bug_tags:
2182 url = bugtracker.get_bug_url(tag, branch, n)
2183 if url == k:
2184@@ -124,7 +124,7 @@
2185 def get_global_bug_tags():
2186 """Return bug tags collected from global config bazaar.conf"""
2187 cfg = config.GlobalConfig()
2188- keys = cfg._get_parser().get('DEFAULT', {}).keys()
2189+ keys = list(cfg._get_parser().get('DEFAULT', {}).keys())
2190 return get_user_bug_trackers_tags(keys)
2191
2192 def get_branch_bug_tags(branch):
2193
2194=== modified file 'lib/cat.py'
2195--- lib/cat.py 2017-11-13 23:31:28 +0000
2196+++ lib/cat.py 2020-07-16 14:28:25 +0000
2197@@ -69,7 +69,7 @@
2198 tree=None, file_id=None, encoding=None,
2199 parent=None):
2200 """Create qcat window."""
2201-
2202+
2203 self.filename = filename
2204 self.revision = revision
2205 self.tree = tree
2206@@ -112,7 +112,7 @@
2207 # we show the bare form as soon as possible.
2208 QBzrWindow.show(self)
2209 QtCore.QTimer.singleShot(0, self.load)
2210-
2211+
2212 @runs_in_loading_queue
2213 @ui_current_widget
2214 @reports_exception()
2215@@ -131,24 +131,24 @@
2216 else:
2217 revision_id = self.revision[0].in_branch(branch).rev_id
2218 self.tree = branch.repository.revision_tree(revision_id)
2219-
2220+
2221 self.file_id = self.tree.path2id(relpath)
2222-
2223+
2224 if not self.file_id:
2225 self.file_id = self.tree.path2id(self.filename)
2226-
2227+
2228 if not self.file_id:
2229 raise errors.BzrCommandError(
2230 "%r is not present in revision %s" % (
2231 self.filename, self.tree.get_revision_id()))
2232-
2233+
2234 self.tree.lock_read()
2235 try:
2236- kind = self.tree.kind(self.filename, self.file_id)
2237+ kind = self.tree.kind(self.filename)
2238 if kind == 'file':
2239- text = self.tree.get_file_text(self.filename, self.file_id)
2240+ text = self.tree.get_file_text(self.filename)
2241 elif kind == 'symlink':
2242- text = self.tree.get_symlink_target(self.filename, self.file_id)
2243+ text = self.tree.get_symlink_target(self.filename)
2244 else:
2245 text = ''
2246 finally:
2247@@ -184,7 +184,7 @@
2248 Supported file types: text, image, binary
2249 """
2250 if kind == 'file':
2251- if not '\0' in text:
2252+ if not b'\0' in text:
2253 return 'text file', self._create_text_view
2254 else:
2255 ext = file_extension(relpath).lower()
2256@@ -331,6 +331,7 @@
2257 # make temp file
2258 import os
2259 import tempfile
2260+ # RJLRJL Check this QBzr reference
2261 qdir = os.path.join(tempfile.gettempdir(), 'QBzr', 'qcat')
2262 if not os.path.isdir(qdir):
2263 os.makedirs(qdir)
2264
2265=== added file 'lib/cleanup.py'
2266--- lib/cleanup.py 1970-01-01 00:00:00 +0000
2267+++ lib/cleanup.py 2020-07-16 14:28:25 +0000
2268@@ -0,0 +1,184 @@
2269+# Copyright (C) 2009, 2010 Canonical Ltd
2270+#
2271+# This program is free software; you can redistribute it and/or modify
2272+# it under the terms of the GNU General Public License as published by
2273+# the Free Software Foundation; either version 2 of the License, or
2274+# (at your option) any later version.
2275+#
2276+# This program is distributed in the hope that it will be useful,
2277+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2278+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2279+# GNU General Public License for more details.
2280+#
2281+# You should have received a copy of the GNU General Public License
2282+# along with this program; if not, write to the Free Software
2283+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2284+
2285+"""Helpers for managing cleanup functions and the errors they might raise.
2286+
2287+The usual way to run cleanup code in Python is::
2288+
2289+ try:
2290+ do_something()
2291+ finally:
2292+ cleanup_something()
2293+
2294+However if both `do_something` and `cleanup_something` raise an exception
2295+Python will forget the original exception and propagate the one from
2296+cleanup_something. Unfortunately, this is almost always much less useful than
2297+the original exception.
2298+
2299+If you want to be certain that the first, and only the first, error is raised,
2300+then use::
2301+
2302+ operation = OperationWithCleanups(do_something)
2303+ operation.add_cleanup(cleanup_something)
2304+ operation.run_simple()
2305+
2306+This is more inconvenient (because you need to make every try block a
2307+function), but will ensure that the first error encountered is the one raised,
2308+while also ensuring all cleanups are run. See OperationWithCleanups for more
2309+details.
2310+"""
2311+
2312+from __future__ import absolute_import
2313+
2314+from collections import deque
2315+# import sys
2316+# from . import (
2317+# debug,
2318+# trace,
2319+# )
2320+
2321+from breezy import (
2322+ debug,
2323+ trace,
2324+ )
2325+
2326+
2327+def _log_cleanup_error(exc):
2328+ trace.mutter('Cleanup failed:')
2329+ trace.log_exception_quietly()
2330+ if 'cleanup' in debug.debug_flags:
2331+ trace.warning('brz: warning: Cleanup failed: %s', exc)
2332+
2333+
2334+def _run_cleanup(func, *args, **kwargs):
2335+ """Run func(*args, **kwargs), logging but not propagating any error it
2336+ raises.
2337+
2338+ :returns: True if func raised no errors, else False.
2339+ """
2340+ try:
2341+ func(*args, **kwargs)
2342+ except KeyboardInterrupt:
2343+ raise
2344+ except Exception as exc:
2345+ _log_cleanup_error(exc)
2346+ return False
2347+ return True
2348+
2349+
2350+def _run_cleanups(funcs):
2351+ """Run a series of cleanup functions."""
2352+ for func, args, kwargs in funcs:
2353+ _run_cleanup(func, *args, **kwargs)
2354+
2355+
2356+class ObjectWithCleanups(object):
2357+ """A mixin for objects that hold a cleanup list.
2358+
2359+ Subclass or client code can call add_cleanup and then later `cleanup_now`.
2360+ """
2361+ def __init__(self):
2362+ self.cleanups = deque()
2363+
2364+ def add_cleanup(self, cleanup_func, *args, **kwargs):
2365+ """Add a cleanup to run.
2366+
2367+ Cleanups may be added at any time.
2368+ Cleanups will be executed in LIFO order.
2369+ """
2370+ self.cleanups.appendleft((cleanup_func, args, kwargs))
2371+
2372+ def cleanup_now(self):
2373+ _run_cleanups(self.cleanups)
2374+ self.cleanups.clear()
2375+
2376+
2377+class OperationWithCleanups(ObjectWithCleanups):
2378+ """A way to run some code with a dynamic cleanup list.
2379+
2380+ This provides a way to add cleanups while the function-with-cleanups is
2381+ running.
2382+
2383+ Typical use::
2384+
2385+ operation = OperationWithCleanups(some_func)
2386+ operation.run(args...)
2387+
2388+ where `some_func` is::
2389+
2390+ def some_func(operation, args, ...):
2391+ do_something()
2392+ operation.add_cleanup(something)
2393+ # etc
2394+
2395+ Note that the first argument passed to `some_func` will be the
2396+ OperationWithCleanups object. To invoke `some_func` without that, use
2397+ `run_simple` instead of `run`.
2398+ """
2399+
2400+ def __init__(self, func):
2401+ super(OperationWithCleanups, self).__init__()
2402+ self.func = func
2403+
2404+ def run(self, *args, **kwargs):
2405+ return _do_with_cleanups(self.cleanups, self.func, self, *args, **kwargs)
2406+
2407+ def run_simple(self, *args, **kwargs):
2408+ return _do_with_cleanups(self.cleanups, self.func, *args, **kwargs)
2409+
2410+
2411+def _do_with_cleanups(cleanup_funcs, func, *args, **kwargs):
2412+ """Run `func`, then call all the cleanup_funcs.
2413+
2414+ All the cleanup_funcs are guaranteed to be run. The first exception raised
2415+ by func or any of the cleanup_funcs is the one that will be propagted by
2416+ this function (subsequent errors are caught and logged).
2417+
2418+ Conceptually similar to::
2419+
2420+ try:
2421+ return func(*args, **kwargs)
2422+ finally:
2423+ for cleanup, cargs, ckwargs in cleanup_funcs:
2424+ cleanup(*cargs, **ckwargs)
2425+
2426+ It avoids several problems with using try/finally directly:
2427+ * an exception from func will not be obscured by a subsequent exception
2428+ from a cleanup.
2429+ * an exception from a cleanup will not prevent other cleanups from
2430+ running (but the first exception encountered is still the one
2431+ propagated).
2432+
2433+ Unike `_run_cleanup`, `_do_with_cleanups` can propagate an exception from a
2434+ cleanup, but only if there is no exception from func.
2435+ """
2436+ try:
2437+ result = func(*args, **kwargs)
2438+ except:
2439+ # We have an exception from func already, so suppress cleanup errors.
2440+ _run_cleanups(cleanup_funcs)
2441+ raise
2442+ # No exception from func, so allow first cleanup error to propgate.
2443+ pending_cleanups = iter(cleanup_funcs)
2444+ try:
2445+ for cleanup, c_args, c_kwargs in pending_cleanups:
2446+ cleanup(*c_args, **c_kwargs)
2447+ except:
2448+ # Still run the remaining cleanups but suppress any further errors.
2449+ _run_cleanups(pending_cleanups)
2450+ raise
2451+ # No error, so we can return the result
2452+ return result
2453
2454=== modified file 'lib/commands.py'
2455--- lib/commands.py 2017-09-11 06:53:22 +0000
2456+++ lib/commands.py 2020-07-16 14:28:25 +0000
2457@@ -19,6 +19,7 @@
2458 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2459
2460 import signal
2461+import contextlib
2462
2463 from breezy import errors
2464 from breezy.commands import Command
2465@@ -40,6 +41,7 @@
2466 from breezy.branch import Branch
2467 from breezy.controldir import ControlDir
2468 from breezy.workingtree import WorkingTree
2469+from breezy.diff import get_trees_and_branches_to_diff_locked
2470
2471 from breezy.plugins.qbrz.lib import i18n
2472 from breezy.plugins.qbrz.lib.add import AddWindow
2473@@ -85,7 +87,7 @@
2474
2475 from breezy.plugins.qbrz.lib.diff_arg import DiffArgProvider
2476
2477-CUR_DIR=u'.'
2478+CUR_DIR='.'
2479
2480 class InvalidEncodingOption(errors.BzrError):
2481
2482@@ -96,8 +98,7 @@
2483 errors.BzrError.__init__(self)
2484 self.encoding = encoding
2485 import encodings
2486- self.valid = ', '.join(sorted(list(
2487- set(encodings.aliases.aliases.values())))).replace('_','-')
2488+ self.valid = ', '.join(sorted(list(set(encodings.aliases.aliases.values())))).replace('_','-')
2489
2490
2491 def check_encoding(encoding):
2492@@ -108,8 +109,7 @@
2493
2494 class PyQt4NotInstalled(errors.BzrError):
2495
2496- _fmt = ('QBzr require at least PyQt 4.4 and '
2497- 'Qt 4.4 to run. Please check your install')
2498+ _fmt = ('QBrz requires at least PyQt 4.4 and Qt 4.4 to run. Please check your install')
2499
2500
2501 def report_missing_pyqt(unbound):
2502@@ -120,7 +120,7 @@
2503 def run(self, *args, **kwargs):
2504 try:
2505 return unbound(self, *args, **kwargs)
2506- except ImportError, e:
2507+ except ImportError as e:
2508 if str(e).endswith('PyQt4'):
2509 raise PyQt4NotInstalled
2510 raise
2511@@ -163,10 +163,10 @@
2512 std_ui_factory = ui.ui_factory
2513 try:
2514 ui.ui_factory = QUIFactory()
2515-
2516+
2517 # Handle interupt signal correctly.
2518 signal.signal(signal.SIGINT, signal.SIG_DFL)
2519-
2520+
2521 # Set up global exception handling.
2522 from breezy.plugins.qbrz.lib.trace import excepthook
2523 sys.excepthook = excepthook
2524@@ -195,11 +195,9 @@
2525 ui.ui_factory = std_ui_factory
2526
2527
2528-ui_mode_option = Option("ui-mode",
2529- help="Causes dialogs to wait after the operation is complete.")
2530+ui_mode_option = Option("ui-mode", help="Causes dialogs to wait after the operation is complete.")
2531 execute_option = Option("execute", short_name='e',
2532- help="Causes dialogs to start the underlying action immediately without "
2533- "waiting for user input.")
2534+ help="Causes dialogs to start the underlying action immediately without waiting for user input.")
2535
2536 # A special option so 'revision' can be passed as a simple string, when we do
2537 # *not* want breezy's feature of parsing the revision string before passing it.
2538@@ -209,23 +207,23 @@
2539 # 'revision' as normal.
2540 simple_revision_option = Option("revision",
2541 short_name='r',
2542- type=unicode,
2543+ type=str,
2544 help='See "help revisionspec" for details.')
2545
2546
2547-def bzr_option(cmd_name, opt_name):
2548- """Helper so we can 'borrow' options from bzr itself without needing to
2549+def brz_option(cmd_name, opt_name):
2550+ """Helper so we can 'borrow' options from brz itself without needing to
2551 duplicate the help text etc. Pass the builtin bzr command name and an
2552 option name.
2553
2554 eg:
2555- takes_options = [bzr_option("push", "create-prefix")]
2556+ takes_options = [brz_option("push", "create-prefix")]
2557
2558 would give a command the exact same '--create-prefix' option as bzr's
2559 push command has, including help text, parsing, etc.
2560 """
2561 from breezy.commands import get_cmd_object
2562- cmd=get_cmd_object(cmd_name, False)
2563+ cmd = get_cmd_object(cmd_name, False)
2564 return cmd.options()[opt_name]
2565
2566
2567@@ -233,13 +231,10 @@
2568 """Show the origin of each line in a file."""
2569 takes_args = ['filename']
2570 takes_options = ['revision',
2571- Option('encoding', type=check_encoding,
2572- help='Encoding of files content (default: utf-8).'),
2573+ Option('encoding', type=check_encoding, help='Encoding of files content (default: utf-8).'),
2574 ui_mode_option,
2575 Option('no-graph', help="Shows the log with no graph."),
2576- Option('line', short_name='L', type=int, argname='N',
2577- param_name='activate_line',
2578- help='Activate line N on start.'),
2579+ Option('line', short_name='L', type=int, argname='N', param_name='activate_line', help='Activate line N on start.'),
2580 ]
2581 aliases = ['qann', 'qblame']
2582
2583@@ -248,8 +243,7 @@
2584 back to this function to process the command-line args and convert
2585 them into the branch and tree etc needed by the UI.
2586 """
2587- wt, branch, relpath = \
2588- ControlDir.open_containing_tree_or_branch(filename)
2589+ wt, branch, relpath = ControlDir.open_containing_tree_or_branch(filename)
2590 if wt is not None:
2591 wt.lock_read()
2592 else:
2593@@ -259,23 +253,18 @@
2594 if wt is not None:
2595 tree = wt
2596 else:
2597- tree = branch.repository.revision_tree(
2598- branch.last_revision())
2599+ tree = branch.repository.revision_tree(branch.last_revision())
2600 elif len(revision) != 1:
2601- raise errors.BzrCommandError(
2602- 'bzr qannotate --revision takes exactly 1 argument')
2603+ raise errors.BzrCommandError('brz qannotate --revision takes exactly 1 argument')
2604 else:
2605- tree = branch.repository.revision_tree(
2606- revision_id = revision[0].in_history(branch).rev_id)
2607+ tree = branch.repository.revision_tree(revision_id = revision[0].in_history(branch).rev_id)
2608
2609 file_id = tree.path2id(relpath)
2610 if file_id is None:
2611 raise errors.NotVersionedError(filename)
2612- [(path, entry)] = list(tree.iter_entries_by_dir(
2613- specific_file_ids=[file_id]))
2614+ [(path, entry)] = list(tree.iter_entries_by_dir(specific_files=[filename]))
2615 if entry.kind != 'file':
2616- raise errors.BzrCommandError(
2617- 'bzr qannotate only works for files (got %r)' % entry.kind)
2618+ raise errors.BzrCommandError('brz qannotate only works for files (got %r)' % entry.kind)
2619 #repo = branch.repository
2620 #w = repo.weave_store.get_weave(file_id, repo.get_transaction())
2621 #content = list(w.annotate_iter(entry.revision))
2622@@ -307,7 +296,10 @@
2623 takes_options = [ui_mode_option]
2624
2625 def _qbrz_run(self, selected_list=None, ui_mode=False):
2626+ # print('\n:: cmd_add was passed ', selected_list)
2627 tree, selected_list = WorkingTree.open_containing_paths(selected_list)
2628+ # print('\n::: cmd_add started', tree, selected_list)
2629+
2630 if selected_list == ['']:
2631 selected_list = None
2632 self.main_window = AddWindow(tree, selected_list, dialog=False, ui_mode=ui_mode)
2633@@ -318,7 +310,7 @@
2634 class cmd_qrevert(QBzrCommand):
2635 """Revert changes files."""
2636 takes_args = ['selected*']
2637- takes_options = [ui_mode_option, bzr_option('revert', 'no-backup')]
2638+ takes_options = [ui_mode_option, brz_option('revert', 'no-backup')]
2639
2640 def _qbrz_run(self, selected_list=None, ui_mode=False, no_backup=False):
2641 tree, selected_list = WorkingTree.open_containing_paths(selected_list)
2642@@ -351,7 +343,7 @@
2643 aliases = ['qbw']
2644
2645 def _qbrz_run(self, revision=None, location=None):
2646- Branch.open_containing(location or u'.') # if there is no branch we want NotBranchError raised
2647+ Branch.open_containing(location or '.') # if there is no branch we want NotBranchError raised
2648 if revision is None:
2649 win = BrowseWindow(location = location)
2650 else:
2651@@ -364,9 +356,9 @@
2652 """GUI for committing revisions."""
2653 takes_args = ['selected*']
2654 takes_options = [
2655- bzr_option('commit', 'message'),
2656- bzr_option('commit', 'local'),
2657- bzr_option('commit', 'file'),
2658+ brz_option('commit', 'message'),
2659+ brz_option('commit', 'local'),
2660+ brz_option('commit', 'file'),
2661 Option('file-encoding', type=check_encoding,
2662 help='Encoding of commit message file content.'),
2663 ui_mode_option,
2664@@ -407,31 +399,25 @@
2665 Option('renamed', short_name='R', help='Show diff for renamed files.'),
2666 Option('ignore-whitespace', short_name='w',
2667 help="Ignore whitespace when finding differences"),
2668- bzr_option('diff', 'old'),
2669- bzr_option('diff', 'new'),
2670+ brz_option('diff', 'old'),
2671+ brz_option('diff', 'new'),
2672 ]
2673 if 'change' in Option.OPTIONS:
2674 takes_options.append('change')
2675 aliases = ['qdi']
2676
2677 def get_diff_window_args(self, processEvents, add_cleanup):
2678+ # RJL if you get a ``AttributeError: 'function' object has no attribute 'enter_context'``
2679+ # error, or something similar, use something like:
2680+ #
2681+ # exit_stack = contextlib.ExitStack()
2682+ #
2683+ # and pass that as add_cleanup
2684+ #
2685 args = {}
2686- try:
2687- from breezy.diff import get_trees_and_branches_to_diff_locked
2688- except ImportError:
2689- from breezy.diff import get_trees_and_branches_to_diff
2690- (args["old_tree"], args["new_tree"],
2691- args["old_branch"], args["new_branch"],
2692- args["specific_files"], _) = \
2693- get_trees_and_branches_to_diff(
2694- self.file_list, self.revision, self.old, self.new)
2695- else:
2696- (args["old_tree"], args["new_tree"],
2697- args["old_branch"], args["new_branch"],
2698- args["specific_files"], _) = \
2699- get_trees_and_branches_to_diff_locked(
2700- self.file_list, self.revision, self.old, self.new,
2701- add_cleanup)
2702+ (args["old_tree"], args["new_tree"],
2703+ args["old_branch"], args["new_branch"],
2704+ args["specific_files"], _) = get_trees_and_branches_to_diff_locked(self.file_list, self.revision, self.old, self.new, add_cleanup)
2705 args["ignore_whitespace"] = self.ignore_whitespace
2706 return args
2707
2708@@ -459,8 +445,7 @@
2709 old=None, new=None, ui_mode=False):
2710
2711 if revision and len(revision) > 2:
2712- raise errors.BzrCommandError('bzr qdiff --revision takes exactly'
2713- ' one or two revision specifiers')
2714+ raise errors.BzrCommandError('brz qdiff --revision takes exactly one or two revision specifiers')
2715 # changes filter
2716 filter_options = FilterOptions(added=added, deleted=deleted,
2717 modified=modified, renamed=renamed)
2718@@ -474,11 +459,7 @@
2719 self.new = new
2720 self.ignore_whitespace = ignore_whitespace
2721
2722- window = DiffWindow(self,
2723- complete=complete,
2724- encoding=encoding,
2725- filter_options=filter_options,
2726- ui_mode=ui_mode)
2727+ window = DiffWindow(self, complete=complete, encoding=encoding, filter_options=filter_options, ui_mode=ui_mode)
2728 window.show()
2729 self._application.exec_()
2730
2731@@ -508,14 +489,11 @@
2732 takes_options = [
2733 ui_mode_option,
2734 Option('no-graph', help="Shows the log with no graph."),
2735- Option('show-trees', help="Show working trees that have changes "
2736- "as nodes in the graph"),
2737+ Option('show-trees', help="Show working trees that have changes as nodes in the graph"),
2738 ]
2739
2740- def _qbrz_run(self, locations_list=None, ui_mode=False, no_graph=False,
2741- show_trees=False):
2742- window = LogWindow(locations_list, None, None, ui_mode=ui_mode,
2743- no_graph=no_graph, show_trees=show_trees)
2744+ def _qbrz_run(self, locations_list=None, ui_mode=False, no_graph=False, show_trees=False):
2745+ window = LogWindow(locations_list, None, None, ui_mode=ui_mode, no_graph=no_graph, show_trees=show_trees)
2746 window.show()
2747 self._application.exec_()
2748
2749@@ -541,17 +519,14 @@
2750
2751 takes_options = [
2752 'revision',
2753- Option('encoding', type=check_encoding,
2754- help='Encoding of files content (default: utf-8).'),
2755- Option('native',
2756- help='Show file with native application.'),
2757+ Option('encoding', type=check_encoding, help='Encoding of files content (default: utf-8).'),
2758+ Option('native', help='Show file with native application.'),
2759 ]
2760 takes_args = ['filename']
2761
2762 def _qbrz_run(self, filename, revision=None, encoding=None, native=None):
2763 if revision is not None and len(revision) != 1:
2764- raise errors.BzrCommandError("bzr qcat --revision takes exactly"
2765- " one revision specifier")
2766+ raise errors.BzrCommandError("brz qcat --revision takes exactly one revision specifier")
2767
2768 if native:
2769 branch, relpath = Branch.open_containing(filename)
2770@@ -563,9 +538,7 @@
2771 result = cat_to_native_app(tree, relpath)
2772 return int(not result)
2773
2774-
2775- window = QBzrCatWindow(filename = filename, revision = revision,
2776- encoding = encoding)
2777+ window = QBzrCatWindow(filename = filename, revision = revision, encoding = encoding)
2778 window.show()
2779 self._application.exec_()
2780
2781@@ -576,7 +549,7 @@
2782 takes_options = [
2783 'remember', 'overwrite',
2784 simple_revision_option,
2785- bzr_option('pull', 'directory'),
2786+ brz_option('pull', 'directory'),
2787 ui_mode_option,
2788 ]
2789 takes_args = ['location?']
2790@@ -605,9 +578,9 @@
2791
2792 takes_options = [ui_mode_option,
2793 simple_revision_option,
2794- bzr_option('merge', 'directory'),
2795- bzr_option('merge', 'force'),
2796- bzr_option('merge', 'uncommitted'),
2797+ brz_option('merge', 'directory'),
2798+ brz_option('merge', 'force'),
2799+ brz_option('merge', 'uncommitted'),
2800 'remember']
2801 takes_args = ['location?']
2802
2803@@ -632,9 +605,9 @@
2804 """Update a mirror of this branch."""
2805
2806 takes_options = ['remember', 'overwrite',
2807- bzr_option("push", "create-prefix"),
2808- bzr_option("push", "use-existing-dir"),
2809- bzr_option("push", "directory"),
2810+ brz_option("push", "create-prefix"),
2811+ brz_option("push", "use-existing-dir"),
2812+ brz_option("push", "directory"),
2813 ui_mode_option]
2814 takes_args = ['location?']
2815
2816@@ -669,7 +642,7 @@
2817 takes_options = [simple_revision_option,
2818 ui_mode_option]
2819 try:
2820- takes_options.append(bzr_option("branch", "bind"))
2821+ takes_options.append(brz_option("branch", "bind"))
2822 except KeyError:
2823 # older version of bzr that doesn't support the option
2824 pass
2825@@ -704,19 +677,17 @@
2826 ' acceptable for verification.',
2827 short_name='k',
2828 type=str,),
2829- 'revision',
2830+ 'revision',
2831 ]
2832 takes_args = ['location?']
2833
2834 def _qbrz_run(self, acceptable_keys=None, revision=None, location=CUR_DIR):
2835 if gpg.GPGStrategy.verify_signatures_available():
2836- window = QBzrVerifySignaturesWindow(acceptable_keys, revision,
2837- location)
2838+ window = QBzrVerifySignaturesWindow(acceptable_keys, revision, location)
2839 window.show()
2840 self._application.exec_()
2841 else:
2842- raise errors.DependencyNotPresent("python-gpgme",
2843- "python-gpgme not installed")
2844+ raise errors.DependencyNotPresent("python-gpgme", "python-gpgme not installed")
2845
2846 class cmd_qinit(QBzrCommand):
2847 """Initializes a new branch or shared repository."""
2848@@ -734,11 +705,8 @@
2849 __doc__ = breezy.builtins.cmd_merge.__doc__
2850
2851 takes_options = breezy.builtins.cmd_merge.takes_options + [
2852- Option('qpreview', help='Instead of merging, '
2853- 'show a diff of the merge in a GUI window.'),
2854- Option('encoding', type=check_encoding,
2855- help='Encoding of files content, used with --qpreview '
2856- '(default: utf-8).'),
2857+ Option('qpreview', help='Instead of merging, show a diff of the merge in a GUI window.'),
2858+ Option('encoding', type=check_encoding, help='Encoding of files content, used with --qpreview (default: utf-8).'),
2859 ]
2860
2861 def run(self, *args, **kw):
2862@@ -865,7 +833,6 @@
2863 self.main_window.show()
2864 self._application.exec_()
2865
2866-
2867 class cmd_qhelp(QBzrCommand):
2868 """Shows a help window"""
2869
2870@@ -885,9 +852,9 @@
2871 takes_args = ['tag_name?']
2872 takes_options = [
2873 ui_mode_option,
2874- bzr_option('tag', 'delete'),
2875- bzr_option('tag', 'directory'),
2876- bzr_option('tag', 'force'),
2877+ brz_option('tag', 'delete'),
2878+ brz_option('tag', 'directory'),
2879+ brz_option('tag', 'force'),
2880 'revision',
2881 ]
2882
2883@@ -997,7 +964,7 @@
2884 from breezy.plugins.qbrz.lib.switch import QBzrSwitchWindow
2885
2886 branch = Branch.open_containing(CUR_DIR)[0]
2887- contrldir = ControlDir.open_containing(CUR_DIR)[0]
2888+ controldir = ControlDir.open_containing(CUR_DIR)[0]
2889 self.main_window = QBzrSwitchWindow(branch, controldir, location, ui_mode)
2890 self.main_window.show()
2891 self._application.exec_()
2892@@ -1078,11 +1045,11 @@
2893 Option('directory',
2894 help='Working directory.',
2895 short_name='d',
2896- type=unicode,
2897+ type=str,
2898 ),
2899 Option('category',
2900 help='Initial category selection.',
2901- type=unicode,
2902+ type=str,
2903 ),
2904 execute_option,
2905 ]
2906@@ -1106,15 +1073,15 @@
2907 execute=execute)
2908 window.show()
2909 self._application.exec_()
2910-
2911+
2912 class cmd_qshelve(QBzrCommand):
2913 """Shelve selected changes away."""
2914 takes_args = ['file*']
2915 takes_options = [
2916 ui_mode_option,
2917- bzr_option('shelve', 'list'),
2918- bzr_option('shelve', 'directory'),
2919- bzr_option('shelve', 'message'),
2920+ brz_option('shelve', 'list'),
2921+ brz_option('shelve', 'directory'),
2922+ brz_option('shelve', 'message'),
2923 Option('all', help='Select all changes.'),
2924 Option('complete', help='Show complete files.'),
2925 Option('ignore-whitespace', short_name='w',
2926@@ -1123,7 +1090,7 @@
2927 help='Encoding of files content (default: utf-8).'),
2928 ]
2929
2930- def _qbrz_run(self, file_list=None, list=False, directory=None, ui_mode=False,
2931+ def _qbrz_run(self, file_list=None, list=False, directory=None, ui_mode=False,
2932 complete=False, ignore_whitespace=False, encoding=None,
2933 all=False, message=None):
2934 if list:
2935@@ -1131,7 +1098,7 @@
2936 else:
2937 initial_tab = 0
2938 self.main_window = ShelveWindow(file_list=file_list, directory=directory, ui_mode=ui_mode,
2939- initial_tab=initial_tab, complete=complete,
2940+ initial_tab=initial_tab, complete=complete,
2941 ignore_whitespace=ignore_whitespace, encoding=encoding,
2942 select_all=all, message=message)
2943 self.main_window.show()
2944@@ -1141,7 +1108,7 @@
2945 """Restore shalved changes."""
2946 takes_options = [
2947 ui_mode_option,
2948- bzr_option('unshelve', 'directory'),
2949+ brz_option('unshelve', 'directory'),
2950 Option('complete', help='Show complete files.'),
2951 Option('ignore-whitespace', short_name='w',
2952 help="Ignore whitespace when finding differences.(Only work when --list specified)"),
2953@@ -1149,10 +1116,10 @@
2954 help='Encoding of files content (default: utf-8).'),
2955 ]
2956
2957- def _qbrz_run(self, directory=None, ui_mode=False,
2958+ def _qbrz_run(self, directory=None, ui_mode=False,
2959 complete=False, ignore_whitespace=False, encoding=None):
2960 self.main_window = ShelveWindow(directory=directory, ui_mode=ui_mode,
2961- initial_tab=1, complete=complete,
2962+ initial_tab=1, complete=complete,
2963 ignore_whitespace=ignore_whitespace, encoding=encoding)
2964 self.main_window.show()
2965 self._application.exec_()
2966@@ -1163,7 +1130,7 @@
2967 takes_args = []
2968 takes_options = [
2969 ui_mode_option,
2970- bzr_option('ignore', 'directory'),
2971+ brz_option('ignore', 'directory'),
2972 ]
2973 aliases = []
2974
2975
2976=== modified file 'lib/commit.py'
2977--- lib/commit.py 2017-09-11 06:53:22 +0000
2978+++ lib/commit.py 2020-07-16 14:28:25 +0000
2979@@ -69,9 +69,11 @@
2980
2981 def __init__(self, spell_checker, parent=None, main_window=None):
2982 QtGui.QTextEdit.__init__(self, parent)
2983+ # RJL The completer, I think, is to provide suggestions for anything typed
2984 self.completer = None
2985 self.spell_checker = spell_checker
2986- self.eow = QtCore.QString("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=")
2987+ # RJL eow = 'end of word'?
2988+ self.eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
2989 self.main_window = main_window
2990
2991 def inputMethodEvent(self, e):
2992@@ -98,15 +100,25 @@
2993 QtGui.QTextEdit.keyPressEvent(self, e)
2994
2995 ctrlOrShift = e.modifiers() & (QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier)
2996- if ctrlOrShift and e.text().isEmpty():
2997+ # if ctrlOrShift and e.text().isEmpty():
2998+ if ctrlOrShift and not e.text():
2999 return
3000
3001 hasModifier = (e.modifiers() != QtCore.Qt.NoModifier) and not ctrlOrShift
3002 completionPrefix = self.textUnderCursor()
3003
3004- if not isShortcut and (hasModifier or e.text().isEmpty()
3005- or completionPrefix.length() < 2
3006- or self.eow.contains(e.text().right(1))):
3007+ # RJL I *think* this is trying to find out whether to hide or display a list
3008+ # of possible completions. right() is a QString method that:
3009+ #
3010+ # Returns a substring that contains the n rightmost characters of the string.
3011+ # The entire string is returned if n is greater than size() or less than zero.
3012+ # QString x = "Pineapple";
3013+ # QString y = x.right(5); // y == "apple"
3014+ #
3015+ # or simply x[-5:] in the land of Python, .right(1) is the last letter
3016+ # which is e.text()[-1:]
3017+
3018+ if not isShortcut and (hasModifier or not e.text() or len(completionPrefix) < 2 or e.text()[-1:] in self.eow):
3019 c.popup().hide()
3020 return
3021
3022@@ -115,8 +127,7 @@
3023 c.popup().setCurrentIndex(c.completionModel().index(0, 0))
3024
3025 cr = self.cursorRect()
3026- cr.setWidth(c.popup().sizeHintForColumn(0) +
3027- c.popup().verticalScrollBar().sizeHint().width())
3028+ cr.setWidth(c.popup().sizeHintForColumn(0) + c.popup().verticalScrollBar().sizeHint().width())
3029 c.complete(cr);
3030
3031 def textUnderCursor(self):
3032@@ -126,41 +137,40 @@
3033
3034 def insertCompletion(self, completion):
3035 tc = self.textCursor()
3036- extra = completion.length() - self.completer.completionPrefix().length()
3037+ extra = len(completion) - len(self.completer.completionPrefix())
3038 tc.movePosition(QtGui.QTextCursor.Left)
3039 tc.movePosition(QtGui.QTextCursor.EndOfWord)
3040- tc.insertText(completion.right(extra))
3041+ # We want the right-most 'extra' letters
3042+ # tc.insertText(completion.right(extra))
3043+ tc.insertText(completion[-extra:])
3044 self.setTextCursor(tc)
3045
3046 def setCompleter(self, completer):
3047 self.completer = completer
3048 completer.setWidget(self)
3049 completer.setCaseSensitivity(QtCore.Qt.CaseSensitive)
3050- self.connect(completer, QtCore.SIGNAL("activated(QString)"),
3051- self.insertCompletion)
3052+ self.connect(completer, QtCore.SIGNAL("activated(QString)"), self.insertCompletion)
3053
3054 def contextMenuEvent(self, event):
3055 menu = self.createStandardContextMenu(event.globalPos())
3056-
3057+
3058 self.context_tc = self.cursorForPosition(event.pos())
3059 self.context_tc.movePosition(QtGui.QTextCursor.StartOfWord)
3060- self.context_tc.movePosition(QtGui.QTextCursor.EndOfWord,
3061- QtGui.QTextCursor.KeepAnchor)
3062- text = unicode(self.context_tc.selectedText())
3063+ self.context_tc.movePosition(QtGui.QTextCursor.EndOfWord, QtGui.QTextCursor.KeepAnchor)
3064+ text = str(self.context_tc.selectedText())
3065 if list(self.spell_checker.check(text)):
3066 suggestions = self.spell_checker.suggest(text)
3067 first_action = menu.actions()[0]
3068 for suggestion in suggestions:
3069 action = QtGui.QAction(suggestion, self)
3070- self.connect(action, QtCore.SIGNAL("triggered(bool)"),
3071- self.suggestion_selected(suggestion))
3072+ self.connect(action, QtCore.SIGNAL("triggered(bool)"), self.suggestion_selected(suggestion))
3073 menu.insertAction(first_action, action)
3074 if suggestions:
3075 menu.insertSeparator(first_action)
3076-
3077+
3078 menu.exec_(event.globalPos())
3079 event.accept()
3080-
3081+
3082 def suggestion_selected(self, text):
3083 def _suggestion_selected(b):
3084 self.context_tc.insertText(text);
3085@@ -175,12 +185,12 @@
3086 # that is going to make this much slower.
3087 self.header().hideSection(0)
3088 self.log_model.last_rev_is_placeholder = True
3089-
3090+
3091 def load_tree(self, tree):
3092 bi = BranchInfo('', tree, tree.branch)
3093 self.log_model.load(
3094 (bi,), bi, None, False, logmodel.PendingMergesGraphVizLoader)
3095-
3096+
3097 def create_context_menu(self, file_ids):
3098 super(PendingMergesList, self).create_context_menu(file_ids)
3099 showinfo = QtGui.QAction("Show &information...", self)
3100@@ -196,19 +206,19 @@
3101
3102 def default_action(self, index=None):
3103 """Show information of a single revision from a index."""
3104-
3105+
3106 if index is None:
3107 index = self.currentIndex()
3108-
3109+
3110 # XXX We should make this show all selected revisions...
3111-
3112- revid = str(index.data(logmodel.RevIdRole).toString())
3113+
3114+ revid = index.data(logmodel.RevIdRole)
3115 branch = self.log_model.graph_viz.get_revid_branch(revid)
3116 parent_window = self.window()
3117 window = RevisionView(revid, branch, parent=parent_window)
3118 window.show()
3119 parent_window.windows.append(window)
3120-
3121+
3122
3123 class CommitWindow(SubProcessDialog):
3124
3125@@ -230,10 +240,10 @@
3126
3127 self.is_bound = bool(tree.branch.get_bound_location())
3128 self.has_pending_merges = len(tree.get_parent_ids())>1
3129-
3130+
3131 if self.has_pending_merges and selected_list:
3132 raise errors.CannotCommitSelectedFileMerge(selected_list)
3133-
3134+
3135 self.windows = []
3136 self.initial_selected_list = selected_list
3137
3138@@ -274,7 +284,7 @@
3139 if local:
3140 self.local_checkbox.setChecked(True)
3141 self.update_branch_groupbox()
3142-
3143+
3144 self.not_uptodate_errors = {
3145 'BoundBranchOutOfDate': gettext(
3146 'Local branch is out of date with master branch.\n'
3147@@ -285,25 +295,25 @@
3148 }
3149 self.not_uptodate_info = InfoWidget(branch_groupbox)
3150 not_uptodate_layout = QtGui.QHBoxLayout(self.not_uptodate_info)
3151-
3152+
3153 # XXX this is to big. Resize
3154 not_uptodate_icon = QtGui.QLabel()
3155 not_uptodate_icon.setPixmap(self.style().standardPixmap(
3156 QtGui.QStyle.SP_MessageBoxWarning))
3157 not_uptodate_layout.addWidget(not_uptodate_icon)
3158-
3159+
3160 self.not_uptodate_label = QtGui.QLabel('error message goes here')
3161 not_uptodate_layout.addWidget(self.not_uptodate_label, 2)
3162-
3163+
3164 update_button = QtGui.QPushButton(gettext('Update'))
3165 self.connect(update_button, QtCore.SIGNAL("clicked(bool)"),
3166 self.open_update_win)
3167
3168 not_uptodate_layout.addWidget(update_button)
3169-
3170+
3171 self.not_uptodate_info.hide()
3172 branch_layout.addWidget(self.not_uptodate_info, 3, 0, 1, 2)
3173-
3174+
3175 splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self)
3176
3177 message_groupbox = QtGui.QGroupBox(gettext("Message"), splitter)
3178@@ -323,24 +333,24 @@
3179 else:
3180 self.show_nonversioned_checkbox.setChecked(QtCore.Qt.Unchecked)
3181
3182- self.filelist = TreeWidget(self)
3183- self.filelist.throbber = self.throbber
3184+ self.filelist_widget = TreeWidget(self)
3185+ self.filelist_widget.throbber = self.throbber
3186 if show_nonversioned:
3187- self.filelist.tree_model.set_select_all_kind('all')
3188+ self.filelist_widget.tree_model.set_select_all_kind('all')
3189 else:
3190- self.filelist.tree_model.set_select_all_kind('versioned')
3191-
3192+ self.filelist_widget.tree_model.set_select_all_kind('versioned')
3193+
3194 self.file_words = {}
3195- self.connect(self.filelist.tree_model,
3196+ self.connect(self.filelist_widget.tree_model,
3197 QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"),
3198 self.on_filelist_data_changed)
3199-
3200- self.selectall_checkbox = SelectAllCheckBox(self.filelist, self)
3201+
3202+ self.selectall_checkbox = SelectAllCheckBox(self.filelist_widget, self)
3203 self.selectall_checkbox.setCheckState(QtCore.Qt.Checked)
3204
3205 language = get_global_config().get_user_option('spellcheck_language') or 'en'
3206 spell_checker = SpellChecker(language)
3207-
3208+
3209 # Equivalent for 'bzr commit --message'
3210 self.message = TextEdit(spell_checker, message_groupbox, main_window=self)
3211 self.message.setToolTip(gettext("Enter the commit message"))
3212@@ -393,10 +403,10 @@
3213 self.tabWidget.addTab(files_tab, gettext("Changes"))
3214
3215 vbox = QtGui.QVBoxLayout(files_tab)
3216- vbox.addWidget(self.filelist)
3217+ vbox.addWidget(self.filelist_widget)
3218 self.connect(self.show_nonversioned_checkbox, QtCore.SIGNAL("toggled(bool)"), self.show_nonversioned)
3219 vbox.addWidget(self.show_nonversioned_checkbox)
3220-
3221+
3222 vbox.addWidget(self.selectall_checkbox)
3223
3224 # Display a list of pending merges
3225@@ -405,11 +415,11 @@
3226 self.selectall_checkbox.setEnabled(False)
3227 self.pending_merges_list = PendingMergesList(
3228 self.processEvents, self.throbber, self)
3229-
3230+
3231 self.tabWidget.addTab(self.pending_merges_list,
3232 gettext("Pending Merges"))
3233 self.tabWidget.setCurrentWidget(self.pending_merges_list)
3234-
3235+
3236 # Pending-merge widget gets disabled as we are executing.
3237 QtCore.QObject.connect(self,
3238 QtCore.SIGNAL("disableUi(bool)"),
3239@@ -460,7 +470,7 @@
3240
3241 # Try to be smart: if there is no saved message
3242 # then set focus on Edit Area; otherwise on OK button.
3243- if unicode(self.message.toPlainText()).strip():
3244+ if str(self.message.toPlainText()).strip():
3245 self.buttonbox.setFocus()
3246 else:
3247 self.message.setFocus()
3248@@ -490,15 +500,15 @@
3249 # loading the file list.
3250 self.pending_merges_list._load_visible_revisions()
3251 self.processEvents()
3252-
3253- self.filelist.tree_model.checkable = not self.pending_merges_list
3254+
3255+ self.filelist_widget.tree_model.checkable = not self.pending_merges_list
3256 self.is_loading = True
3257 # XXX Would be nice if we could only load the files when the
3258 # user clicks on the changes tab, but that would mean that
3259 # we can't load the words list.
3260 if not refresh:
3261- fmodel = self.filelist.tree_filter_model
3262-
3263+ fmodel = self.filelist_widget.tree_filter_model
3264+
3265 want_unversioned = self.show_nonversioned_checkbox.isChecked()
3266 fmodel.setFilter(fmodel.UNVERSIONED, want_unversioned)
3267 if not want_unversioned and self.initial_selected_list:
3268@@ -508,8 +518,8 @@
3269 if not self.tree.path2id(path):
3270 want_unversioned = True
3271 break
3272-
3273- self.filelist.set_tree(
3274+
3275+ self.filelist_widget.set_tree(
3276 self.tree,
3277 branch=self.tree.branch,
3278 changes_mode=True,
3279@@ -517,7 +527,7 @@
3280 initial_checked_paths=self.initial_selected_list,
3281 change_load_filter=lambda c:not c.is_ignored())
3282 else:
3283- self.filelist.refresh()
3284+ self.filelist_widget.refresh()
3285 self.is_loading = False
3286 self.processEvents()
3287 self.update_compleater_words()
3288@@ -526,28 +536,28 @@
3289 finally:
3290 self.throbber.hide()
3291 self.refresh_button.setDisabled(False)
3292-
3293+
3294 def refresh(self):
3295 self.load(True)
3296
3297 def on_filelist_data_changed(self, start_index, end_index):
3298 self.update_compleater_words()
3299-
3300+
3301 def update_compleater_words(self):
3302 if self.is_loading:
3303 return
3304-
3305+
3306 num_files_loaded = 0
3307-
3308+
3309 words = set()
3310- for ref in self.filelist.tree_model.iter_checked():
3311+ for ref in self.filelist_widget.tree_model.iter_checked():
3312 path = ref.path
3313 if path not in self.file_words:
3314 file_words = set()
3315 if num_files_loaded < MAX_AUTOCOMPLETE_FILES:
3316 file_words.add(path)
3317 file_words.add(os.path.split(path)[-1])
3318- change = self.filelist.tree_model.inventory_data_by_path[
3319+ change = self.filelist_widget.tree_model.inventory_data_by_path[
3320 ref.path].change
3321 if change and change.is_renamed():
3322 file_words.add(change.oldpath())
3323@@ -571,7 +581,7 @@
3324 words = list(words)
3325 words.sort(key=lambda x: x.lower())
3326 self.completer_model.setStringList(words)
3327-
3328+
3329 def enableBugs(self, state):
3330 if state == QtCore.Qt.Checked:
3331 self.bugs.setEnabled(True)
3332@@ -608,12 +618,12 @@
3333 return
3334 # collect data
3335 ci_data = QBzrCommitData(tree=self.tree)
3336- message = unicode(self.message.toPlainText()).strip()
3337+ message = str(self.message.toPlainText()).strip()
3338 if message:
3339 ci_data['message'] = message
3340 bug_str = ''
3341 if self.bugsCheckBox.isChecked():
3342- bug_str = unicode(self.bugs.text()).strip()
3343+ bug_str = str(self.bugs.text()).strip()
3344 if bug_str:
3345 ci_data['bugs'] = bug_str
3346 # save only if data different
3347@@ -630,7 +640,7 @@
3348 self.ci_data.wipe()
3349
3350 def _get_message(self):
3351- return unicode(self.message.toPlainText()).strip()
3352+ return str(self.message.toPlainText()).strip()
3353
3354 def _get_selected_files(self):
3355 """Return (has_files_to_commit[bool], files_to_commit[list], files_to_add[list])"""
3356@@ -639,7 +649,7 @@
3357
3358 files_to_commit = []
3359 files_to_add = []
3360- for ref in self.filelist.tree_model.iter_checked():
3361+ for ref in self.filelist_widget.tree_model.iter_checked():
3362 if ref.file_id is None:
3363 files_to_add.append(ref.path)
3364 files_to_commit.append(ref.path)
3365@@ -679,15 +689,15 @@
3366 args.extend(files_to_commit)
3367
3368 if self.bugsCheckBox.isChecked():
3369- for s in unicode(self.bugs.text()).split():
3370+ for s in str(self.bugs.text()).split():
3371 args.append(("--fixes=%s" % s))
3372-
3373+
3374 if self.authorCheckBox.isChecked():
3375- args.append(("--author=%s" % unicode(self.author.text())))
3376-
3377+ args.append(("--author=%s" % str(self.author.text())))
3378+
3379 if self.is_bound and self.local_checkbox.isChecked():
3380 args.append("--local")
3381-
3382+
3383 dir = self.tree.basedir
3384 commands = []
3385 if files_to_add:
3386@@ -699,19 +709,19 @@
3387
3388 def show_nonversioned(self, state):
3389 """Show/hide non-versioned files."""
3390- if state and not self.filelist.want_unversioned:
3391- state = self.filelist.get_state()
3392- self.filelist.set_tree(
3393+ if state and not self.filelist_widget.want_unversioned:
3394+ state = self.filelist_widget.get_state()
3395+ self.filelist_widget.set_tree(
3396 self.tree, changes_mode=True, want_unversioned=True,
3397 change_load_filter=lambda c:not c.is_ignored())
3398- self.filelist.restore_state(state)
3399-
3400+ self.filelist_widget.restore_state(state)
3401+
3402 if state:
3403- self.filelist.tree_model.set_select_all_kind('all')
3404+ self.filelist_widget.tree_model.set_select_all_kind('all')
3405 else:
3406- self.filelist.tree_model.set_select_all_kind('versioned')
3407-
3408- fmodel = self.filelist.tree_filter_model
3409+ self.filelist_widget.tree_model.set_select_all_kind('versioned')
3410+
3411+ fmodel = self.filelist_widget.tree_filter_model
3412 fmodel.setFilter(fmodel.UNVERSIONED, state)
3413
3414 def _save_or_wipe_commit_data(self):
3415@@ -756,47 +766,43 @@
3416 @param dialog_action: purpose of parent window (main action)
3417 """
3418 # XXX make this function universal for both qcommit and qrevert (?)
3419- if self.filelist.tree_model.checkable:
3420+ if self.filelist_widget.tree_model.checkable:
3421 checked = [] # checked versioned
3422 unversioned = [] # checked unversioned (supposed to be added)
3423- for ref in self.filelist.tree_model.iter_checked():
3424+ for ref in self.filelist_widget.tree_model.iter_checked():
3425 if ref.file_id:
3426 checked.append(ref.path)
3427 else:
3428 unversioned.append(ref.path)
3429-
3430+
3431 if checked:
3432 arg_provider = InternalWTDiffArgProvider(
3433 self.tree.basis_tree().get_revision_id(), self.tree,
3434 self.tree.branch, self.tree.branch,
3435 specific_files=checked)
3436-
3437- show_diff(arg_provider, ext_diff=ext_diff, parent_window=self,
3438- context=self.filelist.diff_context)
3439+
3440+ show_diff(arg_provider, ext_diff=ext_diff, parent_window=self, context=self.filelist_widget.diff_context)
3441 else:
3442 msg = "No changes selected to " + dialog_action
3443- QtGui.QMessageBox.warning(self,
3444- "QBzr - " + gettext("Diff"),
3445- gettext(msg),
3446- QtGui.QMessageBox.Ok)
3447-
3448+ QtGui.QMessageBox.warning(self, "QBrz - " + gettext("Diff"), gettext(msg), QtGui.QMessageBox.Ok)
3449+
3450 if unversioned:
3451 # XXX show infobox with message that not all files shown in diff
3452 pass
3453 else:
3454 arg_provider = InternalWTDiffArgProvider(
3455 self.tree.basis_tree().get_revision_id(), self.tree,
3456- self.tree.branch, self.tree.branch)
3457+ self.tree.branch, self.tree.branch)
3458 show_diff(arg_provider, ext_diff=ext_diff, parent_window=self,
3459- context=self.filelist.diff_context)
3460-
3461+ context=self.filelist_widget.diff_context)
3462+
3463 def on_failed(self, error):
3464 SubProcessDialog.on_failed(self, error)
3465 error = str(error)
3466 if error in self.not_uptodate_errors:
3467 self.not_uptodate_label.setText(self.not_uptodate_errors[error])
3468 self.not_uptodate_info.show()
3469-
3470+
3471 def open_update_win(self, b):
3472 update_window = QBzrUpdateWindow(self.tree)
3473 self.windows.append(update_window)
3474@@ -804,4 +810,4 @@
3475 QtCore.QObject.connect(update_window,
3476 QtCore.SIGNAL("subprocessFinished(bool)"),
3477 self.not_uptodate_info,
3478- QtCore.SLOT("setHidden(bool)"))
3479+ QtCore.SLOT("setHidden(bool)"))
3480
3481=== modified file 'lib/commit_data.py'
3482--- lib/commit_data.py 2017-09-11 06:53:22 +0000
3483+++ lib/commit_data.py 2020-07-16 14:28:25 +0000
3484@@ -64,12 +64,12 @@
3485 string or None).
3486 """
3487 d = {}
3488- for k,v in self._data.iteritems():
3489+ for k,v in self._data.items():
3490 if v not in (None, ''):
3491 d[k] = v
3492 return d
3493
3494- def __nonzero__(self):
3495+ def __bool__(self):
3496 """Check if there is some data actually.
3497 @return: True if data dictionary is not empty.
3498 """
3499@@ -92,7 +92,7 @@
3500
3501 def keys(self):
3502 """Return keys of internal dict."""
3503- return self._data.keys()
3504+ return list(self._data.keys())
3505
3506 def as_dict(self):
3507 return self._data.copy()
3508@@ -104,7 +104,7 @@
3509 """
3510 if data:
3511 self._data.update(data)
3512- for key, value in kw.iteritems():
3513+ for key, value in kw.items():
3514 self._data[key] = value
3515
3516 def set_data_on_uncommit(self, old_revid, new_revid):
3517@@ -137,7 +137,7 @@
3518 instance.
3519 """
3520 try:
3521- for k,v in self._data.iteritems():
3522+ for k,v in self._data.items():
3523 if v != other[k]:
3524 return False
3525 except KeyError:
3526
3527=== modified file 'lib/conditional_dataview.py'
3528--- lib/conditional_dataview.py 2009-08-18 14:27:46 +0000
3529+++ lib/conditional_dataview.py 2020-07-16 14:28:25 +0000
3530@@ -16,7 +16,7 @@
3531
3532
3533 from PyQt4 import QtGui
3534-from PyQt4.QtCore import Qt, QVariant
3535+from PyQt4.QtCore import Qt
3536
3537
3538 class QBzrConditionalDataView(QtGui.QFrame):
3539@@ -113,11 +113,11 @@
3540 icon = decoration_provider(row, record)
3541 if icon:
3542 index = model.index(row, 0)
3543- model.setData(index, QVariant(icon), Qt.DecorationRole)
3544+ model.setData(index, icon, Qt.DecorationRole)
3545 for col, value in enumerate(record):
3546 #print "putting %s into %d,%d" % (value, row, col)
3547 index = model.index(row, col)
3548- model.setData(index, QVariant(value or ''), cell_role)
3549+ model.setData(index, value or '', cell_role)
3550
3551 # Update the view & label
3552 self._view.setVisible(row_count > 0)
3553
3554=== modified file 'lib/config.py'
3555--- lib/config.py 2017-09-11 06:53:22 +0000
3556+++ lib/config.py 2020-07-16 14:28:25 +0000
3557@@ -20,10 +20,8 @@
3558 import re
3559 import os.path
3560 from PyQt4 import QtCore, QtGui
3561-from breezy.config import (
3562- ensure_config_dir_exists,
3563- extract_email_address,
3564- )
3565+from breezy.config import extract_email_address
3566+from breezy.bedding import ensure_config_dir_exists
3567 from breezy import cmdline, errors, trace
3568
3569 from breezy.plugins.qbrz.lib import ui_merge_config
3570@@ -59,18 +57,17 @@
3571 # XXX use special function from bugs.py instead
3572 _bug_tracker_re = re.compile('bugtracker_(.+?)_url')
3573
3574+
3575 class QRadioCheckItemDelegate(QtGui.QItemDelegate):
3576-
3577- def drawCheck (self, painter, option, rect, state):
3578+
3579+ def drawCheck(self, painter, option, rect, state):
3580 style = self.parent().style()
3581 radioOption = QtGui.QStyleOptionButton()
3582 radioOption.rect = option.rect
3583 radioOption.state = option.state
3584 if state:
3585 radioOption.state = radioOption.state | QtGui.QStyle.State_On
3586- style.drawControl(QtGui.QStyle.CE_RadioButton,
3587- radioOption,
3588- painter)
3589+ style.drawControl(QtGui.QStyle.CE_RadioButton, radioOption, painter)
3590
3591
3592 class QBzrConfigWindow(QBzrDialog):
3593@@ -112,7 +109,7 @@
3594
3595 self.emailClientCombo = QtGui.QComboBox()
3596 for name, label in _mail_clients:
3597- self.emailClientCombo.addItem(gettext(label), QtCore.QVariant(name))
3598+ self.emailClientCombo.addItem(gettext(label), name)
3599 label = QtGui.QLabel(gettext("E-mail &client:"))
3600 label.setBuddy(self.emailClientCombo)
3601 generalGrid.addWidget(label, 3, 0)
3602@@ -173,11 +170,11 @@
3603 bugTrackersVBox = QtGui.QVBoxLayout(bugTrackersWidget)
3604 bugTrackersVBox.addWidget(self.bugTrackersList)
3605 bugTrackersVBox.addLayout(bugTrackersHBox)
3606-
3607+
3608 diffWidget = QtGui.QWidget()
3609
3610 self.diffShowIntergroupColors = QtGui.QCheckBox(gettext("Show inter-group inserts and deletes in green and red"), diffWidget)
3611-
3612+
3613 label = QtGui.QLabel(gettext("External Diff Apps:"))
3614 self.extDiffList = QtGui.QTreeWidget(diffWidget)
3615 self.extDiffList.setRootIsDecorated(False)
3616@@ -186,7 +183,7 @@
3617 self.extDiffList.setItemDelegateForColumn(0,
3618 QRadioCheckItemDelegate(self.extDiffList))
3619 self.connect(self.extDiffList, QtCore.SIGNAL("itemChanged (QTreeWidgetItem *,int)"),
3620- self.extDiffListItemChanged)
3621+ self.extDiffListItemChanged)
3622
3623 addExtDiffButton = QtGui.QPushButton(gettext("Add"), diffWidget)
3624 self.connect(addExtDiffButton, QtCore.SIGNAL("clicked()"),
3625@@ -205,7 +202,7 @@
3626 diffLayout.addWidget(label)
3627 diffLayout.addWidget(self.extDiffList)
3628 diffLayout.addLayout(extDiffButtonsLayout)
3629-
3630+
3631 if mergetools is not None:
3632 mergeWidget = QtGui.QWidget()
3633 self.merge_ui = ui_merge_config.Ui_MergeConfig()
3634@@ -213,18 +210,18 @@
3635 self.merge_ui.tools.sortByColumn(0, QtCore.Qt.AscendingOrder)
3636 self.merge_ui.remove.setEnabled(False)
3637 self.merge_ui.set_default.setEnabled(False)
3638-
3639+
3640 self.merge_tools_model = MergeToolsTableModel()
3641 self.merge_ui.tools.setModel(self.merge_tools_model)
3642-
3643+
3644 self.connect(self.merge_tools_model,
3645 QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
3646 self.merge_tools_data_changed)
3647-
3648+
3649 self.connect(self.merge_ui.tools.selectionModel(),
3650 QtCore.SIGNAL("selectionChanged(QItemSelection,QItemSelection)"),
3651 self.merge_tools_selectionChanged)
3652-
3653+
3654 self.connect(self.merge_ui.add,
3655 QtCore.SIGNAL("clicked()"),
3656 self.merge_tools_add_clicked)
3657@@ -237,7 +234,7 @@
3658 else:
3659 mergeWidget = QtGui.QLabel(gettext("Bazaar 2.4 or newer is required to configure mergetools."))
3660 mergeWidget.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
3661-
3662+
3663 self.tabwidget.addTab(generalWidget, gettext("General"))
3664 self.tabwidget.addTab(aliasesWidget, gettext("Aliases"))
3665 self.tabwidget.addTab(bugTrackersWidget, gettext("Bug Trackers"))
3666@@ -265,7 +262,7 @@
3667 self.spellcheck_language_combo = QtGui.QComboBox()
3668 languages = sorted(SpellChecker.list_languages())
3669 for name in languages:
3670- self.spellcheck_language_combo.addItem(gettext(name), QtCore.QVariant(name))
3671+ self.spellcheck_language_combo.addItem(gettext(name), name)
3672 if not languages:
3673 self.spellcheck_language_combo.setEnabled(False)
3674 label = QtGui.QLabel(gettext("Spell check &language:"))
3675@@ -287,7 +284,7 @@
3676 label.setBuddy(self.branchsourceBasedirEdit)
3677 grid.addWidget(label, 1, 0)
3678 grid.addLayout(branchsourceBasedirHBox, 1, 1)
3679-
3680+
3681 self.checkoutBasedirEdit = QtGui.QLineEdit()
3682 self.checkoutBasedirEdit.setToolTip(gettext("This directory will be automatically filled in your checkout destination input field"))
3683 btnCheckoutBasedirBrowse = QtGui.QPushButton(gettext('Browse...'))
3684@@ -308,7 +305,7 @@
3685 """Load the configuration."""
3686 config = get_global_config()
3687 parser = config._get_parser()
3688-
3689+
3690 qconfig = get_qbrz_config()
3691
3692 # Name & e-mail
3693@@ -322,10 +319,10 @@
3694 email = ''
3695 except errors.NoWhoami:
3696 name, email = get_user_id_from_os()
3697- except Exception, e:
3698+ except Exception as e:
3699 trace.mutter("qconfig: load name/email error: %s", str(e))
3700 name, email = '', ''
3701-
3702+
3703 self.nameEdit.setText(name)
3704 self.emailEdit.setText(email)
3705
3706@@ -337,8 +334,7 @@
3707 # E-mail client
3708 mailClient = config.get_user_option('mail_client')
3709 if mailClient:
3710- index = self.emailClientCombo.findData(
3711- QtCore.QVariant(mailClient))
3712+ index = self.emailClientCombo.findData(mailClient)
3713 if index >= 0:
3714 self.emailClientCombo.setCurrentIndex(index)
3715
3716@@ -348,8 +344,7 @@
3717 # Spellcheck language
3718 spellcheck_language = config.get_user_option('spellcheck_language') or 'en'
3719 if spellcheck_language:
3720- index = self.spellcheck_language_combo.findData(
3721- QtCore.QVariant(spellcheck_language))
3722+ index = self.spellcheck_language_combo.findData(spellcheck_language)
3723 if index >= 0:
3724 self.spellcheck_language_combo.setCurrentIndex(index)
3725
3726@@ -365,7 +360,7 @@
3727
3728 # Aliases
3729 aliases = parser.get('ALIASES', {})
3730- for alias, command in aliases.items():
3731+ for alias, command in list(aliases.items()):
3732 item = QtGui.QTreeWidgetItem(self.aliasesList)
3733 item.setFlags(QtCore.Qt.ItemIsSelectable |
3734 QtCore.Qt.ItemIsEditable |
3735@@ -375,7 +370,7 @@
3736
3737 # Bug trackers
3738 # XXX use special function from bugs.py
3739- for name, value in parser.get('DEFAULT', {}).items():
3740+ for name, value in list(parser.get('DEFAULT', {}).items()):
3741 m = _bug_tracker_re.match(name)
3742 if not m:
3743 continue
3744@@ -386,7 +381,7 @@
3745 QtCore.Qt.ItemIsEnabled)
3746 item.setText(0, abbreviation)
3747 item.setText(1, value)
3748-
3749+
3750 # Diff
3751 self.diffShowIntergroupColors.setChecked(qconfig.get_option("diff_show_intergroup_colors") in ("True", "1"))
3752 defaultDiff = qconfig.get_option("default_diff")
3753@@ -404,31 +399,32 @@
3754 item.setCheckState(0, QtCore.Qt.Checked)
3755 else:
3756 item.setCheckState(0, QtCore.Qt.Unchecked)
3757-
3758+
3759 item.setText(0, name)
3760 item.setText(1, command)
3761 return item
3762-
3763+
3764 builtin = create_ext_diff_item(gettext("Builtin Diff"),"")
3765 builtin.setFlags(QtCore.Qt.ItemIsSelectable |
3766 QtCore.Qt.ItemIsEnabled |
3767- QtCore.Qt.ItemIsUserCheckable)
3768-
3769+ QtCore.Qt.ItemIsUserCheckable)
3770+
3771 extDiffs = qconfig.get_section('EXTDIFF')
3772- for name, command in extDiffs.items():
3773+ for name, command in list(extDiffs.items()):
3774 create_ext_diff_item(name, command)
3775 self.extDiffListIgnore = False
3776
3777 # Merge
3778 if mergetools is not None:
3779 user_merge_tools = config.get_merge_tools()
3780+ # RJLRJL: check this - might need to be 'brz.default_mergetool'
3781 default_merge_tool = config.get_user_option('bzr.default_mergetool')
3782 if len(user_merge_tools) == 0:
3783 self.import_external_merge(user_merge_tools, config, qconfig)
3784 self.merge_tools_model.set_merge_tools(user_merge_tools,
3785 mergetools.known_merge_tools, default_merge_tool)
3786 self.merge_tools_model.sort(0, QtCore.Qt.AscendingOrder)
3787-
3788+
3789 def import_external_merge(self, user_merge_tools, config, qconfig):
3790 # don't ask to import if we already asked before
3791 if qconfig.get_option_as_bool('imported_external_merge'):
3792@@ -453,7 +449,7 @@
3793 user_merge_tools[name] = new_cmdline
3794 # set a flag to indicate that we've already asked about this
3795 qconfig.set_option('imported_external_merge', True)
3796-
3797+
3798 def convert_external_merge(self, external_merge):
3799 args = cmdline.split(external_merge)
3800 # %b %t %o -o %r
3801@@ -483,9 +479,9 @@
3802 pass
3803
3804 # Name & e-mail
3805- _name = unicode(self.nameEdit.text()).strip()
3806- _email = unicode(self.emailEdit.text()).strip()
3807- username = u''
3808+ _name = str(self.nameEdit.text()).strip()
3809+ _email = str(self.emailEdit.text()).strip()
3810+ username = ''
3811 if _name:
3812 username = _name
3813 if _email:
3814@@ -493,12 +489,12 @@
3815 set_or_delete_option(parser, 'email', username)
3816
3817 # Editor
3818- editor = unicode(self.editorEdit.text())
3819+ editor = str(self.editorEdit.text())
3820 set_or_delete_option(parser, 'editor', editor)
3821
3822 # E-mail client
3823 index = self.emailClientCombo.currentIndex()
3824- mail_client = unicode(self.emailClientCombo.itemData(index).toString())
3825+ mail_client = self.emailClientCombo.itemData(index)
3826 set_or_delete_option(parser, 'mail_client', mail_client)
3827
3828 tabWidth = self.tabWidthSpinner.value()
3829@@ -506,36 +502,36 @@
3830
3831 # Spellcheck language
3832 index = self.spellcheck_language_combo.currentIndex()
3833- spellcheck_language = unicode(self.spellcheck_language_combo.itemData(index).toString())
3834+ spellcheck_language = self.spellcheck_language_combo.itemData(index)
3835 set_or_delete_option(parser, 'spellcheck_language', spellcheck_language)
3836
3837 # Branch source basedir
3838- branchsource_basedir = unicode(self.branchsourceBasedirEdit.text())
3839+ branchsource_basedir = str(self.branchsourceBasedirEdit.text())
3840 qconfig.set_option('branchsource_basedir', branchsource_basedir)
3841
3842 # Checkout basedir
3843- checkout_basedir = unicode(self.checkoutBasedirEdit.text())
3844+ checkout_basedir = str(self.checkoutBasedirEdit.text())
3845 qconfig.set_option('checkout_basedir', checkout_basedir)
3846
3847 # Aliases
3848 parser['ALIASES'] = {}
3849 for index in range(self.aliasesList.topLevelItemCount()):
3850 item = self.aliasesList.topLevelItem(index)
3851- alias = unicode(item.text(0))
3852- command = unicode(item.text(1))
3853+ alias = str(item.text(0))
3854+ command = str(item.text(1))
3855 if alias and command:
3856 parser['ALIASES'][alias] = command
3857
3858 # Bug trackers
3859- for name, value in parser.get('DEFAULT', {}).items():
3860+ for name, value in list(parser.get('DEFAULT', {}).items()):
3861 m = _bug_tracker_re.match(name)
3862 if m:
3863 abbrev = m.group(1)
3864 del parser['DEFAULT']['bugtracker_%s_url' % abbrev]
3865 for index in range(self.bugTrackersList.topLevelItemCount()):
3866 item = self.bugTrackersList.topLevelItem(index)
3867- abbrev = unicode(item.text(0))
3868- url = unicode(item.text(1))
3869+ abbrev = str(item.text(0))
3870+ url = str(item.text(1))
3871 # FIXME add URL validation (must contain {id})
3872 if abbrev and url:
3873 parser['DEFAULT']['bugtracker_%s_url' % abbrev] = url
3874@@ -543,13 +539,13 @@
3875 # Diff
3876 qconfig.set_option('diff_show_intergroup_colors',
3877 self.diffShowIntergroupColors.isChecked())
3878-
3879+
3880 defaultDiff = None
3881 ext_diffs = {}
3882 for index in range(1, self.extDiffList.topLevelItemCount()):
3883 item = self.extDiffList.topLevelItem(index)
3884- name = unicode(item.text(0))
3885- command = unicode(item.text(1))
3886+ name = str(item.text(0))
3887+ command = str(item.text(1))
3888 if item.checkState(0) == QtCore.Qt.Checked:
3889 defaultDiff = command
3890 if name and command:
3891@@ -557,8 +553,8 @@
3892 qconfig.set_section('EXTDIFF', ext_diffs)
3893 qconfig.set_option('default_diff',
3894 defaultDiff)
3895-
3896-
3897+
3898+
3899 if hasattr(config, 'file_name'):
3900 file_name = config.file_name
3901 else:
3902@@ -567,7 +563,7 @@
3903 f = open(file_name, 'wb')
3904 parser.write(f)
3905 f.close()
3906-
3907+
3908 qconfig.save()
3909
3910 # Merge
3911@@ -577,7 +573,7 @@
3912 if config.get_user_option(option, expand=False) is not None:
3913 config.remove_user_option(option)
3914 user_merge_tools = self.merge_tools_model.get_user_merge_tools()
3915- for name, cmdline in user_merge_tools.iteritems():
3916+ for name, cmdline in user_merge_tools.items():
3917 orig_cmdline = config.find_merge_tool(name)
3918 if orig_cmdline is None or orig_cmdline != cmdline:
3919 config.set_user_option('bzr.mergetool.%s' % name, cmdline)
3920@@ -600,8 +596,8 @@
3921 """Check the inputs and return False if there is something wrong
3922 and save should be prohibited."""
3923 # check whoami
3924- _name = unicode(self.nameEdit.text()).strip()
3925- _email = unicode(self.emailEdit.text()).strip()
3926+ _name = str(self.nameEdit.text()).strip()
3927+ _email = str(self.emailEdit.text()).strip()
3928 if (_name, _email) == ('', ''):
3929 if QtGui.QMessageBox.warning(self, "Configuration",
3930 "Name and E-mail settings should not be empty",
3931@@ -656,7 +652,7 @@
3932 index = self.extDiffList.indexOfTopLevelItem(item)
3933 if index >= 1: # You can't remove the builtin diff
3934 self.extDiffList.takeTopLevelItem(index)
3935-
3936+
3937 def extDiffListItemChanged(self, changed_item, col):
3938 if col == 0 and not self.extDiffListIgnore:
3939 checked_count = 0
3940@@ -664,7 +660,7 @@
3941 item = self.extDiffList.topLevelItem(index)
3942 if item.checkState(0) == QtCore.Qt.Checked:
3943 checked_count += 1
3944-
3945+
3946 if checked_count == 0:
3947 self.extDiffListIgnore = True
3948 changed_item.setCheckState(0, QtCore.Qt.Checked)
3949@@ -677,24 +673,24 @@
3950 item.setCheckState(0, QtCore.Qt.Unchecked)
3951 changed_item.setCheckState(0, QtCore.Qt.Checked)
3952 self.extDiffListIgnore = False
3953-
3954+
3955 def get_selected_merge_tool(self):
3956 sel_model = self.merge_ui.tools.selectionModel()
3957 if len(sel_model.selectedRows()) == 0:
3958 return None
3959 row = sel_model.selectedRows()[0].row()
3960 return self.merge_tools_model.get_merge_tool_name(row)
3961-
3962+
3963 def update_buttons(self):
3964 selected = self.get_selected_merge_tool()
3965 self.merge_ui.remove.setEnabled(selected is not None and
3966 self.merge_tools_model.is_user_merge_tool(selected))
3967 self.merge_ui.set_default.setEnabled(selected is not None and
3968 self.merge_tools_model.get_default() != selected)
3969-
3970+
3971 def merge_tools_data_changed(self, top_left, bottom_right):
3972 self.update_buttons()
3973-
3974+
3975 def merge_tools_selectionChanged(self, selected, deselected):
3976 self.update_buttons()
3977
3978@@ -703,31 +699,31 @@
3979 sel_model = self.merge_ui.tools.selectionModel()
3980 sel_model.select(index, QtGui.QItemSelectionModel.ClearAndSelect)
3981 self.merge_ui.tools.edit(index)
3982-
3983+
3984 def merge_tools_remove_clicked(self):
3985 sel_model = self.merge_ui.tools.selectionModel()
3986 assert len(sel_model.selectedRows()) > 0
3987 for index in sel_model.selectedRows():
3988 self.merge_tools_model.remove_merge_tool(index.row())
3989-
3990+
3991 def merge_tools_set_default_clicked(self):
3992 sel_model = self.merge_ui.tools.selectionModel()
3993 self.merge_tools_model.set_default(self.get_selected_merge_tool())
3994-
3995+
3996 def browseEditor(self):
3997 filename = QtGui.QFileDialog.getOpenFileName(self,
3998 gettext('Select editor executable'),
3999 '/')
4000 if filename:
4001 self.editorEdit.setText(filename)
4002-
4003+
4004 def browseCheckoutBasedir(self):
4005 filename = QtGui.QFileDialog.getExistingDirectory(self,
4006 gettext('Select base directory for checkouts'),
4007 '/')
4008 if filename:
4009 self.checkoutBasedirEdit.setText(filename)
4010-
4011+
4012 def browseBranchsourceBasedir(self):
4013 filename = QtGui.QFileDialog.getExistingDirectory(self,
4014 gettext('Select default directory for branch sources'),
4015@@ -747,10 +743,10 @@
4016 be very slow on machines where DNS is broken. So now we simply
4017 use the hostname.
4018 """
4019-
4020+
4021 # This use to live in breezy.config._auto_user_id, but got removed, so
4022 # we have a copy.
4023-
4024+
4025 import sys
4026 if sys.platform == 'win32':
4027 from breezy import win32utils
4028@@ -758,7 +754,7 @@
4029 if name is None:
4030 raise errors.BzrError("Cannot autodetect user name.\n"
4031 "Please, set your name with command like:\n"
4032- 'bzr whoami "Your Name <name@domain.com>"')
4033+ 'brz whoami "Your Name <name@domain.com>"')
4034 host = win32utils.get_host_name_unicode()
4035 if host is None:
4036 host = socket.gethostname()
4037@@ -770,8 +766,7 @@
4038 try:
4039 w = pwd.getpwuid(uid)
4040 except KeyError:
4041- raise errors.BzrCommandError('Unable to determine your name. '
4042- 'Please use "bzr whoami" to set it.')
4043+ raise errors.BzrCommandError('Unable to determine your name. Please use "brz whoami" to set it.')
4044
4045 # we try utf-8 first, because on many variants (like Linux),
4046 # /etc/passwd "should" be in utf-8, and because it's unlikely to give
4047@@ -785,13 +780,11 @@
4048 encoding = osutils.get_user_encoding()
4049 gecos = w.pw_gecos.decode(encoding)
4050 except UnicodeError:
4051- raise errors.BzrCommandError('Unable to determine your name. '
4052- 'Use "bzr whoami" to set it.')
4053+ raise errors.BzrCommandError('Unable to determine your name. Use brz whoami" to set it.')
4054 try:
4055 username = w.pw_name.decode(encoding)
4056 except UnicodeError:
4057- raise errors.BzrCommandError('Unable to determine your name. '
4058- 'Use "bzr whoami" to set it.')
4059+ raise errors.BzrCommandError('Unable to determine your name. Use "brz whoami" to set it.')
4060
4061 comma = gecos.find(',')
4062 if comma == -1:
4063@@ -807,8 +800,7 @@
4064 user_encoding = osutils.get_user_encoding()
4065 realname = username = getpass.getuser().decode(user_encoding)
4066 except UnicodeDecodeError:
4067- raise errors.BzrError("Can't decode username as %s." % \
4068- user_encoding)
4069+ raise errors.BzrError("Can't decode username as %s." % user_encoding)
4070
4071 import socket
4072 return realname, (username + '@' + socket.gethostname())
4073@@ -818,7 +810,7 @@
4074 COL_NAME = 0
4075 COL_COMMANDLINE = 1
4076 COL_COUNT = 2
4077-
4078+
4079 def __init__(self):
4080 super(MergeToolsTableModel, self).__init__()
4081 self._order = []
4082@@ -826,21 +818,21 @@
4083 self._known = {}
4084 self._default = None
4085 self._removed = []
4086-
4087+
4088 def get_user_merge_tools(self):
4089 return self._user
4090-
4091+
4092 def set_merge_tools(self, user, known, default):
4093 self.beginResetModel()
4094 self._user = user
4095 self._known = known
4096- self._order = user.keys() + known.keys()
4097+ self._order = list(user.keys()) + list(known.keys())
4098 self._default = default
4099 self.endResetModel()
4100
4101 def get_default(self):
4102 return self._default
4103-
4104+
4105 def set_default(self, new_default):
4106 old_row = None
4107 if self._default is not None:
4108@@ -859,20 +851,20 @@
4109 self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
4110 self.index(new_row, self.COL_NAME),
4111 self.index(new_row, self.COL_NAME))
4112-
4113+
4114 def get_removed_merge_tools(self):
4115 return self._removed
4116-
4117+
4118 def get_merge_tool_name(self, row):
4119 return self._order[row]
4120-
4121+
4122 def get_merge_tool_command_line(self, row):
4123 name = self._order[row]
4124 return self._user.get(name, self._known.get(name, None))
4125-
4126+
4127 def is_user_merge_tool(self, name):
4128 return name in self._user
4129-
4130+
4131 def new_merge_tool(self):
4132 index = self.createIndex(len(self._order), 0)
4133 self.beginInsertRows(QtCore.QModelIndex(), index.row(), index.row())
4134@@ -880,7 +872,7 @@
4135 self._user[''] = ''
4136 self.endInsertRows()
4137 return index
4138-
4139+
4140 def remove_merge_tool(self, row):
4141 name = self._order[row]
4142 if name not in self._user:
4143@@ -892,26 +884,26 @@
4144 del self._order[row]
4145 del self._user[name]
4146 self.endRemoveRows()
4147-
4148+
4149 def rowCount(self, parent):
4150 return len(self._order)
4151-
4152+
4153 def columnCount(self, parent):
4154 return self.COL_COUNT
4155-
4156+
4157 def data(self, index, role):
4158 name = self._order[index.row()]
4159 cmdline = self.get_merge_tool_command_line(index.row())
4160 if role == QtCore.Qt.DisplayRole:
4161 if index.column() == self.COL_NAME:
4162- return QtCore.QVariant(name)
4163+ return name
4164 elif index.column() == self.COL_COMMANDLINE:
4165- return QtCore.QVariant(cmdline)
4166+ return cmdline
4167 elif role == QtCore.Qt.EditRole:
4168 if index.column() == self.COL_NAME:
4169- return QtCore.QVariant(name)
4170+ return name
4171 elif index.column() == self.COL_COMMANDLINE:
4172- return QtCore.QVariant(cmdline)
4173+ return cmdline
4174 elif role == QtCore.Qt.CheckStateRole:
4175 if index.column() == self.COL_NAME:
4176 return self._default == name and QtCore.Qt.Checked or QtCore.Qt.Unchecked
4177@@ -919,8 +911,8 @@
4178 if name in self._known:
4179 palette = QtGui.QApplication.palette()
4180 return palette.alternateBase()
4181- return QtCore.QVariant()
4182-
4183+ return None
4184+
4185 def setData(self, index, value, role):
4186 name = self._order[index.row()]
4187 if role == QtCore.Qt.EditRole:
4188@@ -932,7 +924,7 @@
4189 self._removed.append(name)
4190 del self._order[index.row()]
4191 del self._user[name]
4192- new_name = unicode(value.toString())
4193+ new_name = str(value)
4194 self._order.insert(index.row(), new_name)
4195 self._user[new_name] = cmdline
4196 if self._default == name:
4197@@ -942,57 +934,60 @@
4198 self.sort(self.COL_NAME, QtCore.Qt.AscendingOrder)
4199 return True
4200 elif index.column() == self.COL_COMMANDLINE:
4201- self._user[name] = unicode(value.toString())
4202+ self._user[name] = str(value)
4203 self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
4204 index, index)
4205 return True
4206 elif role == QtCore.Qt.CheckStateRole:
4207 if index.column() == self.COL_NAME:
4208- if value.toInt() == (QtCore.Qt.Checked, True):
4209+ if int(value) == (QtCore.Qt.Checked, True):
4210 self.set_default(name)
4211- elif (value.toInt() == (QtCore.Qt.Unchecked, True) and
4212- self._default == name):
4213+ elif (int(value) == (QtCore.Qt.Unchecked, True) and self._default == name):
4214 self.set_default(None)
4215+
4216+ # if value.toInt() == (QtCore.Qt.Checked, True):
4217+ # self.set_default(name)
4218+ # elif (value.toInt() == (QtCore.Qt.Unchecked, True) and self._default == name):
4219+ # self.set_default(None)
4220 return False
4221-
4222+
4223 def flags(self, index):
4224- f = super(MergeToolsTableModel, self).flags(index)
4225+ f = super().flags(index)
4226 name = self._order[index.row()]
4227 if name not in self._known:
4228 f = f | QtCore.Qt.ItemIsEditable
4229 if index.column() == self.COL_NAME:
4230 f = f | QtCore.Qt.ItemIsUserCheckable
4231 return f
4232-
4233+
4234 def headerData(self, section, orientation, role):
4235 if orientation == QtCore.Qt.Horizontal:
4236 if section == self.COL_NAME:
4237 if role == QtCore.Qt.DisplayRole:
4238- return QtCore.QVariant(gettext("Name"))
4239+ return gettext("Name")
4240 elif section == self.COL_COMMANDLINE:
4241 if role == QtCore.Qt.DisplayRole:
4242- return QtCore.QVariant(gettext("Command Line"))
4243- return QtCore.QVariant()
4244+ return gettext("Command Line")
4245+ return None
4246
4247 def sort(self, column, sortOrder):
4248 self.emit(QtCore.SIGNAL("layoutAboutToBeChanged()"))
4249- index_map = self._order[:] # copy
4250+ index_map = self._order[:] # copy
4251+
4252 def tool_cmp(a, b):
4253 if column == self.COL_NAME:
4254 return cmp(a, b)
4255 elif column == self.COL_COMMANDLINE:
4256- return cmp(self.get_merge_tool_command_line(a),
4257- self.get_merge_tool_command_line(b))
4258+ return cmp(self.get_merge_tool_command_line(a), self.get_merge_tool_command_line(b))
4259 return 0
4260- self._order.sort(cmp=tool_cmp,
4261- reverse=sortOrder==QtCore.Qt.DescendingOrder)
4262+
4263+ # self._order.sort(cmp=tool_cmp, reverse=sortOrder==QtCore.Qt.DescendingOrder)
4264 for i in range(0, len(index_map)):
4265 index_map[i] = self._order.index(index_map[i])
4266 from_list = []
4267 to_list = []
4268 for col in range(0, self.columnCount(None)):
4269 from_list.extend([self.index(i, col) for i in index_map])
4270- to_list.extend([self.index(i, col)
4271- for i in range(0, len(index_map))])
4272+ to_list.extend([self.index(i, col) for i in range(0, len(index_map))])
4273 self.changePersistentIndexList(from_list, to_list)
4274 self.emit(QtCore.SIGNAL("layoutChanged()"))
4275
4276=== modified file 'lib/conflicts.py'
4277--- lib/conflicts.py 2017-09-11 06:53:22 +0000
4278+++ lib/conflicts.py 2020-07-16 14:28:25 +0000
4279@@ -88,9 +88,9 @@
4280 self.connect(self.merge_tools_combo,
4281 QtCore.SIGNAL("currentIndexChanged(int)"),
4282 self.update_merge_tool_ui)
4283-
4284+
4285 self.merge_tool_error = QtGui.QLabel('', self)
4286-
4287+
4288 self.program_launch_button = QtGui.QPushButton(gettext("&Launch..."), self)
4289 self.program_launch_button.setEnabled(False)
4290 self.connect(
4291@@ -121,15 +121,15 @@
4292 hbox.addWidget(autobutton)
4293 hbox.addWidget(buttonbox)
4294 vbox.addLayout(hbox)
4295- self.initialize_ui()
4296+ self.initialize_ui()
4297
4298 def initialize_ui(self):
4299 config = GlobalConfig()
4300 if mergetools is not None:
4301 # get user-defined merge tools
4302- defined_tools = config.get_merge_tools().keys()
4303+ defined_tools = list(config.get_merge_tools().keys())
4304 # get predefined merge tools
4305- defined_tools += mergetools.known_merge_tools.keys()
4306+ defined_tools += list(mergetools.known_merge_tools.keys())
4307 # sort them nicely
4308 defined_tools.sort()
4309 for merge_tool in defined_tools:
4310@@ -174,8 +174,8 @@
4311 item = QtGui.QTreeWidgetItem()
4312 item.setText(0, conflict.path)
4313 item.setText(1, gettext(conflict.typestring))
4314- item.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(conflict.file_id or '')) # file_id is None for non-versioned items, so we force it to be empty string to avoid Qt error
4315- item.setData(1, QtCore.Qt.UserRole, QtCore.QVariant(conflict.typestring))
4316+ item.setData(0, QtCore.Qt.UserRole, conflict.file_id or '') # file_id is None for non-versioned items, so we force it to be empty string to avoid Qt error
4317+ item.setData(1, QtCore.Qt.UserRole, conflict.typestring)
4318 items.append(item)
4319
4320 if len(items) == 0 and self.conflicts_list.topLevelItemCount() > 0:
4321@@ -213,8 +213,8 @@
4322 if not enabled:
4323 return
4324 config = GlobalConfig()
4325- cmdline = config.find_merge_tool(unicode(self.merge_tools_combo.currentText()))
4326- file_id = str(items[0].data(0, QtCore.Qt.UserRole).toString())
4327+ cmdline = config.find_merge_tool(str(self.merge_tools_combo.currentText()))
4328+ file_id = items[0].data(0, QtCore.Qt.UserRole)
4329 if not file_id:
4330 # bug https://bugs.launchpad.net/qbrz/+bug/655451
4331 return
4332@@ -251,9 +251,9 @@
4333 # XXX why we need to use file_id -> path conversion if we already have filename???
4334 # this conversion fails in the case when user removed file or directory
4335 # which marked as conflicted (e.g. in missing parent conflict case).
4336- #~file_id = str(item.data(0, QtCore.Qt.UserRole).toString())
4337- #~file_names.append(self.wt.id2path(file_id))
4338- file_names.append(unicode(item.text(0)))
4339+ # ~file_id = str(item.data(0, QtCore.Qt.UserRole).toString())
4340+ # ~file_names.append(self.wt.id2path(file_id))
4341+ file_names.append(str(item.text(0)))
4342 resolve(self.wt, file_names, action=action)
4343 self.refresh()
4344
4345@@ -266,10 +266,10 @@
4346 items = self.conflicts_list.selectedItems()
4347 error_msg = ""
4348 enabled = True
4349- if len(items) != 1 or items[0].data(1, QtCore.Qt.UserRole).toString() != "text conflict":
4350+ if len(items) != 1 or items[0].data(1, QtCore.Qt.UserRole) != "text conflict":
4351 enabled = False
4352 config = GlobalConfig()
4353- tool = unicode(self.merge_tools_combo.currentText())
4354+ tool = str(self.merge_tools_combo.currentText())
4355 cmdline = config.find_merge_tool(tool)
4356 if cmdline is None:
4357 error_msg = gettext("Set up external_merge app in qconfig under the Merge tab")
4358
4359=== modified file 'lib/decorators.py'
4360--- lib/decorators.py 2017-09-11 06:53:22 +0000
4361+++ lib/decorators.py 2020-07-16 14:28:25 +0000
4362@@ -29,12 +29,12 @@
4363 def _run(*args, **kwargs):
4364 from breezy.trace import mutter
4365 a = ','.join(repr(i) for i in args)
4366- b = ','.join('%s=%r' % (i,j) for (i,j) in kwargs.iteritems())
4367+ b = ','.join('%s=%r' % (i,j) for (i,j) in kwargs.items())
4368 if a and b:
4369 a = a + ',' + b
4370 else:
4371 a = a or b
4372- func_name = unbound.func_name
4373+ func_name = unbound.__name__
4374 mutter('Called %s(%s)' % (func_name, a))
4375 result = unbound(*args, **kwargs)
4376 mutter('%s returned %r' % (func_name, result))
4377
4378=== modified file 'lib/diff.py'
4379--- lib/diff.py 2018-01-31 22:46:16 +0000
4380+++ lib/diff.py 2020-07-16 14:28:25 +0000
4381@@ -24,9 +24,9 @@
4382 from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes
4383 from breezy.plugins.qbrz.lib.i18n import gettext
4384 from breezy.plugins.qbrz.lib.subprocess import SimpleSubProcessDialog
4385-from breezy.plugins.qbrz.lib.util import (
4386+from breezy.plugins.qbrz.lib.util import (
4387 get_qbrz_config,
4388- is_binary_content,
4389+ content_seems_to_be_binary,
4390 )
4391
4392 from breezy.lazy_import import lazy_import
4393@@ -37,7 +37,7 @@
4394 import sys
4395 import os
4396 import glob
4397-from breezy.patiencediff import PatienceSequenceMatcher as SequenceMatcher
4398+from patiencediff import PatienceSequenceMatcher as SequenceMatcher
4399 from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_
4400 from breezy import trace, osutils, cmdline
4401 from breezy.workingtree import WorkingTree
4402@@ -51,21 +51,21 @@
4403 if default_diff is None:
4404 default_diff = ""
4405 ext_diffs = {gettext("Builtin Diff"):""}
4406-for name, command in qconfig.get_section('EXTDIFF').items():
4407+for name, command in list(qconfig.get_section('EXTDIFF').items()):
4408 ext_diffs[name] = command
4409
4410
4411 def show_diff(arg_provider, ext_diff=None, parent_window=None, context=None):
4412-
4413+
4414 if ext_diff is None:
4415 ext_diff = default_diff
4416-
4417+
4418 if ext_diff == "":
4419-
4420+
4421 # We can't import this globaly becuse it ties to import us,
4422 # which causes and Import Error.
4423 from breezy.plugins.qbrz.lib.diffwindow import DiffWindow
4424-
4425+
4426 window = DiffWindow(arg_provider, parent=parent_window)
4427 window.show()
4428 if parent_window:
4429@@ -112,24 +112,24 @@
4430
4431
4432 class ExtDiffMenu(QtGui.QMenu):
4433-
4434+
4435 def __init__ (self, parent=None, include_builtin=True, set_default=True):
4436 QtGui.QMenu.__init__(self, gettext("Show &differences"), parent)
4437-
4438- for name, command in ext_diffs.items():
4439+
4440+ for name, command in list(ext_diffs.items()):
4441 if command == "" and include_builtin or not command == "":
4442 action = QtGui.QAction(name, self)
4443- action.setData(QtCore.QVariant (command))
4444+ action.setData(command)
4445 if command == default_diff and set_default:
4446 self.setDefaultAction(action)
4447 self.addAction(action)
4448-
4449+
4450 self.connect(self, QtCore.SIGNAL("triggered(QAction *)"),
4451 self.triggered)
4452-
4453+
4454 def triggered(self, action):
4455- ext_diff = unicode(action.data().toString())
4456- self.emit(QtCore.SIGNAL("triggered(QString)"), QtCore.QString(ext_diff))
4457+ ext_diff = str(action.data())
4458+ self.emit(QtCore.SIGNAL("triggered(QString)"), ext_diff)
4459
4460
4461 class DiffButtons(QtGui.QWidget):
4462@@ -164,7 +164,7 @@
4463
4464 def triggered(self, ext_diff=None):
4465 if ext_diff is None:
4466- ext_diff = QtCore.QString(default_diff)
4467+ ext_diff = default_diff
4468 self.emit(QtCore.SIGNAL("triggered(QString)"), ext_diff)
4469
4470
4471@@ -180,21 +180,20 @@
4472
4473 @classmethod
4474 def iter_items(cls, trees, specific_files=None, filter=None, lock_trees=False):
4475+ """
4476+ RJLRJL: updated to call .iter_changes directly
4477+ """
4478 try:
4479 cleanup = []
4480 if lock_trees:
4481 for t in trees:
4482 cleanup.append(t.lock_read().unlock)
4483
4484- changes = trees[1].iter_changes(trees[0],
4485- specific_files=specific_files,
4486- require_versioned=True)
4487-
4488- def changes_key(change):
4489- return change[1][1] or change[1][0]
4490-
4491- for (file_id, paths, changed_content, versioned, parent, name, kind,
4492- executable) in sorted(changes, key=changes_key):
4493+ # changes = trees[1].iter_changes(trees[0], specific_files=specific_files, require_versioned=True)
4494+
4495+ # def changes_key(change):
4496+ # return change[1][1] or change[1][0]
4497+ for change in trees[1].iter_changes(trees[0], specific_files=specific_files, require_versioned=True):
4498 # file_id -> ascii string
4499 # paths -> 2-tuple (old, new) fullpaths unicode/None
4500 # changed_content -> bool
4501@@ -205,8 +204,8 @@
4502 # executable -> 2-tuple (bool/None, bool/None)
4503 # NOTE: None value used for non-existing entry in corresponding
4504 # tree, e.g. for added/deleted file
4505- di = DiffItem.create(trees, file_id, paths, changed_content,
4506- versioned, parent, name, kind, executable,
4507+ di = DiffItem.create(trees, change.file_id, change.path, change.changed_content,
4508+ change.versioned, change.parent_id, change.name, change.kind, change.executable,
4509 filter = filter)
4510 if not di:
4511 continue
4512@@ -216,7 +215,7 @@
4513 cleanup.pop()()
4514
4515 @classmethod
4516- def create(cls, trees, file_id, paths, changed_content, versioned,
4517+ def create(cls, trees, file_id, paths, changed_content, versioned,
4518 parent, name, kind, executable, filter = None):
4519
4520 if parent == (None, None): # filter out TREE_ROOT (?)
4521@@ -237,8 +236,8 @@
4522 for ix in range(2):
4523 if versioned[ix]:
4524 try:
4525- dates[ix] = trees[ix].get_file_mtime(paths[ix], file_id)
4526- except OSError, e:
4527+ dates[ix] = trees[ix].get_file_mtime(paths[ix])
4528+ except OSError as e:
4529 if not renamed or e.errno != errno.ENOENT:
4530 raise
4531 # If we get ENOENT error then probably we trigger
4532@@ -248,7 +247,7 @@
4533 # ghosts around us (see Bug #513096)
4534 dates[ix] = 0 # using 1970/1/1 instead
4535
4536- properties_changed = []
4537+ properties_changed = []
4538 if bool(executable[0]) != bool(executable[1]):
4539 descr = {True: "+x", False: "-x", None: None}
4540 properties_changed.append((descr[executable[0]],
4541@@ -268,7 +267,7 @@
4542 if filter and not filter(status):
4543 return None
4544
4545- return cls(trees, file_id, paths, changed_content, versioned, kind,
4546+ return cls(trees, file_id, paths, changed_content, versioned, kind,
4547 properties_changed, dates, status)
4548
4549 def __init__(self, trees, file_id, paths, changed_content, versioned, kind,
4550@@ -294,16 +293,17 @@
4551 self._load_lines()
4552
4553 def _load_lines(self):
4554- if ((self.versioned[0] != self.versioned[1] or self.changed_content)
4555- and (self.kind[0] == 'file' or self.kind[1] == 'file')):
4556+ if ((self.versioned[0] != self.versioned[1] or self.changed_content) and (self.kind[0] == 'file' or self.kind[1] == 'file')):
4557 lines = []
4558 binary = False
4559+ # print('\n_load_lines', self.file_id)
4560 for ix, tree in enumerate(self.trees):
4561 content = ()
4562 if self.versioned[ix] and self.kind[ix] == 'file':
4563 content = tree.get_file_lines(tree.id2path(self.file_id))
4564+ # print('\n\tcontent loaded for ', tree.id2path(self.file_id), self.file_id)
4565 lines.append(content)
4566- binary = binary or is_binary_content(content)
4567+ binary = binary or content_seems_to_be_binary(content)
4568 self._lines = lines
4569 self._binary = binary
4570 else:
4571@@ -344,11 +344,13 @@
4572 return groups
4573
4574 def difference_groups(self, lines, complete, ignore_whitespace):
4575+ # RJL Changed strings to bytes for pattern-matching and coerced
4576+ # left and right to lists (instead of generators) in 'if...'
4577 left, right = lines
4578 if ignore_whitespace:
4579- re_whitespaces = re.compile("\s+")
4580- left = (re_whitespaces.sub(" ", line) for line in left)
4581- right = (re_whitespaces.sub(" ", line) for line in right)
4582+ re_whitespaces = re.compile(b"\s+")
4583+ left = list((re_whitespaces.sub(b" ", line) for line in left))
4584+ right = list((re_whitespaces.sub(b" ", line) for line in right))
4585 matcher = SequenceMatcher(None, left, right)
4586 if complete:
4587 groups = list([matcher.get_opcodes()])
4588@@ -358,9 +360,9 @@
4589 return groups
4590
4591 def get_unicode_lines(self, encodings):
4592- """Return pair of unicode lines for each side of diff.
4593- Parameter encodings is 2-list or 2-tuple with encoding names (str)
4594- for each side of diff.
4595+ """
4596+ Return pair of unicode lines for each side of diff.
4597+ Parameter encodings is 2-list or 2-tuple with encoding names (str) for each side of diff.
4598 """
4599 lines = self.lines
4600 ulines = self._ulines
4601@@ -372,7 +374,7 @@
4602 else:
4603 try:
4604 ulines[i] = [l.decode(encodings[i]) for l in lines[i]]
4605- except UnicodeDecodeError, e:
4606+ except UnicodeDecodeError as e:
4607 filename = self.paths[i]
4608 trace.note("Some characters in file %s "
4609 "could not be properly decoded "
4610@@ -396,7 +398,7 @@
4611 parent = osutils.joinpath([osutils.tempfile.gettempdir(), 'qbrz'])
4612 if not os.path.isdir(parent):
4613 os.mkdir(parent)
4614- self._root = osutils.mkdtemp(prefix='qbrz/bzr-diff-')
4615+ self._root = osutils.mkdtemp(prefix='qbrz/brz-diff-')
4616 self.prefixes = {}
4617 self._set_prefix()
4618
4619@@ -414,9 +416,10 @@
4620 self.new_prefix = self.get_prefix(self.new_tree)
4621
4622 def get_prefix(self, tree):
4623+
4624 def get_key(tree):
4625 if hasattr(tree, "get_revision_id"):
4626- return tree.__class__.__name__ + ":" + tree.get_revision_id()
4627+ return tree.__class__.__name__ + ":" + tree.get_revision_id().decode('utf-8')
4628 elif hasattr(tree, "abspath"):
4629 return tree.__class__.__name__ + ":" + tree.abspath("")
4630 else:
4631@@ -425,7 +428,7 @@
4632 if tree is None:
4633 return None
4634 key = get_key(tree)
4635- if self.prefixes.has_key(key):
4636+ if key in self.prefixes:
4637 return self.prefixes[key]
4638 prefix = str(len(self.prefixes) + 1)
4639 self.prefixes[key] = prefix
4640@@ -466,31 +469,30 @@
4641 if os.path.isdir(path):
4642 open(os.path.join(path, ".delete"), "w").close()
4643
4644- def _write_file(self, relpath, tree, prefix, force_temp=False,
4645- allow_write=False, file_id=None):
4646+ def _write_file(self, relpath, tree, prefix, force_temp=False, allow_write=False, file_id=None):
4647 if force_temp or not isinstance(tree, WorkingTree):
4648 full_path = self._safe_filename(prefix, relpath)
4649 if os.path.isfile(full_path):
4650 return full_path
4651- return DiffFromTool._write_file(self, relpath, tree, prefix,
4652- force_temp, allow_write, file_id)
4653+ # return DiffFromTool._write_file(self, relpath, tree, prefix, force_temp, allow_write, file_id)
4654+ return DiffFromTool._write_file(self, relpath, tree, prefix, force_temp, allow_write)
4655
4656- def _prepare_files(self, old_path, new_path, force_temp=False,
4657- file_id=None, allow_write_new=False):
4658- old_disk_path = self._write_file(old_path, self.old_tree,
4659- self.old_prefix, force_temp,
4660- file_id=file_id)
4661- new_disk_path = self._write_file(new_path, self.new_tree,
4662- self.new_prefix, force_temp,
4663- allow_write=allow_write_new,
4664- file_id=file_id)
4665- return old_disk_path, new_disk_path
4666+ # def _prepare_files(self, old_path, new_path, force_temp=False,
4667+ # file_id=None, allow_write_new=False):
4668+ # old_disk_path = self._write_file(old_path, self.old_tree,
4669+ # self.old_prefix, force_temp,
4670+ # file_id=file_id)
4671+ # new_disk_path = self._write_file(new_path, self.new_tree,
4672+ # self.new_prefix, force_temp,
4673+ # allow_write=allow_write_new,
4674+ # file_id=file_id)
4675+ # return old_disk_path, new_disk_path
4676
4677 def _execute(self, old_path, new_path):
4678 command = self._get_command(old_path, new_path)
4679 try:
4680 subprocess.Popen(command, cwd=self._root)
4681- except OSError, e:
4682+ except OSError as e:
4683 if e.errno == errno.ENOENT:
4684 raise ExecutableMissing(command[0])
4685 else:
4686@@ -500,12 +502,15 @@
4687 def diff(self, file_id):
4688 try:
4689 new_path = self.new_tree.id2path(file_id)
4690- new_kind = self.new_tree.kind(new_path, file_id)
4691+ # new_kind = self.new_tree.kind(new_path, file_id)
4692+ new_kind = self.new_tree.kind(new_path)
4693 old_path = self.old_tree.id2path(file_id)
4694- old_kind = self.old_tree.kind(old_path, file_id)
4695+ # old_kind = self.old_tree.kind(old_path, file_id)
4696+ old_kind = self.old_tree.kind(old_path)
4697 except NoSuchId:
4698 return DiffPath.CANNOT_DIFF
4699- return DiffFromTool.diff(self, file_id, old_path, new_path, old_kind, new_kind)
4700+ # return DiffFromTool.diff(self, file_id, old_path, new_path, old_kind, new_kind)
4701+ return DiffFromTool.diff(self, old_path, new_path, old_kind, new_kind)
4702
4703 class ExtDiffContext(QtCore.QObject):
4704 """
4705@@ -516,7 +521,7 @@
4706 """
4707 :parent: parent widget. If specified, cache is deleted automatically
4708 when parent is closed.
4709- :to_file: stream to write output messages. If not specified,
4710+ :to_file: stream to write output messages. If not specified,
4711 stdout is used.
4712 :path_encoding: encoding of path
4713 """
4714@@ -562,8 +567,7 @@
4715 Set or change diff command and diffed trees.
4716 """
4717 if self._differ is None:
4718- self._differ = _ExtDiffer(command_string, old_tree, new_tree,
4719- self.to_file, self.path_encoding)
4720+ self._differ = _ExtDiffer(command_string, old_tree, new_tree, self.to_file, self.path_encoding)
4721 else:
4722 self._differ.set_trees(old_tree, new_tree)
4723 self._differ.set_command_string(command_string)
4724@@ -577,7 +581,7 @@
4725 """
4726 Show diffs of specified file_ids.
4727 NOTE: Directories cannot be specified.
4728- Use diff_tree or diff_paths instead when specifing directory.
4729+ Use diff_tree or diff_paths instead when specifing directory.
4730 """
4731 cleanup = []
4732 try:
4733
4734=== modified file 'lib/diffview.py'
4735--- lib/diffview.py 2017-09-11 06:53:22 +0000
4736+++ lib/diffview.py 2020-07-16 14:28:25 +0000
4737@@ -21,7 +21,7 @@
4738
4739 import re
4740 from breezy import timestamp
4741-from breezy.patiencediff import PatienceSequenceMatcher as SequenceMatcher
4742+from patiencediff import PatienceSequenceMatcher as SequenceMatcher
4743 from breezy.plugins.qbrz.lib.i18n import gettext
4744 from breezy.plugins.qbrz.lib.util import (
4745 file_extension,
4746@@ -66,18 +66,18 @@
4747
4748 config = get_qbrz_config()
4749 component_dict = {0:'fill', 1:'bound'}
4750-for key in colors.iterkeys():
4751+for key in colors.keys():
4752 for comp in [0,1]:
4753 color = None
4754 try:
4755 color = config.get_color(key + '_' + component_dict[comp],
4756 'QDIFF COLORS')
4757- except ValueError, msg:
4758+ except ValueError as msg:
4759 #error handling.
4760 mutter(str(msg))
4761 if None != color:
4762 colors[key][comp] = color
4763-
4764+
4765
4766 #Get a user-defined replacement text background
4767 try:
4768@@ -85,11 +85,11 @@
4769 'QDIFF COLORS')
4770 if None != new_interline_bg:
4771 interline_changes_background = new_interline_bg
4772-except ValueError, msg:
4773+except ValueError as msg:
4774 mutter(str(msg))
4775
4776 brushes = {}
4777-for kind, cols in colors.items():
4778+for kind, cols in list(colors.items()):
4779 brushes[kind] = (QtGui.QBrush(cols[0]), QtGui.QBrush(cols[1]))
4780
4781
4782@@ -126,7 +126,7 @@
4783 if block_y > bot:
4784 break
4785 painter.drawLine(0, block_y, w, block_y)
4786-
4787+
4788 pen.setWidth(1)
4789 for y_top, y_bot, kind in self.changes:
4790 y_top -= y
4791@@ -140,7 +140,7 @@
4792 painter.drawLine(0, y_top, w, y_top)
4793 painter.drawLine(0, y_bot - 1, w, y_bot - 1)
4794 del painter
4795- QtGui.QTextBrowser.paintEvent(self, event)
4796+ QtGui.QTextBrowser.paintEvent(self, event)
4797
4798 def wheelEvent(self, event):
4799 if event.orientation() == QtCore.Qt.Vertical and self.scrollbar:
4800@@ -155,7 +155,7 @@
4801 self.scrollbar = None
4802 self.view = parent
4803 self.clear()
4804-
4805+
4806 def clear(self):
4807 self.changes = []
4808 self.infoBlocks = []
4809@@ -203,7 +203,7 @@
4810 ly_bot -= ly + 1
4811 ry_top -= ry
4812 ry_bot -= ry + 1
4813-
4814+
4815 if ly_top < 0 and ly_bot < 0 and ry_top < 0 and ry_bot < 0:
4816 continue
4817 if ly_top > h and ly_bot > h and ry_top > h and ry_bot > h:
4818@@ -221,7 +221,7 @@
4819
4820 painter.fillPath(region, brushes[kind][0])
4821 painter.setPen(colors[kind][1])
4822- for path, aa in zip((upper_line, lower_line),
4823+ for path, aa in zip((upper_line, lower_line),
4824 (ly_top != ry_top, ly_bot != ry_bot)):
4825 painter.setRenderHints(QtGui.QPainter.Antialiasing, aa)
4826 painter.drawPath(path)
4827@@ -264,7 +264,7 @@
4828 b.scrollbar = self
4829
4830 for i, scbar in enumerate([self] + [b.verticalScrollBar() for b in browsers]):
4831- self.connect(scbar, QtCore.SIGNAL("valueChanged(int)"),
4832+ self.connect(scbar, QtCore.SIGNAL("valueChanged(int)"),
4833 lambda value, target=i : self.scrolled(target))
4834
4835 self.connect(browsers[0], QtCore.SIGNAL("resized()"), self.adjust_range)
4836@@ -398,19 +398,19 @@
4837 titleFont = QtGui.QFont(self.font())
4838 titleFont.setPointSize(titleFont.pointSize() * 140 / 100)
4839 titleFont.setBold(True)
4840-
4841+
4842 self.monospacedFont = get_monospace_font()
4843 metadataFont = QtGui.QFont(self.font())
4844 metadataFont.setPointSize(titleFont.pointSize() * 70 / 100)
4845 metadataLabelFont = QtGui.QFont(metadataFont)
4846 metadataLabelFont.setBold(True)
4847-
4848+
4849 self.monospacedFormat = QtGui.QTextCharFormat()
4850 self.monospacedFormat.setFont(self.monospacedFont)
4851 self.ttype_formater = CachedTTypeFormater(
4852 QtGui.QTextCharFormat(self.monospacedFormat))
4853 self.background = self.monospacedFormat.background()
4854-
4855+
4856 self.titleFormat = QtGui.QTextCharFormat()
4857 self.titleFormat.setFont(titleFont)
4858 self.metadataFormat = QtGui.QTextCharFormat()
4859@@ -436,12 +436,12 @@
4860 b.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
4861
4862 self.cursors = [QtGui.QTextCursor(doc) for doc in self.docs]
4863-
4864+
4865 for i, (panel, doc, cursor) in enumerate(zip(self.guidebar_panels,
4866 self.docs, self.cursors)):
4867 doc.setUndoRedoEnabled(False)
4868 doc.setDefaultFont(self.monospacedFont)
4869-
4870+
4871 panel.edit.setDocument(doc)
4872 self.addWidget(panel)
4873 self.setCollapsible(i, False)
4874@@ -457,15 +457,15 @@
4875 self.connect(self.browsers[1].horizontalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.syncHorizontalSlider2)
4876
4877 self.rewinded = False
4878-
4879+
4880 self.lastModifiedLabel = gettext('Last modified:')
4881 self.statusLabel = gettext('Status:')
4882 self.kindLabel = gettext('Kind:')
4883 self.propertiesLabel = gettext('Properties:')
4884-
4885+
4886 self.image_exts = ['.'+str(i)
4887 for i in QtGui.QImageReader.supportedImageFormats()]
4888-
4889+
4890 config = get_qbrz_config()
4891 self.show_intergroup_colors = config.get_option("diff_show_intergroup_colors") in ("True", "1")
4892
4893@@ -522,16 +522,16 @@
4894 else:
4895 cursor.insertText(" ", self.metadataFormat)
4896 cursor.insertBlock()
4897-
4898+
4899 infoBlocks = (cursors[0].block().layout(),
4900 cursors[1].block().layout())
4901 changes = []
4902-
4903+
4904 if not binary:
4905 for cursor in cursors:
4906 cursor.setCharFormat(self.monospacedFormat)
4907 cursor.insertBlock()
4908-
4909+
4910 def fix_last_line(lines):
4911 """Fix last line if there is no new line.
4912
4913@@ -544,7 +544,7 @@
4914 if last and last[-1] not in ('\r', '\n'):
4915 lines = lines[:-1] + [last+'\n']
4916 return lines
4917-
4918+
4919 lines = [fix_last_line(l) for l in lines]
4920 if have_pygments:
4921 use_pygments = True
4922@@ -570,7 +570,7 @@
4923 else:
4924 use_pygments = False
4925 display_lines = lines
4926-
4927+
4928 def insertLine(cursor, line):
4929 if use_pygments:
4930 for ttype, value in line:
4931@@ -579,12 +579,12 @@
4932 cursor.insertText(value, format)
4933 else:
4934 cursor.insertText(line)
4935-
4936+
4937 def insertIxs(ixs):
4938 for cursor, line, ix in zip(cursors, display_lines, ixs):
4939 for l in line[ix[0]:ix[1]]:
4940 insertLine(cursor, l)
4941-
4942+
4943 def modifyFormatForTag (format, tag):
4944 if tag == "replace":
4945 format.setBackground(interline_changes_background)
4946@@ -594,7 +594,7 @@
4947 format.setBackground(brushes[tag][0])
4948 else:
4949 format.setBackground(interline_changes_background)
4950-
4951+
4952 split_words = re.compile(r"\w+|\n\r|\r\n|\W")
4953 def insertIxsWithChangesHighlighted(ixs):
4954 texts = ["".join(l[ix[0]:ix[1]]) for l, ix in zip(lines, ixs)]
4955@@ -602,9 +602,9 @@
4956 # This is what the pygments lexer does, so we need to do the
4957 # same incase we have \r\n line endings.
4958 texts = ["\n".join(t.splitlines()) for t in texts]
4959-
4960+
4961 texts = [split_words.findall(t) for t in texts]
4962-
4963+
4964 if use_pygments:
4965 groups = ([], [])
4966 for tag, i0, i1, j0, j1 in SequenceMatcher(None,
4967@@ -639,14 +639,14 @@
4968 format = QtGui.QTextCharFormat()
4969 format.setFont(self.monospacedFont)
4970 modifyFormatForTag(format, tag)
4971-
4972+
4973 cursors[0].insertText("".join(texts[0][i0:i1]),format)
4974 cursors[1].insertText("".join(texts[1][j0:j1]),format)
4975-
4976+
4977 for cursor in cursors:
4978 cursor.setCharFormat (self.monospacedFormat)
4979
4980-
4981+
4982 for i, group in enumerate(groups):
4983 if i > 0:
4984 y_top = [cursor.block().layout() for cursor in self.cursors]
4985@@ -711,8 +711,8 @@
4986 heights[i] = image.height()
4987 self.docs[i].addResource(QtGui.QTextDocument.ImageResource,
4988 QtCore.QUrl(file_id),
4989- QtCore.QVariant(image))
4990-
4991+ image)
4992+
4993 max_height = max(heights)
4994 for i, cursor in enumerate(self.cursors):
4995 format = QtGui.QTextBlockFormat()
4996@@ -747,7 +747,7 @@
4997 self.browsers[0].infoBlocks.append(l_block)
4998 self.browsers[1].infoBlocks.append(r_block)
4999 self.handle(1).infoBlocks.append((l_block, r_block))
5000-
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches