View Single Post
Old 07-06-2014, 03:48 AM   #2
kovidgoyal
creator of calibre
kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.kovidgoyal ought to be getting tired of karma fortunes by now.
 
kovidgoyal's Avatar
 
Posts: 43,957
Karma: 22669822
Join Date: Oct 2006
Location: Mumbai, India
Device: Various
Guide for porting plugin code to Qt 5

  1. The first thing to port is imports from PyQt4. Where ever you have a statement that look like:
    Code:
    from PyQt4.Qt import ...
    change it to

    Code:
    try:
        from PyQt4.Qt import ...
    except ImportError:
        from PyQt5.Qt import ...
    If you use the QtCore or QtGui modules directly, change the imports like this.

    Code:
    try:
        from PyQt4 import QtGui
    except ImportError:
        from PyQt5 import Qt as QtGui
  2. PyQt5 automatically converts QVariants to the equivalent python objects. So any code that explicitly converted QVariants will need to be ported. Look for function calls like: toBool(), toString(), toPyObject(), toInt(), etc.

    To port these we use a utility function that will do the right thing regardless of Qt version.
    Code:
    try:
        from calibre.gui2 import QVariant
        del QVariant
    except ImportError:
        is_qt4 = False
        convert_qvariant = lambda x: x
    else:
        is_qt4 = True
    
        def convert_qvariant(x):
            vt = x.type()
            if vt == x.String:
                return unicode(x.toString())
            if vt == x.List:
                return [convert_qvariant(i) for i in x.toList()]
            return x.toPyObject()
    Now replace any sites in your code that explicitly convert QVariants with a call to convert_qvariant(value) instead.

  3. The QString and QChar classes no longer exist in PyQt5. However, you should not have been using them in PyQt4 either. Simply replace their usage with the python unicode object. Any function call that expects QString will take a unicode object in both PyQt4 and PyQt5. Any Qt function that you call that returns a QString should simply be wrapped like this to work in both PyQt4 and PyQt5
    Code:
    ans = unicode(function_that_returns_a_qstring())
  4. The QAbstractItemModel class (and its various subclasses such as QListModel, QTreeModel and so on) no longer have a reset() method. If you use this method, replace it with beginResetModel() and endResetModel() which work with both Qt 4 and Qt 5

  5. The deprecated line edit with completion (MultiCompleteComboBox, MultiCompleteLineEdit) from calibre has been removed. If you use it replace it with EditWithComplete from calibre.gui2.complete2 (this works with both Qt 4 and Qt 5 and exists in all versions of calibre >=0.9.0).
  6. If you used the deprecated SIGNAL macro to connect Qt signals and slots, you will have to replace it with a new syntax, since it no longer exists in Qt 5. For example:

    Code:
    self.connect(action, SIGNAL("triggered()"), slot)
    
    becomes
    
    self.action.triggered.connect(slot)
    The new syntax is nicer and more robust than the old and works in both Qt 4 and Qt 5
There are a few other, more obscure changes that might be needed, depending on what parts of Qt you use, which I will be happy to help with, if necessary.

Last edited by kovidgoyal; 08-15-2014 at 04:45 AM.
kovidgoyal is offline   Reply With Quote