Comment 4 for bug 435286

Revision history for this message
John A Meinel (jameinel) wrote : Re: [Bug 435286] Re: qmerge dialog should remember its size

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

John A Meinel wrote:
> Alexander Belchenko wrote:
>> It works for me actually. Sorry for the noise.
>
>
> So it still doesn't work for me for merge, push, and pull
>
> Other windows like branch seem to have settings in qbzr.conf.
>
> Hmm... they have settings but the changes are not remembered.
>
> Maybe it is because I'm using PyQt 4.5.2 on python2.6?
>
> I don't see any failure warnings, etc. in ~/.bzr.log is there something
> I can do to help debug this?
>
> John
> =:->
>

So I started adding some 'print' statements into qbzr, and while I see:
$ bzr qcommit
_QBzrWindowBase.restoreSize (CommitWindow), commit
Committing to: C:/Users/jameinel/dev/,tmp/a/
modified foo
Committed revision 3.

I never see "saveSize()" getting called.

I tracked things down to _QBzrWindowBase.closeEvent() which is the only
bit of code I could find that was calling saveSize().

So I started tracking down through the call paths of closeEvent and I
think I have it sorted out.

Specifically, SubProcessDialog.closeEvent is:

    def closeEvent(self, event):
        if not self.process_widget.is_running():
            QBzrDialog.closeEvent(self, event)
        else:
            self.process_widget.abort()
            event.ignore()

And if check QBzrDialog I have:

class QBzrDialog(QtGui.QDialog, _QBzrWindowBase):

and it is on _QBzrWindowBase that you have:

    def closeEvent(self, event):
        self.closing = True
        self.saveSize()
        for window in self.windows:
            if window.isVisible():
                window.close()
        event.accept()

My guess is that PyQt 4.5.2 now implements a closeEvent function, and
you are using multi-inheritance and expecting all members to get called.

However because you have:

class QBzrDialog(QtGui.QDialog, _QBzrWindowBase):

Only the QDialog.closeEvent is getting called, and not your custom
implementation. and QDialog.closeEvent() isn't calling
super(...).closeEvent() in order to handle the multi-inheritance issue.

As somewhat proof of this, if I do:

=== modified file 'lib/util.py'
- --- lib/util.py 2009-08-20 13:23:27 +0000
+++ lib/util.py 2009-09-23 15:12:57 +0000
@@ -390,7 +390,7 @@
         self.closing = False

- -class QBzrDialog(QtGui.QDialog, _QBzrWindowBase):
+class QBzrDialog(_QBzrWindowBase, QtGui.QDialog):

     def __init__(self, title=None, parent=None, ui_mode=True):
         self.ui_mode = ui_mode

Then settings are properly saved again....

I don't really know the correct answer, but I can say that multiple
inheritance is hurting you here. It may be that the PyQt wrappers don't
play well with multiple inheritance.

I also notice that "_QBzrWindowBase" is a bare class, not a subclass of
QObject or 'object', which may complicate things even more. (without
subclassing 'object' you get an old-style class, which acts differently
in python than new-style classes.)

However, neither
  class _QBzrWindowBase(QtCore.QObject):
nor
  class _QBzrWindowBase(object):

caused things to work. The only thing that worked was the above. Or
possibly:
=== modified file 'lib/util.py'
- --- lib/util.py 2009-08-20 13:23:27 +0000
+++ lib/util.py 2009-09-23 15:25:01 +0000
@@ -407,6 +407,10 @@
     def do_reject(self):
         self.reject()

+ def closeEvent(self, event):
+ QtGui.QDialog.closeEvent(self, event)
+ _QBzrWindowBase.closeEvent(self, event)
+

Note that the PyQt docs say this:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#multiple-inheritance

14.3 Multiple Inheritance

It is not possible to define a new Python class that sub-classes from
more than one Qt class.

It also says:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#super-and-pyqt-classes
14.7 super and PyQt Classes

In versions of PyQt earlier than v4.5 there were restrictions on the use
of super with PyQt classes. These restrictions no longer apply with v4.5
and later.

So my guess is that PyQt <4.5 isn't inheriting from 'object' and as of
4.5 it started inheriting from 'object', and that probably changed the
final effect of multiple inheritance and method resolution order.

If you look at the python documentation:
http://docs.python.org/tutorial/classes.html#multiple-inheritance

It says that for "old-style classes the only rule is:
 depth-first, left-to-right
"

Which means that if QtCore.QDialog implements a closeEvent() then

class QBzrDialog(QtGui.QDialog, _QBzrWindowBase):

Will always call the QDialog.closeEvent *first*, since it is the
'leftmost' parent.

The alternative with new-style classes is the mro, which is defined more
in detail here:
http://www.python.org/download/releases/2.3/mro/

Anyway, I'm trying to get to the sources for the closeEvent stuff, I'll
see where I get to.

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkq6QS0ACgkQJdeBCYSNAAP7OgCgz2GB5lniM5HPLQkbyPv/tpLw
SucAnj/f3IVgDe1zUFprgQxKRHkbdCeW
=Ipfi
-----END PGP SIGNATURE-----