[Development] Qt Quick Controls Dialogs -- enabled state of the standard buttons (API choices)

Vladimir Moolle vmoolle at ics.com
Sat Aug 22 01:22:51 CEST 2015


Hi, I’d like to discuss approaches to API design in the context of
https://bugreports.qt.io/browse/QTBUG-47850 (making Quick Controls dialogs’
standard buttons’ enabled properly state accessible).

It seems, that the desired properties of an API implementing the above
would be:
possibility to declaratively manipulate enabled-ness of the buttons
lack of risks brought by “signal races” (usually happens when imperative
and declarative code is mixed)
optionally, possibility to tweak more than just the “enabled” property of
the buttons (at least the API could allow for such extension in the future).

Below are some approaches coming to mind (after a discussion we had with
colleagues):

1. A getter method on Dialog, more or less duplicating that of the QDialog.
Pros are the API (and the patch implementing it) being trivial. Cons are
necessity to call the getter only after the button is created (by otherwise
declarative code) and complexities of button lifetime tracking.

2. A set of applyEnabled, helpEnabled, … properties on the Dialog. Pros is
being declarative and API simplicity, cons is the obvious verbosity
(especially, if more properties are exposed this way later).

3. An enabledButtons (disabledButtons? disabledStandardButtons?
enabledStandardButtons??) property containing an ORed set of button roles
(just like the standardButtons property). Pros are things being
declarative, and uniform, cons -- that crafting a binding expression for
more than a couple buttons may get ugly (and listening  / responding to
changes through the single QML signal handler may require having a signal
parameter matching the old / previous state of the ORed enum combo -- which
is strange; note: something close is discussed by
https://bugreports.qt.io/browse/QTBUG-40868?focusedCommentId=253265)

4. An auxiliary object can be used to make the buttons accessible
declaratively:
Dialog {
    StandardButtonProxy {
        id: okProxy
        role: StandardButton.Ok
        Binding {
             target: okProxy.button // here it is
             property: “enabled”
             value: <some binding expression>
        }
    }
}
Pros of this approach would be its simplicity (on both API and
implementation sides), and relative safety (the “button” property would be
null when the button is not there, incl. temporarily -- i.e. during button
model reorganizations, etc.), cons -- that it would be merely a means to
expose standard buttons “the QML way”, not addressing the fact that
exposing control instances from underneath may not be the best practice by
itself (and especially in QML, where a smart user may try to save the
reference, thus confusing the GC).

5. A special ButtonState object type serving as “declarative proxy” for the
button’s properties, i.e.:
Dialog {
    <...>
    ButtonState {
        role: StandardButton.Ok
        enabled: <some binding expression>
    }
}
Pros of this approach would be “proper” declarativity, and ability to
easily extend the exposed property set (adding possibility to override
other properties other than “enabled”), cons would be limiting further API
changes in this area to being based on this one-way “reflect my properties”
approach (and making some bindings track the state of the button by default
would complicate things beyond reasonable).

6. Finally, Dialog could accept (optional) delegates for the buttons
created, allowing for arbitrary customizations, i.e.:
Dialog {
    <...>
    StandardButtonDelegate {       //name arguably could be better
        role: StandardButton.Apply // could be “roles” here even
        StandardButton {           // a Button, but with default bindings
for “text”, etc.
            enabled: <some binding expression>
        }
    }
    StandardButtonDelegate {       //name arguably could be better
        role: StandardButton.Apply // could be “roles” here even
        Rectangle {                // a very custom “button”
       <...>
            signal clicked         // or a warning emitted by Dialog if
absent
            enabled: <some binding expression>
        }
    }
}
The pros of this approach would be the possibility to customize the buttons
(standard or not) freely, including styling, overriding text (when / if
necessary) etc., while being fully declarative.

This way, the Dialog only does button management (i.e. platform-specific
layout, creation and destruction), but the aspect of button’s behavior is
completely separated (providing for a nice separation of concerns), and
there’re no API bottlenecks like proxy property bags (#5 above) and so on.
An obvious con would be ease of breaking layouts with geometry bindings  /
anchors specified for the button (unless specifically addressed (and unset)
by Dialog’s logic).

Overall, approaches #5 and #6 seem to attract more sympathy among those who
discussed the API decisions in question here internally. What would you
guys say (most importantly, Qt Quick Controls patch reviewers, but everyone
else interested as well)?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20150822/bcc78be6/attachment.html>


More information about the Development mailing list