Add AutomatedToggleGroup & Refactor AccountList

This commit is contained in:
yushijinhun 2018-10-01 20:39:00 +08:00
parent 83f7e61d37
commit 7da5b8fbc8
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4
6 changed files with 134 additions and 71 deletions

View File

@ -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<T extends Node> extends Control {
public abstract void add();
@Override
protected Skin<?> createDefaultSkin() {
return new ListPageSkin(this);
}
public ObservableList<T> getItems() {
return items.get();
}
public void setItems(ObservableList<T> items) {
this.items.set(items);
}
public ListProperty<T> 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);
}
}

View File

@ -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<AccountListItem> implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(i18n("account.manage"));
private ObjectProperty<Account> selectedAccount = new SimpleObjectProperty<Account>() {
{
itemsProperty().addListener(onInvalidating(this::invalidated));
}
@Override
protected void invalidated() {
Account selected = get();
itemsProperty().forEach(item -> item.selectedProperty().set(item.getAccount() == selected));
}
};
private final ListProperty<Account> accounts = new SimpleListProperty<>(FXCollections.observableArrayList());
private ToggleGroup toggleGroup;
private final ObservableList<AccountListItem> accountItems;
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.manage"));
private final ListProperty<Account> accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList());
private final ObjectProperty<Account> 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<Account> selectedAccountProperty() {

View File

@ -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> 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<Image> 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<Image> imageProperty() {
return image;
}
}

View File

@ -43,9 +43,7 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
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();

View File

@ -0,0 +1,51 @@
/*
* 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.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<? extends Toggle> toggles;
private final ListChangeListener<Toggle> listListener;
public AutomatedToggleGroup(ObservableList<? extends Toggle> 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));
}
}

View File

@ -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 <T> ObjectProperty<T> selectedItemPropertyFor(ComboBox<T> comboBox) {
return (ObjectProperty<T>) comboBox.getProperties().computeIfAbsent(
@ -54,7 +56,9 @@ public final class SelectedItemProperties {
.flatMap(SelectionModel::selectedItemProperty),
modelProperty.getValue()::select);
}
// ====
// ==== Toggle ====
@SuppressWarnings("unchecked")
public static ObjectProperty<Toggle> selectedTogglePropertyFor(ToggleGroup toggleGroup) {
return (ObjectProperty<Toggle>) toggleGroup.getProperties().computeIfAbsent(
@ -68,6 +72,10 @@ public final class SelectedItemProperties {
toggleGroup::selectToggle);
}
public static <T> ObjectProperty<T> createSelectedItemPropertyFor(ObservableList<? extends Toggle> items, Class<T> userdataType) {
return selectedItemPropertyFor(new AutomatedToggleGroup(items), userdataType);
}
@SuppressWarnings("unchecked")
public static <T> ObjectProperty<T> selectedItemPropertyFor(ToggleGroup toggleGroup, Class<T> userdataType) {
return (ObjectProperty<T>) toggleGroup.getProperties().computeIfAbsent(
@ -113,6 +121,7 @@ public final class SelectedItemProperties {
return property;
}
// ====
private SelectedItemProperties() {
}