将 IconedTwoLineListItem#tags 的类型修改为 ObservableList<Label> (#4473)

This commit is contained in:
Glavo
2025-09-13 20:17:05 +08:00
committed by GitHub
parent 811b1fb5f4
commit e7526e39bf
11 changed files with 75 additions and 71 deletions

View File

@@ -10,6 +10,7 @@ import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
@@ -21,7 +22,7 @@ import org.jackhuang.hmcl.util.StringUtils;
public class IconedTwoLineListItem extends HBox { public class IconedTwoLineListItem extends HBox {
private final StringProperty title = new SimpleStringProperty(this, "title"); private final StringProperty title = new SimpleStringProperty(this, "title");
private final ObservableList<String> tags = FXCollections.observableArrayList(); private final ObservableList<Label> tags = FXCollections.observableArrayList();
private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle"); private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle");
private final StringProperty externalLink = new SimpleStringProperty(this, "externalLink"); private final StringProperty externalLink = new SimpleStringProperty(this, "externalLink");
private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image"); private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
@@ -62,7 +63,7 @@ public class IconedTwoLineListItem extends HBox {
this.title.set(title); this.title.set(title);
} }
public ObservableList<String> getTags() { public ObservableList<Label> getTags() {
return tags; return tags;
} }

View File

@@ -29,16 +29,22 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.AggregatedObservableList; import org.jackhuang.hmcl.util.AggregatedObservableList;
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
public class TwoLineListItem extends VBox { public class TwoLineListItem extends VBox {
private static final String DEFAULT_STYLE_CLASS = "two-line-list-item"; private static final String DEFAULT_STYLE_CLASS = "two-line-list-item";
public static Label createTagLabel(String tag) {
Label tagLabel = new Label();
tagLabel.getStyleClass().add("tag");
tagLabel.setText(tag);
HBox.setMargin(tagLabel, new Insets(0, 8, 0, 0));
return tagLabel;
}
private final StringProperty title = new SimpleStringProperty(this, "title"); private final StringProperty title = new SimpleStringProperty(this, "title");
private final ObservableList<String> tags = FXCollections.observableArrayList(); private final ObservableList<Label> tags = FXCollections.observableArrayList();
private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle"); private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle");
private final ObservableList<Node> tagLabels;
private final AggregatedObservableList<Node> firstLineChildren; private final AggregatedObservableList<Node> firstLineChildren;
public TwoLineListItem(String titleString, String subtitleString) { public TwoLineListItem(String titleString, String subtitleString) {
@@ -58,16 +64,9 @@ public class TwoLineListItem extends VBox {
lblTitle.getStyleClass().add("title"); lblTitle.getStyleClass().add("title");
lblTitle.textProperty().bind(title); lblTitle.textProperty().bind(title);
tagLabels = MappedObservableList.create(tags, tag -> {
Label tagLabel = new Label();
tagLabel.getStyleClass().add("tag");
tagLabel.setText(tag);
HBox.setMargin(tagLabel, new Insets(0, 8, 0, 0));
return tagLabel;
});
firstLineChildren = new AggregatedObservableList<>(); firstLineChildren = new AggregatedObservableList<>();
firstLineChildren.appendList(FXCollections.singletonObservableList(lblTitle)); firstLineChildren.appendList(FXCollections.singletonObservableList(lblTitle));
firstLineChildren.appendList(tagLabels); firstLineChildren.appendList(tags);
Bindings.bindContent(firstLine.getChildren(), firstLineChildren.getAggregatedList()); Bindings.bindContent(firstLine.getChildren(), firstLineChildren.getAggregatedList());
Label lblSubtitle = new Label(); Label lblSubtitle = new Label();
@@ -111,7 +110,11 @@ public class TwoLineListItem extends VBox {
this.subtitle.set(subtitle); this.subtitle.set(subtitle);
} }
public ObservableList<String> getTags() { public void addTag(String tag) {
getTags().add(createTagLabel(tag));
}
public ObservableList<Label> getTags() {
return tags; return tags;
} }

View File

@@ -229,27 +229,28 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
} else { } else {
twoLineListItem.setSubtitle(null); twoLineListItem.setSubtitle(null);
} }
twoLineListItem.getTags().clear();
if (remoteVersion instanceof GameRemoteVersion) { if (remoteVersion instanceof GameRemoteVersion) {
RemoteVersion.Type versionType = remoteVersion.getVersionType(); RemoteVersion.Type versionType = remoteVersion.getVersionType();
switch (versionType) { switch (versionType) {
case RELEASE: case RELEASE:
twoLineListItem.getTags().setAll(i18n("version.game.release")); twoLineListItem.addTag(i18n("version.game.release"));
imageView.setImage(VersionIconType.GRASS.getIcon()); imageView.setImage(VersionIconType.GRASS.getIcon());
break; break;
case PENDING: case PENDING:
case SNAPSHOT: case SNAPSHOT:
if (versionType == RemoteVersion.Type.SNAPSHOT if (versionType == RemoteVersion.Type.SNAPSHOT
&& GameVersionNumber.asGameVersion(remoteVersion.getGameVersion()).isAprilFools()) { && GameVersionNumber.asGameVersion(remoteVersion.getGameVersion()).isAprilFools()) {
twoLineListItem.getTags().setAll(i18n("version.game.april_fools")); twoLineListItem.addTag(i18n("version.game.april_fools"));
imageView.setImage(VersionIconType.APRIL_FOOLS.getIcon()); imageView.setImage(VersionIconType.APRIL_FOOLS.getIcon());
} else { } else {
twoLineListItem.getTags().setAll(i18n("version.game.snapshot")); twoLineListItem.addTag(i18n("version.game.snapshot"));
imageView.setImage(VersionIconType.COMMAND.getIcon()); imageView.setImage(VersionIconType.COMMAND.getIcon());
} }
break; break;
default: default:
twoLineListItem.getTags().setAll(i18n("version.game.old")); twoLineListItem.addTag(i18n("version.game.old"));
imageView.setImage(VersionIconType.CRAFT_TABLE.getIcon()); imageView.setImage(VersionIconType.CRAFT_TABLE.getIcon());
break; break;
} }
@@ -276,7 +277,7 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
if (twoLineListItem.getSubtitle() == null) if (twoLineListItem.getSubtitle() == null)
twoLineListItem.setSubtitle(remoteVersion.getGameVersion()); twoLineListItem.setSubtitle(remoteVersion.getGameVersion());
else else
twoLineListItem.getTags().setAll(remoteVersion.getGameVersion()); twoLineListItem.addTag(remoteVersion.getGameVersion());
} }
} }
} }

View File

@@ -250,9 +250,9 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
TwoLineListItem item = new TwoLineListItem(); TwoLineListItem item = new TwoLineListItem();
item.setTitle((java.isJDK() ? "JDK" : "JRE") + " " + java.getVersion()); item.setTitle((java.isJDK() ? "JDK" : "JRE") + " " + java.getVersion());
item.setSubtitle(java.getBinary().toString()); item.setSubtitle(java.getBinary().toString());
item.getTags().add(i18n("java.info.architecture") + ": " + java.getArchitecture().getDisplayName()); item.addTag(i18n("java.info.architecture") + ": " + java.getArchitecture().getDisplayName());
if (vendor != null) if (vendor != null)
item.getTags().add(i18n("java.info.vendor") + ": " + vendor); item.addTag(i18n("java.info.vendor") + ": " + vendor);
BorderPane.setAlignment(item, Pos.CENTER); BorderPane.setAlignment(item, Pos.CENTER);
center.getChildren().setAll(item); center.getChildren().setAll(item);
root.setCenter(center); root.setCenter(center);

View File

@@ -523,9 +523,9 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
// ListViewBehavior would consume ESC pressed event, preventing us from handling it, so we ignore it here // ListViewBehavior would consume ESC pressed event, preventing us from handling it, so we ignore it here
ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE); ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE);
listView.setCellFactory(x -> new FloatListCell<RemoteMod>(listView) { listView.setCellFactory(x -> new FloatListCell<>(listView) {
TwoLineListItem content = new TwoLineListItem(); private final TwoLineListItem content = new TwoLineListItem();
ImageView imageView = new ImageView(); private final ImageView imageView = new ImageView();
{ {
HBox container = new HBox(8); HBox container = new HBox(8);
@@ -542,10 +542,10 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(getSkinnable().repository.getType()).getModByCurseForgeId(dataItem.getSlug()); ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(getSkinnable().repository.getType()).getModByCurseForgeId(dataItem.getSlug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : dataItem.getTitle()); content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : dataItem.getTitle());
content.setSubtitle(dataItem.getDescription()); content.setSubtitle(dataItem.getDescription());
content.getTags().setAll(dataItem.getCategories().stream() content.getTags().clear();
dataItem.getCategories().stream()
.map(category -> getSkinnable().getLocalizedCategory(category)) .map(category -> getSkinnable().getLocalizedCategory(category))
.collect(Collectors.toList())); .forEach(content::addTag);
if (StringUtils.isNotBlank(dataItem.getIconUrl())) { if (StringUtils.isNotBlank(dataItem.getIconUrl())) {
imageView.imageProperty().bind(FXUtils.newRemoteImage(dataItem.getIconUrl(), 40, 40, true, true)); imageView.imageProperty().bind(FXUtils.newRemoteImage(dataItem.getIconUrl(), 40, 40, true, true));
} }

View File

@@ -228,9 +228,9 @@ public class DownloadPage extends Control implements DecoratorPage {
ModTranslations.Mod mod = getSkinnable().translations.getModByCurseForgeId(getSkinnable().addon.getSlug()); ModTranslations.Mod mod = getSkinnable().translations.getModByCurseForgeId(getSkinnable().addon.getSlug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : getSkinnable().addon.getTitle()); content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : getSkinnable().addon.getTitle());
content.setSubtitle(getSkinnable().addon.getDescription()); content.setSubtitle(getSkinnable().addon.getDescription());
content.getTags().setAll(getSkinnable().addon.getCategories().stream() getSkinnable().addon.getCategories().stream()
.map(category -> getSkinnable().page.getLocalizedCategory(category)) .map(category -> getSkinnable().page.getLocalizedCategory(category))
.collect(Collectors.toList())); .forEach(content::addTag);
descriptionPane.getChildren().add(content); descriptionPane.getChildren().add(content);
if (getSkinnable().mod != null) { if (getSkinnable().mod != null) {
@@ -353,10 +353,9 @@ public class DownloadPage extends Control implements DecoratorPage {
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug()); ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.getTitle()); content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.getTitle());
content.setSubtitle(addon.getDescription()); content.setSubtitle(addon.getDescription());
content.getTags().setAll(addon.getCategories().stream() addon.getCategories().stream()
.map(page::getLocalizedCategory) .map(page::getLocalizedCategory)
.collect(Collectors.toList())); .forEach(content::addTag);
if (StringUtils.isNotBlank(addon.getIconUrl())) { if (StringUtils.isNotBlank(addon.getIconUrl())) {
imageView.imageProperty().bind(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true)); imageView.imageProperty().bind(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true));
} }
@@ -389,15 +388,15 @@ public class DownloadPage extends Control implements DecoratorPage {
switch (dataItem.getVersionType()) { switch (dataItem.getVersionType()) {
case Alpha: case Alpha:
content.getTags().add(i18n("mods.channel.alpha")); content.addTag(i18n("mods.channel.alpha"));
graphicPane.getChildren().setAll(SVG.ALPHA_CIRCLE.createIcon(Theme.blackFill(), 24)); graphicPane.getChildren().setAll(SVG.ALPHA_CIRCLE.createIcon(Theme.blackFill(), 24));
break; break;
case Beta: case Beta:
content.getTags().add(i18n("mods.channel.beta")); content.addTag(i18n("mods.channel.beta"));
graphicPane.getChildren().setAll(SVG.BETA_CIRCLE.createIcon(Theme.blackFill(), 24)); graphicPane.getChildren().setAll(SVG.BETA_CIRCLE.createIcon(Theme.blackFill(), 24));
break; break;
case Release: case Release:
content.getTags().add(i18n("mods.channel.release")); content.addTag(i18n("mods.channel.release"));
graphicPane.getChildren().setAll(SVG.RELEASE_CIRCLE.createIcon(Theme.blackFill(), 24)); graphicPane.getChildren().setAll(SVG.RELEASE_CIRCLE.createIcon(Theme.blackFill(), 24));
break; break;
} }
@@ -405,22 +404,22 @@ public class DownloadPage extends Control implements DecoratorPage {
for (ModLoaderType modLoaderType : dataItem.getLoaders()) { for (ModLoaderType modLoaderType : dataItem.getLoaders()) {
switch (modLoaderType) { switch (modLoaderType) {
case FORGE: case FORGE:
content.getTags().add(i18n("install.installer.forge")); content.addTag(i18n("install.installer.forge"));
break; break;
case CLEANROOM: case CLEANROOM:
content.getTags().add(i18n("install.installer.cleanroom")); content.addTag(i18n("install.installer.cleanroom"));
break; break;
case NEO_FORGED: case NEO_FORGED:
content.getTags().add(i18n("install.installer.neoforge")); content.addTag(i18n("install.installer.neoforge"));
break; break;
case FABRIC: case FABRIC:
content.getTags().add(i18n("install.installer.fabric")); content.addTag(i18n("install.installer.fabric"));
break; break;
case LITE_LOADER: case LITE_LOADER:
content.getTags().add(i18n("install.installer.liteloader")); content.addTag(i18n("install.installer.liteloader"));
break; break;
case QUILT: case QUILT:
content.getTags().add(i18n("install.installer.quilt")); content.addTag(i18n("install.installer.quilt"));
break; break;
} }
} }

View File

@@ -47,11 +47,9 @@ public class GameItemSkin extends SkinBase<GameItem> {
TwoLineListItem item = new TwoLineListItem(); TwoLineListItem item = new TwoLineListItem();
item.titleProperty().bind(skinnable.titleProperty()); item.titleProperty().bind(skinnable.titleProperty());
FXUtils.onChangeAndOperate(skinnable.tagProperty(), tag -> { FXUtils.onChangeAndOperate(skinnable.tagProperty(), tag -> {
if (StringUtils.isNotBlank(tag)) {
item.getTags().setAll(tag);
} else {
item.getTags().clear(); item.getTags().clear();
} if (StringUtils.isNotBlank(tag))
item.addTag(tag);
}); });
item.subtitleProperty().bind(skinnable.subtitleProperty()); item.subtitleProperty().bind(skinnable.subtitleProperty());
BorderPane.setAlignment(item, Pos.CENTER); BorderPane.setAlignment(item, Pos.CENTER);

View File

@@ -395,7 +395,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
TwoLineListItem title = new TwoLineListItem(); TwoLineListItem title = new TwoLineListItem();
title.setTitle(modInfo.getModInfo().getName()); title.setTitle(modInfo.getModInfo().getName());
if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) {
title.getTags().setAll(modInfo.getModInfo().getVersion()); title.addTag(modInfo.getModInfo().getVersion());
} }
title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile())); title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile()));
@@ -442,9 +442,10 @@ class ModListPageSkin extends SkinBase<ModListPage> {
default: default:
continue; continue;
} }
List<String> tags = title.getTags(); if (title.getTags()
if (!tags.contains(loaderName)) { .stream()
tags.add(loaderName); .noneMatch(it -> it.getText().equals(loaderName))) {
title.addTag(loaderName);
} }
} }
@@ -551,26 +552,26 @@ class ModListPageSkin extends SkinBase<ModListPage> {
content.getTags().clear(); content.getTags().clear();
switch (dataItem.getModInfo().getModLoaderType()) { switch (dataItem.getModInfo().getModLoaderType()) {
case FORGE: case FORGE:
content.getTags().add(i18n("install.installer.forge")); content.addTag(i18n("install.installer.forge"));
break; break;
case CLEANROOM: case CLEANROOM:
content.getTags().add(i18n("install.installer.cleanroom")); content.addTag(i18n("install.installer.cleanroom"));
break; break;
case NEO_FORGED: case NEO_FORGED:
content.getTags().add(i18n("install.installer.neoforge")); content.addTag(i18n("install.installer.neoforge"));
break; break;
case FABRIC: case FABRIC:
content.getTags().add(i18n("install.installer.fabric")); content.addTag(i18n("install.installer.fabric"));
break; break;
case LITE_LOADER: case LITE_LOADER:
content.getTags().add(i18n("install.installer.liteloader")); content.addTag(i18n("install.installer.liteloader"));
break; break;
case QUILT: case QUILT:
content.getTags().add(i18n("install.installer.quilt")); content.addTag(i18n("install.installer.quilt"));
break; break;
} }
if (dataItem.getMod() != null && I18n.isUseChinese()) { if (dataItem.getMod() != null && I18n.isUseChinese()) {
content.getTags().add(dataItem.getMod().getDisplayName()); content.addTag(dataItem.getMod().getDisplayName());
} }
content.setSubtitle(dataItem.getSubtitle()); content.setSubtitle(dataItem.getSubtitle());
if (booleanProperty != null) { if (booleanProperty != null) {

View File

@@ -245,7 +245,8 @@ public final class WorldBackupsPage extends ListPageBase<WorldBackupsPage.Backup
item.setTitle(parseColorEscapes(skinnable.getBackupWorld().getWorldName())); item.setTitle(parseColorEscapes(skinnable.getBackupWorld().getWorldName()));
item.setSubtitle(formatDateTime(skinnable.getBackupTime()) + (skinnable.count == 0 ? "" : " (" + skinnable.count + ")")); item.setSubtitle(formatDateTime(skinnable.getBackupTime()) + (skinnable.count == 0 ? "" : " (" + skinnable.count + ")"));
if (world.getGameVersion() != null) item.getTags().add(world.getGameVersion()); if (world.getGameVersion() != null)
item.addTag(world.getGameVersion());
} }
{ {

View File

@@ -76,9 +76,9 @@ public final class WorldListItemSkin extends SkinBase<WorldListItem> {
item.setSubtitle(i18n("world.datetime", formatDateTime(Instant.ofEpochMilli(world.getLastPlayed())), world.getGameVersion() == null ? i18n("message.unknown") : world.getGameVersion())); item.setSubtitle(i18n("world.datetime", formatDateTime(Instant.ofEpochMilli(world.getLastPlayed())), world.getGameVersion() == null ? i18n("message.unknown") : world.getGameVersion()));
if (world.getGameVersion() != null) if (world.getGameVersion() != null)
item.getTags().add(world.getGameVersion()); item.addTag(world.getGameVersion());
if (world.isLocked()) if (world.isLocked())
item.getTags().add(i18n("world.locked")); item.addTag(i18n("world.locked"));
} }
{ {

View File

@@ -28,10 +28,10 @@ import java.util.function.Function;
public final class AggregatedObservableList<T> { public final class AggregatedObservableList<T> {
protected final List<ObservableList<T>> lists = new ArrayList<>(); private final List<ObservableList<? extends T>> lists = new ArrayList<>();
final private List<Integer> sizes = new ArrayList<>(); private final List<Integer> sizes = new ArrayList<>();
final private List<InternalListModificationListener> listeners = new ArrayList<>(); private final List<InternalListModificationListener> listeners = new ArrayList<>();
final protected ObservableList<T> aggregatedList = FXCollections.observableArrayList(); private final ObservableList<T> aggregatedList = FXCollections.observableArrayList();
public AggregatedObservableList() { public AggregatedObservableList() {
@@ -46,7 +46,7 @@ public final class AggregatedObservableList<T> {
return aggregatedList; return aggregatedList;
} }
public void appendList(@NotNull ObservableList<T> list) { public void appendList(@NotNull ObservableList<? extends T> list) {
assert !lists.contains(list) : "List is already contained: " + list; assert !lists.contains(list) : "List is already contained: " + list;
lists.add(list); lists.add(list);
final InternalListModificationListener listener = new InternalListModificationListener(list); final InternalListModificationListener listener = new InternalListModificationListener(list);
@@ -59,7 +59,7 @@ public final class AggregatedObservableList<T> {
"lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size(); "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size();
} }
public void prependList(@NotNull ObservableList<T> list) { public void prependList(@NotNull ObservableList<? extends T> list) {
assert !lists.contains(list) : "List is already contained: " + list; assert !lists.contains(list) : "List is already contained: " + list;
lists.add(0, list); lists.add(0, list);
final InternalListModificationListener listener = new InternalListModificationListener(list); final InternalListModificationListener listener = new InternalListModificationListener(list);
@@ -72,7 +72,7 @@ public final class AggregatedObservableList<T> {
"lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size(); "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size();
} }
public void removeList(@NotNull ObservableList<T> list) { public void removeList(@NotNull ObservableList<? extends T> list) {
assert lists.size() == sizes.size() && lists.size() == listeners.size() : assert lists.size() == sizes.size() && lists.size() == listeners.size() :
"lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size(); "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size() + " or not equal to listeners.size=" + listeners.size();
final int index = lists.indexOf(list); final int index = lists.indexOf(list);
@@ -98,7 +98,7 @@ public final class AggregatedObservableList<T> {
* @param list the list in question * @param list the list in question
* @return the start index of this list in the aggregated List * @return the start index of this list in the aggregated List
*/ */
private int getStartIndex(@NotNull ObservableList<T> list) { private int getStartIndex(@NotNull ObservableList<? extends T> list) {
int startIndex = 0; int startIndex = 0;
//System.out.println("=== searching startIndex of " + list); //System.out.println("=== searching startIndex of " + list);
assert lists.size() == sizes.size() : "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size(); assert lists.size() == sizes.size() : "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size();
@@ -120,7 +120,7 @@ public final class AggregatedObservableList<T> {
* @param startIndex the start of the list (retrieve with {@link #getStartIndex(ObservableList)} * @param startIndex the start of the list (retrieve with {@link #getStartIndex(ObservableList)}
* @return the end index of this list in the aggregated List * @return the end index of this list in the aggregated List
*/ */
private int getEndIndex(@NotNull ObservableList<T> list, int startIndex) { private int getEndIndex(@NotNull ObservableList<? extends T> list, int startIndex) {
assert lists.size() == sizes.size() : "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size(); assert lists.size() == sizes.size() : "lists.size=" + lists.size() + " not equal to sizes.size=" + sizes.size();
final int index = lists.indexOf(list); final int index = lists.indexOf(list);
return startIndex + sizes.get(index) - 1; return startIndex + sizes.get(index) - 1;
@@ -129,9 +129,9 @@ public final class AggregatedObservableList<T> {
private final class InternalListModificationListener implements ListChangeListener<T> { private final class InternalListModificationListener implements ListChangeListener<T> {
@NotNull @NotNull
private final ObservableList<T> list; private final ObservableList<? extends T> list;
public InternalListModificationListener(@NotNull ObservableList<T> list) { public InternalListModificationListener(@NotNull ObservableList<? extends T> list) {
this.list = list; this.list = list;
} }