[Qt-components] Ubuntu UI toolkit - Clipboard access

Zsombor Egri zsombor.egri at canonical.com
Wed Jan 23 19:39:35 CET 2013


On 01/23/2013 07:55 PM, Alan Alpert wrote:
> On Wed, Jan 23, 2013 at 9:00 AM, Zsombor Egri
> <zsombor.egri at canonical.com> wrote:
>> On 01/23/2013 05:49 PM, Alan Alpert wrote:
>>> On Wed, Jan 23, 2013 at 3:15 AM, Zsombor Egri
>>> <zsombor.egri at canonical.com> wrote:
>>>> On 01/23/2013 12:09 PM, Aaron J. Seigo wrote:
>>>>
>>>> On Wednesday, January 23, 2013 10:06:59 Zsombor Egri wrote:
>>>>
>>>> Here's an API we are proposing for accessing the system clipboard from
>>>> QML and to filter its content before being copied into a TextField/TextArea.
>>>>
>>>> proposing to be added to Qt's QML API? (that seems the best place for such a
>>>> thing)
>>>>
>>>> This was proposed for the Ubuntu UI toolkit, just wanted to share with you
>>>> because I see it makes sense to have such a component in Qt QML.
>>>>
>>>>
>>>> The API consists of an object, a data transfer type and a filter element.
>>>>
>>>> The global object is based on (and uses) QClipboard functionality:
>>>>
>>>> *clipboard* {
>>>>     function *clear*() - to clear the clipboard content
>>>>     function *setData*(string mimeType, var data) - pushes data to the
>>>> clipboard
>>>>     function MimeData *data*() - retrieves the clipboard data
>>>> }
>>>>
>>>> i'm not a fan of global objects in the least. much nicer to instantiate
>>>> items
>>>> that are actually needed. otherwise, we end up with a growing pile of
>>>> objects
>>>> of limited value in many use cases.
>>>>
>>>> Agree. The unicity of the Clipboard per application drove me to have the
>>>> object instead of instantiating items per need.
>>> Use the new Singleton Type API:
>>> http://qt-project.org/doc/qt-5.0/qtqml/qqmlengine.html#qmlRegisterSingletonType-2
>>>
>>> Only one instance per application, easier to use than a global object,
>>> and still not created until the application needs it.
>>>
>>> Also the setData/data and clear sure look like that should just be one
>>> data property with a setter, getter and reset function.
>>>
>>>> also, why functions instead of a data property? an object with mimeType and
>>>> data properties could be assigned/retrieved from it. setting an invalid
>>>> object
>>>> would be a no-op.
>>>>
>>>> it also makes clear unnecessary: just set data to be an empty / invalid
>>>> MimeData object.
>>>>
>>>> Makes sense.
>>>>
>>>>
>>>> The MimeData type provides access to the clipboard data itself; all
>>>> properties are read-only.
>>>>
>>>> *MimeData* {
>>>>     readonly property list<string> *types* - contains the available
>>>> types in the clipboard
>>>>     readonly property string *text* - text data or undefined if no text
>>>> data in clipboard
>>>>     readonly property string *html* - HTML data or undefined
>>>>     readonly property list<url> *urls* - list or URLs or undefined
>>>>     readonly property color *color* - color data or undefined
>>>>
>>>>     function var *mimeData*(string type) - returns data corresponding to
>>>> the MIME type
>>>> }
>>>>
>>>> why not a single variant property?
>>>> why a function to return the mimeData? this is going to be implemented in
>>>> C++
>>>> i imagine anyways, so a property that is retrieved via a C++ function seems
>>>> normal. it can be set to read-only.
>>> If we aren't exposing the full QMimeData functionality anyways, why
>>> not just add these as convenience functions on the global clipboard
>>> object?
>> I was about to send a new API proposal with one object when I got your
>> reply :)
>>>> A single variant property may make sense if the clipboard could have only
>>>> one mime type data inside. But you can have more of those at the same time,
>>>> so the properties would retrieve the particular data types when the mimeData
>>>> function would retrieve other types. A pair of (type, data) property would
>>>> also do the job, where setting the type would automatically alter the data,
>>>> but I find those kind of dependencies a bit cumbersome...
>>>>
>>>>
>>>> And finally the clipboard filter element, which is meant to capture
>>>> clipboard changes aswell as to grab clipboard key shortcuts from a
>>>> TextField or TextArea so data can be filtered before pasting it into the
>>>> text inputs.
>>> I'd also have thought that you could handle key combinations before
>>> the TextEdit already using Keys.onPressed. If you have that and a
>>> global clipboard, why do you need the filter element?
>>>
>>> Even if there is a need, I don't see why you need this to be a
>>> separate filter instead of just having the signals on the
>>> TextArea/TextInput (like how QTextEdit has a virtual you can use).
>> The API is proposed for Ubuntu UI toolkit and therefore we are working
>> on top of existing Qt5 QML components. I brought it here to discuss it
>> so that - eventually - we can include it in QML or Qt Components.
>>
>> On top of TextInput/TextEdit I don't get Key_Copy/Key_Cut/Key_Paste keys
>> in Keys.onPressed, so this functionality must be captured somehow inside
>> these components, otherwise we need a component to filter these out and
>> steal them from the TextEdit/TextInput.
> In general I think explicit key handling on an item is supposed to
> take precedence over the default key handling. Which means it should
> work, but we might need to 'fix a few bugs'.
Then, if we should get these key events, I guess I have to file a bug.
In C++ I get them as QKeySequence matches, are those converted into
Qt.Key_XXX codes? (haven't checked yet the sources)
>
>> On the other hand I do also see a benefit on having these events
>> captured on TextInput/TextEdit level so the functionality would then
>> also be available in TextField and TextArea respectively.
>>
>>>> this feels like something that would make sense as part of MimeData above,
>>>> perhaps?
>>>>
>>>> Not really, the MimeData aint supposed to be instantiable within QML. It's
>>>> just a data holder.
>>>>
>>>>
>>>> also, what sort of filtering do you forsee being done?
>>>>
>>>> Typical example is when you want to filter the data to be copied from the
>>>> clipboard into a text input element. You can control the content when using
>>>> context menu so you can leave out all the unnecessary data, but when using
>>>> key sequence, both TextInput and TextEdit will grab those so you are no
>>>> longer in control of filtering the data pasted. The ClipboardFilter helps
>>>> you on that.
>>>>
>>>> Yes, you could say that you push the data filtered, but at the source you
>>>> never know who's gonna be the destination.
>>>>
>>> To sum up, since I suggested that this all belongs on one singleton
>>> clipboard object, here's what that API might look like:
>>>
>>> Clipboard { // Although you can't instantiate one yourself
>>>     property string data - latest data (of a single mimetype which is
>>> convertable to string) in the clipboard
>>>     property string mimeType - the mimetype of data
>>>
>>>     //Possible conveniences
>>>     readonly property list<string> formats - contains the available
>>> types in the clipboard
>>>     readonly property string text - text data or undefined if no text
>>> data in clipboard
>>>     readonly property string html - HTML data or undefined
>>>     readonly property list<url> urls - list or URLs or undefined
>>>     readonly property color color - color data or undefined
>>> }
>>>
>>> Note that bytearray MIME data, which QML can't handle, is basically
>>> ignored. You'll need C++ if you want to use that.
>> Right. Almost like my second proposal :) But, when to push data to
>> clipboard?
> Any time you set data or mimeData.
You mean mimeType is set. To me this sounds like one operation overhead.
If for instance you have a clipboard history logger app like Clipit, it
will show two separate clipboard entries. That may be a bit of a problem.
>
>> When the data is set or when the type is set?
> Any time the clipboard changes, the new data and type are set.
>
>> How do we make
>> sure we push the right time?
> We push every time. This means we'll push at the right time, as well
> as many other times. Is that a problem?
It is. Same reason I had for Clipit. You will have plenty of history
entries, and I'd say we should consider these cases too. It also sounds
a bit of a hammering ;)
>
>> How about if we want to have more MIME
>> types in the clipboard at the same time?
> This doesn't support that. Is that really an issue considering how few
> MIME types (only string ones) can be effectively used in QML?
An application may want to store different data in the clipboard.
Typical case is the QtCreator copy case: QtCreator stores the plain text
and HTML formatted text too in clipboard.
>
>> In addition to your summary I had a function called push() which when
>> called would copy all the properties set to the clipboard. Note that I
>> have few properties more R/W than you.
>>
>> Clipboard { // Although you can't instantiate one yourself
>>     property string data - latest data (of a single mimetype which is
>> convertable to string) in the clipboard
>>     property string mimeType - the mimetype of data
>>
>>     //Possible conveniences
>>     readonly property list<string> formats - contains the available
>> types in the clipboard
>>     property string text - text data or undefined if no text
>> data in clipboard
>>     property string html - HTML data or undefined
>>     readonly property list<url> urls - list or URLs or undefined
>>     property color color - color data or undefined
>>
>>     // functions
>>     function push() - copies the data to the clipboard
>> }
>>
> I don't like having the push() pushing the data from the Clipboard
> singleton to the backing clipboard. The Clipboard is supposed to
> represent the state of the application clipboard, there's no way to
> tell if the text is one that just came in from somewhere else or one
> that you set but haven't pushed yet.
>
> If you need this manual control of pushing data, and multiple MIME
> type support, the API should look more like this:
>
> Clipboard {
>     property MimeData data
> }
Yep, somewhat similar to what I had previously, just with singleton type
and one property, which looks a bit too funny :)
>
> where setting data pushes a new MimeData and reading it grabs the
> current data. Just like the basic QClipboard API (in fact, we probably
> want them to work with the same QMimeData objects).
>
> We lose a lot of convenience though, we'd at least need a .toString()
> and convenience string constructor on MimeData so QML can, in the
> common case, just use it as strings.
>
>>> For the filter properties, we just need something like Keys.onPressed:
>>> if (key.buttons == Qt::Copy_Shortcut), right? Other than the default
>>> key handling, pastes would already be programmatic (thus
>>> intercept-able by the application).
>> Till these get into Qt5 we have to survive with some filters, and most
>> likely we will embed those into TextField and TextArea somehow. As said,
>> I cannot intercept the shortcuts at the moment outside of
>> TextInput/TextEdit.
> I thought you were suggesting a Clipboard API to put in Qt5 anyways,
> which would mean the ETA for both filters and the TextInput/TextEdit
> changes would likely be the same. This is definitely the sort of
> functionality which would fit better in QtQuick than each component
> set having an "API-Compatible" implementation.
We need this API now. So I was thinking to discuss an API that fits both
of us, so when QtQuick will have it we can drop ours from our libraries.

So: the API starts to look more like:

1. Because it would be beneficial to be able to push several mime types
at the same time
Clipboard {
    property MimeData data;
}

2. The MimeData would contain properties to get/set different mime data
types (we could actually derive this from QMimeData)
MimeData {
    readonly property list<string> formats
    property string data
    property string type
    // convenience properties to set certain types
    property string text - to get/set "text/plain"
    property string html - to get/set "text/html"
    property color color - to get/set color data
    property list<url> urls - to get/set urls
}

3. Clipboard shortcut handling should be doable on TextInput/TextEdit
level by simply handling Keys.onPressed attached signal (key codes:
Key_Cut, Key_Copy, Key_Paste)

How does this sound?

Zsombor




More information about the Qt-components mailing list