On Sun, 9 Apr 2023 20:23:55 GMT, John Hendrikx <[email protected]> wrote:
> With the preferences Map, this could work similar perhaps; set a key to
> whatever you want with put, and restore it to its original value by setting
> it to null.
That's how the current API works, with a little bit of added complexity:
interface Preferences {
...
/**
* Overrides the value of the {@link #appearanceProperty() appearance}
property.
* <p>
* Specifying {@code null} clears the override, which restores the value of
the
* {@code appearance} property to the platform-provided value.
* <p>
* Calling this method does not update the {@code appearance} property
instantaneously;
* instead, the property is only updated after calling {@link #commit()},
or after the
* occurrence of an operating system event that causes the {@code
appearance} property
* to be recomputed.
*
* @param appearance the platform appearance override, or {@code null} to
clear the override
*/
void setAppearance(Appearance appearance);
...
/**
* Overrides a key-value mapping.
* <p>
* If a platform-provided mapping for the key already exists, calling this
method overrides
* the value that is mapped to the key. If a platform-provided mapping for
the key doesn't
* exist, this method creates a new mapping.
* <p>
* Specifying a {@code null} value clears the override, which restores the
value mapped to
* the key to the platform-provided value. If the platform does not provide
a mapping for
* the specified key, the mapping is effectively removed.
* <p>
* Calling this method does not update the mapping instantaneously;
instead, the mapping
* is only updated after calling {@link #commit()}, or after the occurrence
of an operating
* system event that causes the mapped value to be recomputed.
*
* @param key the key
* @param value the new value, or {@code null} to clear the override
* @throws NullPointerException if {@code key} is null
* @throws IllegalArgumentException if a platform-provided mapping for the
key exists, and
* the specified value is an instance of a
different class
* than the platform-provided value
* @return the previous value associated with {@code key}
*/
<T> T override(String key, T value);
/**
* Commits outstanding overridden preferences, which also causes the values
of derived
* properties to be recomputed.
*/
void commit();
}
It is very likely the case that changing preferences can lead to very expensive
operations in large real-world applications. For example, style themes or the
entire user interface may be recreated, icons/images may be loaded, etc.
The `Preferences` implementation accounts for this by firing only a single
invalidation notification, even when multiple platform preferences have
changed. The documentation of `Preferences` contains guidance for users of this
API:
* @implNote In many cases, multiple platform preferences can change at the
same time.
* For example, switching from light to dark mode changes various
foreground elements to light
* colors, and various background elements to dark colors.
* <p>
* The {@code Preferences} implementation returned from this
method fires a single invalidation
* event for such bulk changes. If a listener performs
potentially heavy work, such as recreating
* and applying CSS themes, it might be beneficial to use {@link
javafx.beans.InvalidationListener}
* instead of {@link javafx.collections.MapChangeListener} to
prevent the listener from firing
* multiple times in bulk change scenarios.
This works when the changes originate from the OS, but it doesn't work when an
application overrides preference mappings manually. `ObservableMap` doesn't
support bulk changes, so repeatedly calling `override(...)` would end up firing
multiple change notifications, and subscribers would have no way of knowing
when the bulk change transaction has ended.
That's where the concept of _uncommitted modifications_ comes into play:
calling `override(...)` or any of the property setters like
`setAppearance(...)` doesn't apply the changes immediately, it delays those
changes until `commit()` is called or until an OS event causes the preference
to be recomputed. When that happens, a single invalidation notification is
fired, the same as it would have if the change originated from the OS.
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1014#issuecomment-1502081527