[PyQt] QMacPasteboardMime

Michael Herrmann michael at herrmann.io
Tue Jul 17 07:08:27 BST 2018


On 16 July 2018 at 19:57, Phil Thompson <phil at riverbankcomputing.com> wrote:

> A small, complete example would help.
>

Good suggestion. In creating a self-contained example, I actually figured
out how
to fix the problem. Here is my code in case others are interested:

from PyQt5.QtMacExtras import QMacPasteboardMime

class MacClipboardFix(QMacPasteboardMime):
"""
Work around QTBUG-61562 on Mac, which can be reproduced as follows:

from PyQt5.QtWidgets import QApplication
app = QApplication([])
app.clipboard().setText('Hello')

Now paste into Excel or Pycharm. The text that gets pasted is not just
'Hello' but '\uFEFFHello'.
"""
def __init__(self):
super().__init__(QMacPasteboardMime.MIME_CLIP)
def convertorName(self):
return 'UnicodeTextUtf8Default'
def flavorFor(self, mime):
if mime == 'text/plain':
return 'public.utf8-plain-text'
parts = mime.split('charset=', 1)
if len(parts) > 1:
charset = parts[1].split(';', 1)[0]
if charset == 'system':
return 'public.utf8-plain-text'
if charset in ('iso-106464-ucs-2', 'utf16'):
return 'public.utf16-plain-text'
return None
def canConvert(self, mime, flav):
return mime.startswith('text/plain') and \
flav in ('public.utf8-plain-text', 'public.utf16-plain-text')
def mimeFor(self, flavor):
if flavor == 'public.utf8-plain-text':
return 'text/plain'
if flavor == 'public.utf16-plain-text':
return 'text/plain;charset=utf16'
return None
def convertFromMime(self, mime, data, flavor):
if flavor == 'public.utf8-plain-text':
return [data.encode('utf-8')]
if flavor == 'public.utf16-plain-text':
return [data.encode('utf-16')]
return []
def convertToMime(self, mime, data, flavor):
if len(data) > 1:
raise ValueError('Cannot handle multiple data members')
data, = data
if flavor == 'public.utf8-plain-text':
return data.decode('utf-8')
if flavor == 'public.utf16-plain-text':
return data.decode('utf-16')
raise ValueError('Unhandled MIME type: ' + mime)

You then need to instantiate this class (and keep the instance around so it
isn't
garbage collected) somewhere in your code.

Thanks Phil, and sorry for unnecessarily having strained your time.

Best,
Michael

On 16 July 2018 at 19:57, Phil Thompson <phil at riverbankcomputing.com> wrote:

> On 16 Jul 2018, at 5:58 pm, Michael Herrmann <michael at herrmann.io> wrote:
> >
> > Hi all,
> >
> > I'm trying to work around QTBUG-61562: On Mac, this bug prepends
> invisible Unicode characters to the clipboard when copy/pasting.
> >
> > The class QMacPasteboardMime lets one customize copy/pasting on Mac. I
> created a subclass of it, which does get picked up by Qt. However, the
> crucial methods canConvert(...) and convertFromMime(...) aren't called.
> Only the more preliminary convertorName() and flavorFor(...) of my subclass
> are invoked.
> >
> > Does anyone have experience with this? Here is my code, adapted from a
> solution posted in the discussion of QTBUG-61652:
> >
> > from PyQt5.QtMacExtras import QMacPasteboardMime
> >
> > class MyMime(QMacPasteboardMime):
> >     def __init__(self):
> >         super().__init__(QMacPasteboardMime.MIME_CLIP)
> >     def convertorName(self):
> >         return 'UnicodeTextUtf8Default'
> >     def flavorFor(self, mime):
> >         if mime == 'text/plain':
> >             return 'public.utf8-plain-text'
> >         i = mime.find('charset=')
> >         if i >= 0:
> >             charset = mime[i + len('charset='):]
> >             charset = charset.split(';', 1)[0]
> >             if charset == 'system':
> >                 return 'public.utf8-plain-text'
> >             if charset in ('iso-10646-ucs-2', 'ut16'):
> >                 return 'public.utf16-plain-text'
> >         return None
> >     def canConvert(self, mime, flav):
> >         return mime.startswith('text/plain') and \
> >             flav in ('public.utf8-plain-text', 'public.utf16-plain-text')
> >     def mimeFor(self, flavor):
> >         if flavor == 'public.utf8-plain-text':
> >             return 'text/plain'
> >         if flavor == 'public.utf16-plain-text':
> >             return 'text/plain;charset=utf16'
> >         return None
> >     def convertToMime(self, mimetype, data, flavor):
> >         if len(data) > 1:
> >             raise ValueError('Cannot handle multiple member data')
> >         first, = data
> >         if flavor == 'public.utf8-plain-text':
> >             return first.decode('utf-8')
> >         if flavor == 'public.utf16-plain-text':
> >             return first.decode('utf-16')
> >         raise ValueError('Unhandled MIME type: ' + mimetype)
> >     def convertFromMime(self, mime, data, flavor):
> >         string = data.toString()
> >         if flavor == 'public.utf-8.plain-text':
> >             return string.encode('utf-8')
> >         if flavor == 'public.utf16-plain-text':
> >             return string.encode('utf-16')
> >         return b''
> >
> > As I said, flavorFor(...) gets called with 'text/plain'. And
> convertorName() gets called. But not canConvert(...) and
> convertFromMime(...).
>
> A small, complete example would help.
>
> Phil




-- 
[image: Inline image 1]

Michael Herrmann, MSc
Vienna, Austria
Follow me on Twitter <https://twitter.com/m_herrmann>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180717/97a246bb/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Strich.png
Type: image/png
Size: 2820 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180717/97a246bb/attachment-0001.png>


More information about the PyQt mailing list