RFR: 8301302: Platform preferences API [v3]
Michael Strauß
mstrauss at openjdk.org
Mon Jul 24 17:45:36 UTC 2023
On Thu, 2 Feb 2023 19:54:33 GMT, Michael Strauß <mstrauss at openjdk.org> wrote:
>> Please read [this document](https://gist.github.com/mstr2/9f46f92c98d3c86aa6a0b4224a9a6548) for an introduction to the Platform Preferences API, and how it interacts with the proposed style theme and stage appearance features.
>
> Michael Strauß has updated the pull request with a new target base due to a merge or a rebase.
In general, platform preferences correspond to OS-level settings and are updated dynamically. Third-party themes might integrate platform preferences into their look and feel, which is often what users expect to see. But consider a scenario where an application uses a third-party theme that adapts to the OS appearance, but the application author only wants to support a dark appearance (independent from the OS appearance).
For this scenario, platform preferences should be overridable from application code. I've considered several potential approaches:
#### 1. Provide two sets of preferences:
class Platform {
Preferences getUserPreferences();
Preferences getPlatformPreferences();
}
In this idea, `getUserPreferences` returns a mutable version of the immutable `getPlatformPreferences`. However, this requires theme authors to always use user preferences instead of platform preferences (or combine both); if they fail to do so, application authors are out of luck.
#### 2. Add a separate, overridable property for each of the convenience API properties:
interface Preferences {
...
ReadOnlyObjectProperty<Appearance> appearanceProperty();
ObjectProperty<Appearance> appearanceOverrideProperty();
...
}
The value of the read-only `appearanceProperty()` then corresponds to the value of `appearanceOverrideProperty()` if the property is set to a non-null value. Otherwise, it corresponds to the platform-provided value.
#### 3. Add a special setter for each of the convenience API properties:
interface Preferences {
...
ReadOnlyObjectProperty<Appearance> appearanceProperty();
void setAppearance(Appearance appearance);
...
}
The `setAppearance` method can be used to _override_ the value of `appearanceProperty()`. When `null` is passed into this method, the platform default value is restored (or, put differently, the override is cleared). There is some precedence in JavaFX for a "special setter" pattern: for example, while the `Stage.widthProperty()` is read-only, `Stage.setWidth` is a special setter that attempts to set the stage width to the specified value (and may fail to do so).
I prefer the third option (the special setter), as it seems to be the cleanest approach that doesn't unnecessarily expand the API.
I think I've come around to the idea of dropping the `override` method in favor of `put`. However, I don't like the idea of using `put("key", null)` to reset an overridden mapping to its default value. Having "reset" be its own operation seems to work quite well, though:
interface Preferences extends ObservableMap<String, Object> {
...
/**
* Overrides a preference 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.
*
* @param key the key
* @param value the new value
* @throws NullPointerException if {@code key} or {@code value} 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}
*/
Object put(String key, Object value);
/**
* Resets an overridden preference mapping to its platform-provided value.
* <p>
* If the preference is overridden, but the platform does not provide a mapping for the
* specified key, the mapping will be removed. If no mapping exists for the specified
* key, calling this method has no effect.
*
* @param key the key
* @throws NullPointerException if {@code key} is null
*/
void reset(String key);
/**
* Resets all overridden preference mappings to their platform-provided values and removes
* all mappings for which the platform does not provide a default value.
*/
void reset();
}
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1014#issuecomment-1501177237
PR Comment: https://git.openjdk.org/jfx/pull/1014#issuecomment-1531375810
More information about the openjfx-dev
mailing list