diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/ListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/ListPage.java index 3c2fcb11e..2c2fa98a8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/ListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/ListPage.java @@ -22,6 +22,7 @@ import javafx.beans.property.ListProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleListProperty; import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.control.Control; import javafx.scene.control.Skin; @@ -32,16 +33,32 @@ public abstract class ListPage extends Control { public abstract void add(); + @Override + protected Skin createDefaultSkin() { + return new ListPageSkin(this); + } + + public ObservableList getItems() { + return items.get(); + } + + public void setItems(ObservableList items) { + this.items.set(items); + } + public ListProperty itemsProperty() { return items; } + public boolean isLoading() { + return loading.get(); + } + + public void setLoading(boolean loading) { + this.loading.set(loading); + } + public BooleanProperty loadingProperty() { return loading; } - - @Override - protected Skin createDefaultSkin() { - return new ListPageSkin(this); - } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java index 9515a5883..5376e00a8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java @@ -19,48 +19,22 @@ package org.jackhuang.hmcl.ui.account; import javafx.beans.property.*; import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.control.ToggleGroup; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.ListPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.util.javafx.MappedObservableList; - -import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.javafx.SelectedItemProperties.createSelectedItemPropertyFor; public class AccountList extends ListPage implements DecoratorPage { - private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(i18n("account.manage")); - private ObjectProperty selectedAccount = new SimpleObjectProperty() { - { - itemsProperty().addListener(onInvalidating(this::invalidated)); - } - - @Override - protected void invalidated() { - Account selected = get(); - itemsProperty().forEach(item -> item.selectedProperty().set(item.getAccount() == selected)); - } - }; - private final ListProperty accounts = new SimpleListProperty<>(FXCollections.observableArrayList()); - - private ToggleGroup toggleGroup; - private final ObservableList accountItems; + private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.manage")); + private final ListProperty accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList()); + private final ObjectProperty selectedAccount; public AccountList() { - toggleGroup = new ToggleGroup(); - - accountItems = MappedObservableList.create( - accountsProperty(), - account -> new AccountListItem(toggleGroup, account)); - - itemsProperty().bindContent(accountItems); - - toggleGroup.selectedToggleProperty().addListener((o, a, toggle) -> { - if (toggle == null || toggle.getUserData() == null) return; - selectedAccount.set(((AccountListItem) toggle.getUserData()).getAccount()); - }); + setItems(MappedObservableList.create(accounts, AccountListItem::new)); + selectedAccount = createSelectedItemPropertyFor(getItems(), Account.class); } public ObjectProperty selectedAccountProperty() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java index 6f721b084..3c660da0b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java @@ -18,9 +18,8 @@ package org.jackhuang.hmcl.ui.account; import javafx.beans.property.*; -import javafx.scene.control.Control; import javafx.scene.control.Skin; -import javafx.scene.control.ToggleGroup; +import javafx.scene.control.ToggleButton; import javafx.scene.image.Image; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount; @@ -33,17 +32,17 @@ import org.jackhuang.hmcl.task.Schedulers; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class AccountListItem extends Control { +public class AccountListItem extends ToggleButton { + private final Account account; - private final ToggleGroup toggleGroup; private final StringProperty title = new SimpleStringProperty(); private final StringProperty subtitle = new SimpleStringProperty(); - private final BooleanProperty selected = new SimpleBooleanProperty(); private final ObjectProperty image = new SimpleObjectProperty<>(); - public AccountListItem(ToggleGroup toggleGroup, Account account) { + public AccountListItem(Account account) { this.account = account; - this.toggleGroup = toggleGroup; + getStyleClass().clear(); + setUserData(account); StringBuilder subtitleString = new StringBuilder(Accounts.getAccountTypeName(account)); if (account instanceof AuthlibInjectorAccount) { @@ -56,7 +55,6 @@ public class AccountListItem extends Control { else title.set(account.getUsername() + " - " + account.getCharacter()); subtitle.set(subtitleString.toString()); - selected.set(Accounts.selectedAccountProperty().get() == account); final int scaleRatio = 4; Image image = account instanceof YggdrasilAccount ? @@ -70,30 +68,6 @@ public class AccountListItem extends Control { return new AccountListItemSkin(this); } - public ToggleGroup getToggleGroup() { - return toggleGroup; - } - - public Account getAccount() { - return account; - } - - public StringProperty titleProperty() { - return title; - } - - public StringProperty subtitleProperty() { - return subtitle; - } - - public BooleanProperty selectedProperty() { - return selected; - } - - public ObjectProperty imageProperty() { - return image; - } - public void refresh() { if (account instanceof YggdrasilAccount) { // progressBar.setVisible(true); @@ -113,4 +87,44 @@ public class AccountListItem extends Control { public void remove() { Accounts.getAccounts().remove(account); } + + public Account getAccount() { + return account; + } + + public String getTitle() { + return title.get(); + } + + public void setTitle(String title) { + this.title.set(title); + } + + public StringProperty titleProperty() { + return title; + } + + public String getSubtitle() { + return subtitle.get(); + } + + public void setSubtitle(String subtitle) { + this.subtitle.set(subtitle); + } + + public StringProperty subtitleProperty() { + return subtitle; + } + + public Image getImage() { + return image.get(); + } + + public void setImage(Image image) { + this.image.set(image); + } + + public ObjectProperty imageProperty() { + return image; + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java index b4713b3dc..954f4da88 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java @@ -43,9 +43,7 @@ public class AccountListItemSkin extends SkinBase { JFXRadioButton chkSelected = new JFXRadioButton(); BorderPane.setAlignment(chkSelected, Pos.CENTER); - chkSelected.setUserData(skinnable); chkSelected.selectedProperty().bindBidirectional(skinnable.selectedProperty()); - chkSelected.setToggleGroup(skinnable.getToggleGroup()); root.setLeft(chkSelected); HBox center = new HBox(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/AutomatedToggleGroup.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/AutomatedToggleGroup.java new file mode 100644 index 000000000..2216a3a1e --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/AutomatedToggleGroup.java @@ -0,0 +1,51 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2018 huangyuhui + * + * 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.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; + +/** + * @author yushijinhun + */ +public class AutomatedToggleGroup extends ToggleGroup { + + private final ObservableList toggles; + private final ListChangeListener listListener; + + public AutomatedToggleGroup(ObservableList toggles) { + this.toggles = toggles; + + listListener = change -> { + while (change.next()) { + change.getRemoved().forEach(it -> it.setToggleGroup(null)); + change.getAddedSubList().forEach(it -> it.setToggleGroup(this)); + } + }; + toggles.addListener(listListener); + + toggles.forEach(it -> it.setToggleGroup(this)); + } + + public void disconnect() { + toggles.removeListener(listListener); + toggles.forEach(it -> it.setToggleGroup(null)); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/SelectedItemProperties.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/SelectedItemProperties.java index a84cad264..7abd3689c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/SelectedItemProperties.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/SelectedItemProperties.java @@ -29,6 +29,7 @@ import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.beans.property.ObjectProperty; import javafx.beans.property.Property; +import javafx.collections.ObservableList; import javafx.scene.control.ComboBox; import javafx.scene.control.SelectionModel; import javafx.scene.control.Toggle; @@ -41,6 +42,7 @@ public final class SelectedItemProperties { private static final String PROP_PREFIX = SelectedItemProperties.class.getName(); + // ==== ComboBox ==== @SuppressWarnings("unchecked") public static ObjectProperty selectedItemPropertyFor(ComboBox comboBox) { return (ObjectProperty) comboBox.getProperties().computeIfAbsent( @@ -54,7 +56,9 @@ public final class SelectedItemProperties { .flatMap(SelectionModel::selectedItemProperty), modelProperty.getValue()::select); } + // ==== + // ==== Toggle ==== @SuppressWarnings("unchecked") public static ObjectProperty selectedTogglePropertyFor(ToggleGroup toggleGroup) { return (ObjectProperty) toggleGroup.getProperties().computeIfAbsent( @@ -68,6 +72,10 @@ public final class SelectedItemProperties { toggleGroup::selectToggle); } + public static ObjectProperty createSelectedItemPropertyFor(ObservableList items, Class userdataType) { + return selectedItemPropertyFor(new AutomatedToggleGroup(items), userdataType); + } + @SuppressWarnings("unchecked") public static ObjectProperty selectedItemPropertyFor(ToggleGroup toggleGroup, Class userdataType) { return (ObjectProperty) toggleGroup.getProperties().computeIfAbsent( @@ -113,6 +121,7 @@ public final class SelectedItemProperties { return property; } + // ==== private SelectedItemProperties() { }