mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-02-05 16:44:47 +08: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 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));
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ import org.jackhuang.hmcl.util.*;
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
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 java.io.File;
|
||||
@ -348,7 +348,7 @@ public final class FXUtils {
|
||||
* @param comboBox the combo box being bound with {@code property}.
|
||||
* @param property the property being bound with {@code combo box}.
|
||||
* @see #unbindEnum(JFXComboBox)
|
||||
* @deprecated Use {@link SelectionModelSelectedItemProperty#selectedItemPropertyFor(ComboBox)}
|
||||
* @deprecated Use {@link SelectedItemProperties#selectedItemPropertyFor(ComboBox)}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
|
@ -27,8 +27,8 @@ import javafx.scene.control.Control;
|
||||
import javafx.scene.control.Skin;
|
||||
|
||||
public abstract class ListPage<T extends Node> extends Control {
|
||||
private final ListProperty<T> items = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||
private final BooleanProperty loading = new SimpleBooleanProperty(false);
|
||||
private final ListProperty<T> items = new SimpleListProperty<>(this, "items", FXCollections.observableArrayList());
|
||||
private final BooleanProperty loading = new SimpleBooleanProperty(this, "loading", false);
|
||||
|
||||
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.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 {
|
||||
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("settings.launcher"));
|
||||
|
@ -17,8 +17,6 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.javafx;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
@ -37,20 +35,6 @@ public final class 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 ObservableList<T> origin;
|
||||
private ObservableList<U> target;
|
||||
|
@ -36,6 +36,11 @@ public class ReadWriteComposedProperty<T> extends SimpleObjectProperty<T> {
|
||||
private ChangeListener<T> listener;
|
||||
|
||||
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.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…
Reference in New Issue
Block a user