mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-13 05:46:59 -04:00
Add selectedItemPropertyFor(ToggleGroup)
This commit is contained in:
parent
86765275c8
commit
83f7e61d37
@ -91,9 +91,9 @@ public final class Accounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ObservableList<Account> accounts = observableArrayList(account -> new Observable[] { account });
|
private static ObservableList<Account> accounts = observableArrayList(account -> new Observable[] { account });
|
||||||
private static ReadOnlyListWrapper<Account> accountsWrapper = new ReadOnlyListWrapper<>(accounts);
|
private static ReadOnlyListWrapper<Account> accountsWrapper = new ReadOnlyListWrapper<>(Accounts.class, "accounts", accounts);
|
||||||
|
|
||||||
private static ObjectProperty<Account> selectedAccount = new SimpleObjectProperty<Account>() {
|
private static ObjectProperty<Account> selectedAccount = new SimpleObjectProperty<Account>(Accounts.class, "selectedAccount") {
|
||||||
{
|
{
|
||||||
accounts.addListener(onInvalidating(this::invalidated));
|
accounts.addListener(onInvalidating(this::invalidated));
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ import org.jackhuang.hmcl.util.*;
|
|||||||
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
||||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.javafx.SelectionModelSelectedItemProperty;
|
import org.jackhuang.hmcl.util.javafx.SelectedItemProperties;
|
||||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -348,7 +348,7 @@ public final class FXUtils {
|
|||||||
* @param comboBox the combo box being bound with {@code property}.
|
* @param comboBox the combo box being bound with {@code property}.
|
||||||
* @param property the property being bound with {@code combo box}.
|
* @param property the property being bound with {@code combo box}.
|
||||||
* @see #unbindEnum(JFXComboBox)
|
* @see #unbindEnum(JFXComboBox)
|
||||||
* @deprecated Use {@link SelectionModelSelectedItemProperty#selectedItemPropertyFor(ComboBox)}
|
* @deprecated Use {@link SelectedItemProperties#selectedItemPropertyFor(ComboBox)}
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -27,8 +27,8 @@ import javafx.scene.control.Control;
|
|||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
|
|
||||||
public abstract class ListPage<T extends Node> extends Control {
|
public abstract class ListPage<T extends Node> extends Control {
|
||||||
private final ListProperty<T> items = new SimpleListProperty<>(FXCollections.observableArrayList());
|
private final ListProperty<T> items = new SimpleListProperty<>(this, "items", FXCollections.observableArrayList());
|
||||||
private final BooleanProperty loading = new SimpleBooleanProperty(false);
|
private final BooleanProperty loading = new SimpleBooleanProperty(this, "loading", false);
|
||||||
|
|
||||||
public abstract void add();
|
public abstract void add();
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
import static org.jackhuang.hmcl.util.javafx.SelectionModelSelectedItemProperty.selectedItemPropertyFor;
|
import static org.jackhuang.hmcl.util.javafx.SelectedItemProperties.selectedItemPropertyFor;
|
||||||
|
|
||||||
public final class SettingsPage extends SettingsView implements DecoratorPage {
|
public final class SettingsPage extends SettingsView implements DecoratorPage {
|
||||||
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("settings.launcher"));
|
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("settings.launcher"));
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.javafx;
|
package org.jackhuang.hmcl.util.javafx;
|
||||||
|
|
||||||
import javafx.beans.InvalidationListener;
|
|
||||||
import javafx.beans.Observable;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@ -37,20 +35,6 @@ public final class MappedObservableList {
|
|||||||
private MappedObservableList() {
|
private MappedObservableList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReferenceHolder implements InvalidationListener {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private Object ref;
|
|
||||||
|
|
||||||
ReferenceHolder(Object ref) {
|
|
||||||
this.ref = ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidated(Observable observable) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MappedObservableListUpdater<T, U> implements ListChangeListener<T> {
|
private static class MappedObservableListUpdater<T, U> implements ListChangeListener<T> {
|
||||||
private ObservableList<T> origin;
|
private ObservableList<T> origin;
|
||||||
private ObservableList<U> target;
|
private ObservableList<U> target;
|
||||||
|
@ -36,6 +36,11 @@ public class ReadWriteComposedProperty<T> extends SimpleObjectProperty<T> {
|
|||||||
private ChangeListener<T> listener;
|
private ChangeListener<T> listener;
|
||||||
|
|
||||||
public ReadWriteComposedProperty(ObservableValue<T> readSource, Consumer<T> writeTarget) {
|
public ReadWriteComposedProperty(ObservableValue<T> readSource, Consumer<T> writeTarget) {
|
||||||
|
this(null, "", readSource, writeTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadWriteComposedProperty(Object bean, String name, ObservableValue<T> readSource, Consumer<T> writeTarget) {
|
||||||
|
super(bean, name);
|
||||||
this.readSource = readSource;
|
this.readSource = readSource;
|
||||||
this.writeTarget = writeTarget;
|
this.writeTarget = writeTarget;
|
||||||
|
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.util.javafx;
|
||||||
|
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
|
||||||
|
class ReferenceHolder implements InvalidationListener {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Object ref;
|
||||||
|
|
||||||
|
public ReferenceHolder(Object ref) {
|
||||||
|
this.ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidated(Observable observable) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.util.javafx;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.WeakInvalidationListener;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.SelectionModel;
|
||||||
|
import javafx.scene.control.Toggle;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yushijinhun
|
||||||
|
*/
|
||||||
|
public final class SelectedItemProperties {
|
||||||
|
|
||||||
|
private static final String PROP_PREFIX = SelectedItemProperties.class.getName();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> ObjectProperty<T> selectedItemPropertyFor(ComboBox<T> comboBox) {
|
||||||
|
return (ObjectProperty<T>) comboBox.getProperties().computeIfAbsent(
|
||||||
|
PROP_PREFIX + ".comboxBox.selectedItem",
|
||||||
|
any -> createPropertyForSelectionModel(comboBox, comboBox.selectionModelProperty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ObjectProperty<T> createPropertyForSelectionModel(Object bean, Property<? extends SelectionModel<T>> modelProperty) {
|
||||||
|
return new ReadWriteComposedProperty<>(bean, "extra.selectedItem",
|
||||||
|
MultiStepBinding.of(modelProperty)
|
||||||
|
.flatMap(SelectionModel::selectedItemProperty),
|
||||||
|
modelProperty.getValue()::select);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static ObjectProperty<Toggle> selectedTogglePropertyFor(ToggleGroup toggleGroup) {
|
||||||
|
return (ObjectProperty<Toggle>) toggleGroup.getProperties().computeIfAbsent(
|
||||||
|
PROP_PREFIX + ".toggleGroup.selectedToggle",
|
||||||
|
any -> createPropertyForToggleGroup(toggleGroup));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObjectProperty<Toggle> createPropertyForToggleGroup(ToggleGroup toggleGroup) {
|
||||||
|
return new ReadWriteComposedProperty<>(toggleGroup, "extra.selectedToggle",
|
||||||
|
toggleGroup.selectedToggleProperty(),
|
||||||
|
toggleGroup::selectToggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> ObjectProperty<T> selectedItemPropertyFor(ToggleGroup toggleGroup, Class<T> userdataType) {
|
||||||
|
return (ObjectProperty<T>) toggleGroup.getProperties().computeIfAbsent(
|
||||||
|
pair(PROP_PREFIX + ".toggleGroup.selectedItem", userdataType),
|
||||||
|
any -> createMappedPropertyForToggleGroup(
|
||||||
|
toggleGroup,
|
||||||
|
toggle -> toggle == null ? null : userdataType.cast(toggle.getUserData())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ObjectProperty<T> createMappedPropertyForToggleGroup(ToggleGroup toggleGroup, Function<Toggle, T> mapper) {
|
||||||
|
ObjectProperty<Toggle> selectedToggle = selectedTogglePropertyFor(toggleGroup);
|
||||||
|
AtomicReference<Optional<T>> pendingItemHolder = new AtomicReference<>();
|
||||||
|
|
||||||
|
Consumer<T> itemSelector = newItem -> {
|
||||||
|
Optional<Toggle> toggleToSelect = toggleGroup.getToggles().stream()
|
||||||
|
.filter(toggle -> Objects.equals(newItem, mapper.apply(toggle)))
|
||||||
|
.findFirst();
|
||||||
|
if (toggleToSelect.isPresent()) {
|
||||||
|
pendingItemHolder.set(null);
|
||||||
|
selectedToggle.set(toggleToSelect.get());
|
||||||
|
} else {
|
||||||
|
// We are asked to select an nonexistent item.
|
||||||
|
// However, this item may become available in the future.
|
||||||
|
// So here we store it, and once the associated toggle becomes available, we will update the selection.
|
||||||
|
pendingItemHolder.set(Optional.ofNullable(newItem));
|
||||||
|
selectedToggle.set(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ReadWriteComposedProperty<T> property = new ReadWriteComposedProperty<>(toggleGroup, "extra.selectedItem",
|
||||||
|
MultiStepBinding.of(selectedTogglePropertyFor(toggleGroup))
|
||||||
|
.map(mapper),
|
||||||
|
itemSelector);
|
||||||
|
|
||||||
|
InvalidationListener onTogglesChanged = any -> {
|
||||||
|
Optional<T> pendingItem = pendingItemHolder.get();
|
||||||
|
if (pendingItem != null) {
|
||||||
|
itemSelector.accept(pendingItem.orElse(null));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
toggleGroup.getToggles().addListener(new WeakInvalidationListener(onTogglesChanged));
|
||||||
|
property.addListener(new ReferenceHolder(onTogglesChanged));
|
||||||
|
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SelectedItemProperties() {
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher.
|
|
||||||
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
|
||||||
*/
|
|
||||||
package org.jackhuang.hmcl.util.javafx;
|
|
||||||
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
|
||||||
import javafx.beans.property.Property;
|
|
||||||
import javafx.scene.control.ComboBox;
|
|
||||||
import javafx.scene.control.SelectionModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author yushijinhun
|
|
||||||
*/
|
|
||||||
public final class SelectionModelSelectedItemProperty {
|
|
||||||
|
|
||||||
private static final String NODE_PROPERTY = SelectionModelSelectedItemProperty.class.getName() + ".instance";
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> ObjectProperty<T> selectedItemPropertyFor(ComboBox<T> comboBox) {
|
|
||||||
return (ObjectProperty<T>) comboBox.getProperties().computeIfAbsent(
|
|
||||||
NODE_PROPERTY,
|
|
||||||
any -> createSelectedItemProperty(comboBox.selectionModelProperty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> ObjectProperty<T> createSelectedItemProperty(Property<? extends SelectionModel<T>> modelProperty) {
|
|
||||||
return new ReadWriteComposedProperty<>(
|
|
||||||
MultiStepBinding.of(modelProperty)
|
|
||||||
.flatMap(SelectionModel::selectedItemProperty),
|
|
||||||
newValue -> modelProperty.getValue().select(newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
private SelectionModelSelectedItemProperty() {
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user