Add selectedMinecraftVersion

This commit is contained in:
huangyuhui 2018-08-30 22:09:05 +08:00
parent 9c149f3529
commit 1566e069ed
4 changed files with 153 additions and 45 deletions

View File

@ -19,14 +19,18 @@ package org.jackhuang.hmcl.setting;
import com.google.gson.*; import com.google.gson.*;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.*;
import javafx.beans.property.SimpleBooleanProperty;
import org.jackhuang.hmcl.event.EventBus;
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
import org.jackhuang.hmcl.game.HMCLDependencyManager; import org.jackhuang.hmcl.game.HMCLDependencyManager;
import org.jackhuang.hmcl.game.HMCLGameRepository; import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.ui.WeakListenerHelper;
import org.jackhuang.hmcl.util.ImmediateObjectProperty; import org.jackhuang.hmcl.util.ImmediateObjectProperty;
import org.jackhuang.hmcl.util.ImmediateStringProperty; import org.jackhuang.hmcl.util.ImmediateStringProperty;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.ToStringBuilder; import org.jackhuang.hmcl.util.ToStringBuilder;
import java.io.File; import java.io.File;
@ -38,66 +42,80 @@ import java.util.Optional;
* @author huangyuhui * @author huangyuhui
*/ */
public final class Profile { public final class Profile {
private final WeakListenerHelper helper = new WeakListenerHelper();
private final HMCLGameRepository repository; private final HMCLGameRepository repository;
private final ModManager modManager; private final ModManager modManager;
private final ImmediateObjectProperty<File> gameDirProperty; private final StringProperty selectedVersion = new SimpleStringProperty();
public ImmediateObjectProperty<File> gameDirProperty() { public StringProperty selectedVersionProperty() {
return gameDirProperty; return selectedVersion;
}
public String getSelectedVersion() {
return selectedVersion.get();
}
public void setSelectedVersion(String selectedVersion) {
this.selectedVersion.set(selectedVersion);
}
private final ObjectProperty<File> gameDir;
public ObjectProperty<File> gameDirProperty() {
return gameDir;
} }
public File getGameDir() { public File getGameDir() {
return gameDirProperty.get(); return gameDir.get();
} }
public void setGameDir(File gameDir) { public void setGameDir(File gameDir) {
gameDirProperty.set(gameDir); this.gameDir.set(gameDir);
} }
private final ImmediateObjectProperty<VersionSetting> globalProperty = new ImmediateObjectProperty<>(this, "global", new VersionSetting()); private final ObjectProperty<VersionSetting> global = new ImmediateObjectProperty<>(this, "global", new VersionSetting());
public ImmediateObjectProperty<VersionSetting> globalProperty() { public ObjectProperty<VersionSetting> globalProperty() {
return globalProperty; return global;
} }
public VersionSetting getGlobal() { public VersionSetting getGlobal() {
return globalProperty.get(); return global.get();
} }
private void setGlobal(VersionSetting global) { private void setGlobal(VersionSetting global) {
if (global == null) if (global == null)
global = new VersionSetting(); global = new VersionSetting();
globalProperty.set(global); this.global.set(global);
} }
private final ImmediateStringProperty nameProperty; private final ImmediateStringProperty name;
public ImmediateStringProperty nameProperty() { public ImmediateStringProperty nameProperty() {
return nameProperty; return name;
} }
public String getName() { public String getName() {
return nameProperty.get(); return name.get();
} }
public void setName(String name) { public void setName(String name) {
nameProperty.set(name); this.name.set(name);
} }
private BooleanProperty useRelativePathProperty = new SimpleBooleanProperty(this, "useRelativePath", false); private BooleanProperty useRelativePath = new SimpleBooleanProperty(this, "useRelativePath", false);
public BooleanProperty useRelativePathProperty() { public BooleanProperty useRelativePathProperty() {
return useRelativePathProperty(); return useRelativePath;
} }
public boolean isUseRelativePath() { public boolean isUseRelativePath() {
return useRelativePathProperty.get(); return useRelativePath.get();
} }
public void setUseRelativePath(boolean useRelativePath) { public void setUseRelativePath(boolean useRelativePath) {
useRelativePathProperty.set(useRelativePath); this.useRelativePath.set(useRelativePath);
} }
public Profile(String name) { public Profile(String name) {
@ -105,12 +123,26 @@ public final class Profile {
} }
public Profile(String name, File initialGameDir) { public Profile(String name, File initialGameDir) {
nameProperty = new ImmediateStringProperty(this, "name", name); this.name = new ImmediateStringProperty(this, "name", name);
gameDirProperty = new ImmediateObjectProperty<>(this, "gameDir", initialGameDir); gameDir = new ImmediateObjectProperty<>(this, "gameDir", initialGameDir);
repository = new HMCLGameRepository(this, initialGameDir); repository = new HMCLGameRepository(this, initialGameDir);
modManager = new ModManager(repository); modManager = new ModManager(repository);
gameDirProperty.addListener((a, b, newValue) -> repository.changeDirectory(newValue)); gameDir.addListener((a, b, newValue) -> repository.changeDirectory(newValue));
selectedVersion.addListener(o -> checkSelectedVersion());
helper.add(EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> checkSelectedVersion()));
}
private void checkSelectedVersion() {
if (!repository.isLoaded()) return;
String newValue = selectedVersion.get();
if (!repository.hasVersion(newValue)) {
Optional<String> version = repository.getVersions().stream().findFirst().map(Version::getId);
if (version.isPresent())
selectedVersion.setValue(version.get());
else if (StringUtils.isNotBlank(newValue))
selectedVersion.setValue(null);
}
} }
public HMCLGameRepository getRepository() { public HMCLGameRepository getRepository() {
@ -171,11 +203,12 @@ public final class Profile {
} }
public void addPropertyChangedListener(InvalidationListener listener) { public void addPropertyChangedListener(InvalidationListener listener) {
nameProperty.addListener(listener); name.addListener(listener);
globalProperty.addListener(listener); global.addListener(listener);
gameDirProperty.addListener(listener); gameDir.addListener(listener);
useRelativePathProperty.addListener(listener); useRelativePath.addListener(listener);
globalProperty.get().addPropertyChangedListener(listener); global.get().addPropertyChangedListener(listener);
selectedVersion.addListener(listener);
} }
public static final class Serializer implements JsonSerializer<Profile>, JsonDeserializer<Profile> { public static final class Serializer implements JsonSerializer<Profile>, JsonDeserializer<Profile> {
@ -193,6 +226,7 @@ public final class Profile {
jsonObject.add("global", context.serialize(src.getGlobal())); jsonObject.add("global", context.serialize(src.getGlobal()));
jsonObject.addProperty("gameDir", src.getGameDir().getPath()); jsonObject.addProperty("gameDir", src.getGameDir().getPath());
jsonObject.addProperty("useRelativePath", src.isUseRelativePath()); jsonObject.addProperty("useRelativePath", src.isUseRelativePath());
jsonObject.addProperty("selectedMinecraftVersion", src.getSelectedVersion());
return jsonObject; return jsonObject;
} }
@ -205,7 +239,7 @@ public final class Profile {
Profile profile = new Profile("Default", new File(gameDir)); Profile profile = new Profile("Default", new File(gameDir));
profile.setGlobal(context.deserialize(obj.get("global"), VersionSetting.class)); profile.setGlobal(context.deserialize(obj.get("global"), VersionSetting.class));
profile.setSelectedVersion(Optional.ofNullable(obj.get("selectedMinecraftVersion")).map(JsonElement::getAsString).orElse(""));
profile.setUseRelativePath(Optional.ofNullable(obj.get("useRelativePath")).map(JsonElement::getAsBoolean).orElse(false)); profile.setUseRelativePath(Optional.ofNullable(obj.get("useRelativePath")).map(JsonElement::getAsBoolean).orElse(false));
return profile; return profile;
} }

View File

@ -0,0 +1,58 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 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.ui;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import java.util.LinkedList;
import java.util.List;
public class WeakListenerHelper {
List<Object> refs = new LinkedList<>();
public WeakListenerHelper() {
}
public WeakInvalidationListener weak(InvalidationListener listener) {
refs.add(listener);
return new WeakInvalidationListener(listener);
}
public <T> WeakChangeListener<T> weak(ChangeListener<T> listener) {
refs.add(listener);
return new WeakChangeListener<>(listener);
}
public <T> WeakListChangeListener<T> weak(ListChangeListener<T> listener) {
refs.add(listener);
return new WeakListChangeListener<>(listener);
}
public void add(Object obj) {
refs.add(obj);
}
public boolean remove(Object obj) {
return refs.remove(obj);
}
}

View File

@ -47,6 +47,7 @@ public class FontComboBox extends JFXComboBox<String> {
setOnMouseClicked(e -> { setOnMouseClicked(e -> {
if (loaded) return; if (loaded) return;
getItems().setAll(Font.getFamilies()); getItems().setAll(Font.getFamilies());
loaded = true;
}); });
} }

View File

@ -19,6 +19,7 @@ package org.jackhuang.hmcl.event;
import org.jackhuang.hmcl.util.SimpleMultimap; import org.jackhuang.hmcl.util.SimpleMultimap;
import java.lang.ref.WeakReference;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -31,8 +32,16 @@ public final class EventManager<T extends Event> {
private final SimpleMultimap<EventPriority, Consumer<T>> handlers private final SimpleMultimap<EventPriority, Consumer<T>> handlers
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new); = new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new);
private final SimpleMultimap<EventPriority, Runnable> handlers2
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new); public Consumer<T> registerWeak(Consumer<T> consumer) {
register(new WeakListener(consumer));
return consumer;
}
public Consumer<T> registerWeak(Consumer<T> consumer, EventPriority priority) {
register(new WeakListener(consumer), priority);
return consumer;
}
public void register(Consumer<T> consumer) { public void register(Consumer<T> consumer) {
register(consumer, EventPriority.NORMAL); register(consumer, EventPriority.NORMAL);
@ -44,28 +53,17 @@ public final class EventManager<T extends Event> {
} }
public void register(Runnable runnable) { public void register(Runnable runnable) {
register(runnable, EventPriority.NORMAL); register(t -> runnable.run());
} }
public void register(Runnable runnable, EventPriority priority) { public void register(Runnable runnable, EventPriority priority) {
if (!handlers2.get(priority).contains(runnable)) register(t -> runnable.run(), priority);
handlers2.put(priority, runnable);
}
public void unregister(Consumer<T> consumer) {
handlers.removeValue(consumer);
}
public void unregister(Runnable runnable) {
handlers2.removeValue(runnable);
} }
public Event.Result fireEvent(T event) { public Event.Result fireEvent(T event) {
for (EventPriority priority : EventPriority.values()) { for (EventPriority priority : EventPriority.values()) {
for (Consumer<T> handler : handlers.get(priority)) for (Consumer<T> handler : handlers.get(priority))
handler.accept(event); handler.accept(event);
for (Runnable runnable : handlers2.get(priority))
runnable.run();
} }
if (event.hasResult()) if (event.hasResult())
@ -74,4 +72,21 @@ public final class EventManager<T extends Event> {
return Event.Result.DEFAULT; return Event.Result.DEFAULT;
} }
private class WeakListener implements Consumer<T> {
private final WeakReference<Consumer<T>> ref;
public WeakListener(Consumer<T> listener) {
this.ref = new WeakReference<>(listener);
}
@Override
public void accept(T t) {
Consumer<T> listener = ref.get();
if (listener == null) {
handlers.removeValue(this);
} else {
listener.accept(t);
}
}
}
} }