Merge branch 'dev' of github.com:GravitLauncher/Launcher into dev

This commit is contained in:
Gravit 2019-02-17 14:24:52 +07:00
commit b3d007c6d1
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
27 changed files with 5 additions and 1286 deletions

View file

@ -41,9 +41,6 @@ public static void registerHandlers() {
if (!registredHandl) {
registerHandler("null", NullAuthHandler.class);
registerHandler("memory", MemoryAuthHandler.class);
// Auth handler that doesn't do nothing :D
registerHandler("binaryFile", BinaryFileAuthHandler.class);
registerHandler("mysql", MySQLAuthHandler.class);
registredHandl = true;
}

View file

@ -1,37 +0,0 @@
package ru.gravit.launchserver.auth.handler;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.utils.helper.IOHelper;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public final class BinaryFileAuthHandler extends FileAuthHandler {
@Override
protected void readAuthFile() throws IOException {
try (HInput input = new HInput(IOHelper.newInput(file))) {
int count = input.readLength(0);
for (int i = 0; i < count; i++) {
UUID uuid = input.readUUID();
Entry entry = new Entry(input);
addAuth(uuid, entry);
}
}
}
@Override
protected void writeAuthFileTmp() throws IOException {
Set<Map.Entry<UUID, Entry>> entrySet = entrySet();
try (HOutput output = new HOutput(IOHelper.newOutput(fileTmp))) {
output.writeLength(entrySet.size(), 0);
for (Map.Entry<UUID, Entry> entry : entrySet) {
output.writeUUID(entry.getKey());
entry.getValue().write(output);
}
}
}
}

View file

@ -1,233 +0,0 @@
package ru.gravit.launchserver.auth.handler;
import ru.gravit.launcher.profiles.PlayerProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.stream.StreamObject;
import ru.gravit.launchserver.auth.provider.AuthProviderResult;
import ru.gravit.utils.helper.*;
import java.io.IOException;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public abstract class FileAuthHandler extends AuthHandler {
public static final class Entry extends StreamObject {
private String username;
private String accessToken;
private String serverID;
public Entry(HInput input) throws IOException {
username = VerifyHelper.verifyUsername(input.readString(64));
if (input.readBoolean()) {
accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
if (input.readBoolean())
serverID = VerifyHelper.verifyServerID(input.readASCII(41));
}
}
public Entry(String username) {
this.username = VerifyHelper.verifyUsername(username);
}
public Entry(String username, String accessToken, String serverID) {
this(username);
if (accessToken == null && serverID != null)
throw new IllegalArgumentException("Can't set access token while server ID is null");
// Set and verify access token
this.accessToken = accessToken == null ? null : SecurityHelper.verifyToken(accessToken);
this.serverID = serverID == null ? null : VerifyHelper.verifyServerID(serverID);
}
private void auth(String username, String accessToken) {
this.username = username; // Update username case
this.accessToken = accessToken;
serverID = null;
}
private boolean checkServer(String username, String serverID) {
return username.equals(this.username) && serverID.equals(this.serverID);
}
public String getAccessToken() {
return accessToken;
}
public String getServerID() {
return serverID;
}
public String getUsername() {
return username;
}
private boolean joinServer(String username, String accessToken, String serverID) {
if (!username.equals(this.username) || !accessToken.equals(this.accessToken))
return false; // Username or access token mismatch
// Update server ID
this.serverID = serverID;
return true;
}
@Override
public void write(HOutput output) throws IOException {
output.writeString(username, 64);
output.writeBoolean(accessToken != null);
if (accessToken != null) {
output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
output.writeBoolean(serverID != null);
if (serverID != null)
output.writeASCII(serverID, 41);
}
}
}
public Path file;
public Path fileTmp;
public boolean offlineUUIDs;
// Instance
private final SecureRandom random = SecurityHelper.newRandom();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// Storage
private final Map<UUID, Entry> entryMap = new HashMap<>(256);
private final Map<String, UUID> usernamesMap = new HashMap<>(256);
protected final void addAuth(UUID uuid, Entry entry) {
lock.writeLock().lock();
try {
Entry previous = entryMap.put(uuid, entry);
if (previous != null)
usernamesMap.remove(CommonHelper.low(previous.username));
usernamesMap.put(CommonHelper.low(entry.username), uuid);
} finally {
lock.writeLock().unlock();
}
}
@Override
public final UUID auth(AuthProviderResult authResult) {
lock.writeLock().lock();
try {
UUID uuid = usernameToUUID(authResult.username);
Entry entry = entryMap.get(uuid);
// Not registered? Fix it!
if (entry == null) {
entry = new Entry(authResult.username);
// Generate UUID
uuid = genUUIDFor(authResult.username);
entryMap.put(uuid, entry);
usernamesMap.put(CommonHelper.low(authResult.username), uuid);
}
// Authenticate
entry.auth(authResult.username, authResult.accessToken);
return uuid;
} finally {
lock.writeLock().unlock();
}
}
@Override
public final UUID checkServer(String username, String serverID) {
lock.readLock().lock();
try {
UUID uuid = usernameToUUID(username);
Entry entry = entryMap.get(uuid);
// Check server (if has such account of course)
return entry != null && entry.checkServer(username, serverID) ? uuid : null;
} finally {
lock.readLock().unlock();
}
}
@Override
public final void close() throws IOException {
lock.readLock().lock();
try {
LogHelper.info("Writing auth handler file (%d entries)", entryMap.size());
writeAuthFileTmp();
IOHelper.move(fileTmp, file);
} finally {
lock.readLock().unlock();
}
}
protected final Set<Map.Entry<UUID, Entry>> entrySet() {
return Collections.unmodifiableMap(entryMap).entrySet();
}
private UUID genUUIDFor(String username) {
if (offlineUUIDs) {
UUID md5UUID = PlayerProfile.offlineUUID(username);
if (!entryMap.containsKey(md5UUID))
return md5UUID;
LogHelper.warning("Offline UUID collision, using random: '%s'", username);
}
// Pick random UUID
UUID uuid;
do
uuid = new UUID(random.nextLong(), random.nextLong());
while (entryMap.containsKey(uuid));
return uuid;
}
@Override
public final boolean joinServer(String username, String accessToken, String serverID) {
lock.writeLock().lock();
try {
Entry entry = entryMap.get(usernameToUUID(username));
return entry != null && entry.joinServer(username, accessToken, serverID);
} finally {
lock.writeLock().unlock();
}
}
protected abstract void readAuthFile() throws IOException;
@Override
public final UUID usernameToUUID(String username) {
lock.readLock().lock();
try {
return usernamesMap.get(CommonHelper.low(username));
} finally {
lock.readLock().unlock();
}
}
@Override
public final String uuidToUsername(UUID uuid) {
lock.readLock().lock();
try {
Entry entry = entryMap.get(uuid);
return entry == null ? null : entry.username;
} finally {
lock.readLock().unlock();
}
}
protected abstract void writeAuthFileTmp() throws IOException;
}

View file

@ -12,7 +12,6 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class UpdateListResponse implements JsonResponseInterface {

View file

@ -60,20 +60,8 @@ var LauncherSettings = LauncherSettingsClass.static;
// Helper JS class API imports
var JSApplication = null;
var CheckComboBox = null;
var CheckModel = null;
var IndexedCheckModel = null;
var CheckComboBoxSkin = null;
var RingProgressIndicator = null;
var RingProgressIndicatorSkin = null;
if (typeof JSApplicationClass !== 'undefined') {
JSApplication = JSApplicationClass.static;
CheckComboBox = CheckComboBoxClass.static;
CheckModel = CheckModelClass.static;
IndexedCheckModel = IndexedCheckModelClass.static;
CheckComboBoxSkin = CheckComboBoxSkinClass.static;
RingProgressIndicator = RingProgressIndicatorClass.static;
RingProgressIndicatorSkin = RingProgressIndicatorSkinClass.static;
}
// API wrapper

View file

@ -71,8 +71,6 @@ public void start(String... args) throws Throwable {
throw new IllegalStateException("Launcher has been already started");
Launcher.modulesManager.initModules();
runtimeProvider.preLoad();
FunctionalBridge.worker = new RequestWorker();
CommonHelper.newThread("Task Worker", true, FunctionalBridge.worker).start();
FunctionalBridge.getHWID = CommonHelper.newThread("GetHWID Thread", true, FunctionalBridge::getHWID);
FunctionalBridge.getHWID.start();
LogHelper.debug("Dir: %s", DirBridge.dir);

View file

@ -1,30 +0,0 @@
package ru.gravit.launcher;
import ru.gravit.utils.helper.LogHelper;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class RequestWorker implements Runnable {
public RequestWorker() {
queue = new LinkedBlockingQueue<>(64);
}
public BlockingQueue<Runnable> queue;
@Override
public void run() {
LogHelper.debug("FX Task Thread start");
while (!Thread.interrupted()) {
try {
Runnable task;
task = queue.take();
task.run();
} catch (InterruptedException e) {
LogHelper.error(e);
return;
}
}
LogHelper.debug("FX Task Thread done");
}
}

View file

@ -3,7 +3,6 @@
import javafx.concurrent.Task;
import ru.gravit.launcher.HWID;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.RequestWorker;
import ru.gravit.launcher.hasher.FileNameMatcher;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.hwid.OshiHWIDProvider;
@ -13,17 +12,18 @@
import ru.gravit.launcher.request.update.LegacyLauncherRequest;
import ru.gravit.launcher.request.websockets.RequestInterface;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
public class FunctionalBridge {
@LauncherAPI
public static LauncherSettings settings;
@LauncherAPI
public static RequestWorker worker;
public static ExecutorService worker = Executors.newWorkStealingPool();
@LauncherAPI
public static OshiHWIDProvider hwidProvider = new OshiHWIDProvider();
@LauncherAPI
@ -64,11 +64,7 @@ public static void makeJsonRequest(RequestInterface request, Runnable callback)
@LauncherAPI
public static void startTask(@SuppressWarnings("rawtypes") Task task) {
try {
worker.queue.put(task);
} catch (InterruptedException e) {
LogHelper.error(e);
}
worker.execute(task);
}
@LauncherAPI

View file

@ -3,7 +3,6 @@
import ru.gravit.launcher.client.ClientLauncherContext;
import java.nio.file.Path;
import java.util.Collection;
public interface LauncherGuardInterface {
String getName();

View file

@ -7,7 +7,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
public class LauncherJavaGuard implements LauncherGuardInterface {

View file

@ -6,7 +6,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
public class LauncherNoGuard implements LauncherGuardInterface {

View file

@ -9,8 +9,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

View file

@ -5,12 +5,6 @@
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.LauncherConfig;
import ru.gravit.launcher.client.*;
import ru.gravit.launcher.gui.choosebox.CheckComboBox;
import ru.gravit.launcher.gui.choosebox.CheckComboBoxSkin;
import ru.gravit.launcher.gui.choosebox.CheckModel;
import ru.gravit.launcher.gui.choosebox.IndexedCheckModel;
import ru.gravit.launcher.gui.indicator.RingProgressIndicator;
import ru.gravit.launcher.gui.indicator.RingProgressIndicatorSkin;
import ru.gravit.launcher.hasher.FileNameMatcher;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.hasher.HashedEntry;
@ -117,12 +111,6 @@ public static void addLauncherClassBindings(Map<String, Object> bindings) {
try {
Class.forName("javafx.application.Application");
bindings.put("JSApplicationClass", JSApplication.class);
bindings.put("RingProgressIndicatorClass", RingProgressIndicator.class);
bindings.put("RingProgressIndicatorSkinClass", RingProgressIndicatorSkin.class);
bindings.put("CheckComboBoxClass", CheckComboBox.class);
bindings.put("CheckModelClass", CheckModel.class);
bindings.put("IndexedCheckModelClass", IndexedCheckModel.class);
bindings.put("CheckComboBoxSkinClass", CheckComboBoxSkin.class);
} catch (ClassNotFoundException ignored) {
LogHelper.warning("JavaFX API isn't available");
}

View file

@ -1,233 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import com.sun.javafx.collections.MappingChange;
import com.sun.javafx.collections.NonIterableChange;
import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import java.util.BitSet;
import java.util.Map;
abstract class CheckBitSetModelBase<T> implements IndexedCheckModel<T> {
private final Map<T, BooleanProperty> itemBooleanMap;
private final BitSet checkedIndices;
private final ReadOnlyUnbackedObservableList<Integer> checkedIndicesList;
private final ReadOnlyUnbackedObservableList<T> checkedItemsList;
CheckBitSetModelBase(final Map<T, BooleanProperty> itemBooleanMap) {
this.itemBooleanMap = itemBooleanMap;
this.checkedIndices = new BitSet();
this.checkedIndicesList = new ReadOnlyUnbackedObservableList<Integer>() {
@Override
public boolean contains(Object o) {
if (o instanceof Number) {
Number n = (Number) o;
int index = n.intValue();
return index >= 0 && index < checkedIndices.length() && checkedIndices.get(index);
}
return false;
}
@Override
public Integer get(int index) {
if (index < 0 || index >= getItemCount())
return -1;
for (int pos = 0, val = checkedIndices.nextSetBit(0); val >= 0
|| pos == index; pos++, val = checkedIndices.nextSetBit(val + 1))
if (pos == index)
return val;
return -1;
}
@Override
public int size() {
return checkedIndices.cardinality();
}
};
this.checkedItemsList = new ReadOnlyUnbackedObservableList<T>() {
@Override
public T get(int i) {
int pos = checkedIndicesList.get(i);
if (pos < 0 || pos >= getItemCount())
return null;
return getItem(pos);
}
@Override
public int size() {
return checkedIndices.cardinality();
}
};
final MappingChange.Map<Integer, T> map = this::getItem;
checkedIndicesList.addListener((ListChangeListener<Integer>) c -> {
boolean hasRealChangeOccurred = false;
while (c.next() && !hasRealChangeOccurred)
hasRealChangeOccurred = c.wasAdded() || c.wasRemoved();
if (hasRealChangeOccurred) {
c.reset();
checkedItemsList.callObservers(new MappingChange<>(c, map, checkedItemsList));
}
c.reset();
});
getCheckedItems().addListener((ListChangeListener<T>) c -> {
while (c.next()) {
if (c.wasAdded())
for (T item : c.getAddedSubList()) {
BooleanProperty p = getItemBooleanProperty(item);
if (p != null)
p.set(true);
}
if (c.wasRemoved())
for (T item : c.getRemoved()) {
BooleanProperty p = getItemBooleanProperty(item);
if (p != null)
p.set(false);
}
}
});
}
@Override
public void check(int index) {
if (index < 0 || index >= getItemCount())
return;
checkedIndices.set(index);
final int changeIndex = checkedIndicesList.indexOf(index);
checkedIndicesList.callObservers(
new NonIterableChange.SimpleAddChange<>(changeIndex, changeIndex + 1, checkedIndicesList));
}
@Override
public void check(T item) {
int index = getItemIndex(item);
check(index);
}
@Override
public void checkAll() {
for (int i = 0; i < getItemCount(); i++)
check(i);
}
@Override
public void checkIndices(int... indices) {
for (int indice : indices)
check(indice);
}
@Override
public void clearCheck(int index) {
if (index < 0 || index >= getItemCount())
return;
checkedIndices.clear(index);
final int changeIndex = checkedIndicesList.indexOf(index);
checkedIndicesList.callObservers(
new NonIterableChange.SimpleRemovedChange<>(changeIndex, changeIndex, index, checkedIndicesList));
}
@Override
public void clearCheck(T item) {
int index = getItemIndex(item);
clearCheck(index);
}
@Override
public void clearChecks() {
for (int index = 0; index < checkedIndices.length(); index++)
clearCheck(index);
}
@Override
public ObservableList<Integer> getCheckedIndices() {
return checkedIndicesList;
}
@Override
public ObservableList<T> getCheckedItems() {
return checkedItemsList;
}
@Override
public abstract T getItem(int index);
BooleanProperty getItemBooleanProperty(T item) {
return itemBooleanMap.get(item);
}
@Override
public abstract int getItemCount();
@Override
public abstract int getItemIndex(T item);
@Override
public boolean isChecked(int index) {
return checkedIndices.get(index);
}
@Override
public boolean isChecked(T item) {
int index = getItemIndex(item);
return isChecked(index);
}
@Override
public boolean isEmpty() {
return checkedIndices.isEmpty();
}
@Override
public void toggleCheckState(int index) {
if (isChecked(index))
clearCheck(index);
else
check(index);
}
@Override
public void toggleCheckState(T item) {
int index = getItemIndex(item);
toggleCheckState(index);
}
protected void updateMap() {
itemBooleanMap.clear();
for (int i = 0; i < getItemCount(); i++) {
final int index = i;
final T item = getItem(index);
final BooleanProperty booleanProperty = new SimpleBooleanProperty(item, "selected", false); //$NON-NLS-1$
itemBooleanMap.put(item, booleanProperty);
booleanProperty.addListener(o -> {
if (booleanProperty.get()) {
checkedIndices.set(index);
final int changeIndex1 = checkedIndicesList.indexOf(index);
checkedIndicesList.callObservers(new NonIterableChange.SimpleAddChange<>(changeIndex1,
changeIndex1 + 1, checkedIndicesList));
} else {
final int changeIndex2 = checkedIndicesList.indexOf(index);
checkedIndices.clear(index);
checkedIndicesList.callObservers(new NonIterableChange.SimpleRemovedChange<>(changeIndex2,
changeIndex2, index, checkedIndicesList));
}
});
}
}
}

View file

@ -1,142 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.control.Skin;
import javafx.util.StringConverter;
import ru.gravit.launcher.LauncherAPI;
import java.util.HashMap;
import java.util.Map;
public class CheckComboBox<T> extends ControlsFXControl {
private static class CheckComboBoxBitSetCheckModel<T> extends CheckBitSetModelBase<T> {
private final ObservableList<T> items;
CheckComboBoxBitSetCheckModel(final ObservableList<T> items, final Map<T, BooleanProperty> itemBooleanMap) {
super(itemBooleanMap);
this.items = items;
this.items.addListener((ListChangeListener<T>) c -> updateMap());
updateMap();
}
@Override
public T getItem(int index) {
return items.get(index);
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public int getItemIndex(T item) {
return items.indexOf(item);
}
}
private final ObservableList<T> items;
private final Map<T, BooleanProperty> itemBooleanMap;
private CheckComboBoxSkin<T> checkComboBoxSkin;
private ObjectProperty<IndexedCheckModel<T>> checkModel = new SimpleObjectProperty<>(this, "checkModel");
private ObjectProperty<StringConverter<T>> converter = new SimpleObjectProperty<>(this,
"converter");
private StringProperty title = new SimpleStringProperty(null);
public CheckComboBox() {
this(null);
}
public CheckComboBox(final ObservableList<T> items) {
final int initialSize = items == null ? 32 : items.size();
this.itemBooleanMap = new HashMap<>(initialSize);
this.items = items == null ? FXCollections.observableArrayList() : items;
setCheckModel(new CheckComboBoxBitSetCheckModel<>(this.items, itemBooleanMap));
}
@LauncherAPI
public final ObjectProperty<IndexedCheckModel<T>> checkModelProperty() {
return checkModel;
}
@LauncherAPI
public final ObjectProperty<StringConverter<T>> converterProperty() {
return converter;
}
@Override
protected Skin<?> createDefaultSkin() {
checkComboBoxSkin = new CheckComboBoxSkin<>(this);
return checkComboBoxSkin;
}
@LauncherAPI
public final IndexedCheckModel<T> getCheckModel() {
return checkModel == null ? null : checkModel.get();
}
@LauncherAPI
public final StringConverter<T> getConverter() {
return converterProperty().get();
}
@LauncherAPI
public BooleanProperty getItemBooleanProperty(int index) {
if (index < 0 || index >= items.size())
return null;
return getItemBooleanProperty(getItems().get(index));
}
@LauncherAPI
public BooleanProperty getItemBooleanProperty(T item) {
return itemBooleanMap.get(item);
}
@LauncherAPI
public ObservableList<T> getItems() {
return items;
}
@LauncherAPI
public final String getTitle() {
return title.getValue();
}
@LauncherAPI
public void hide() {
if (checkComboBoxSkin != null)
checkComboBoxSkin.hide();
}
@LauncherAPI
public final void setCheckModel(IndexedCheckModel<T> value) {
checkModelProperty().set(value);
}
@LauncherAPI
public final void setConverter(StringConverter<T> value) {
converterProperty().set(value);
}
@LauncherAPI
public final void setTitle(String value) {
title.setValue(value);
}
@LauncherAPI
public void show() {
if (checkComboBoxSkin != null)
checkComboBoxSkin.show();
}
@LauncherAPI
public final StringProperty titleProperty() {
return title;
}
}

View file

@ -1,172 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
import com.sun.javafx.scene.control.behavior.BehaviorBase;
import com.sun.javafx.scene.control.skin.BehaviorSkinBase;
import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Skin;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.input.KeyCode;
import ru.gravit.launcher.LauncherAPI;
import java.util.Collections;
public class CheckComboBoxSkin<T> extends BehaviorSkinBase<CheckComboBox<T>, BehaviorBase<CheckComboBox<T>>> {
private final ComboBox<T> comboBox;
private final ListCell<T> buttonCell;
private final CheckComboBox<T> control;
private final ReadOnlyUnbackedObservableList<T> selectedItems;
@SuppressWarnings("unchecked")
public CheckComboBoxSkin(final CheckComboBox<T> control) {
super(control, new BehaviorBase<>(control, Collections.emptyList()));
this.control = control;
ObservableList<T> items = control.getItems();
ReadOnlyUnbackedObservableList<Integer> selectedIndices = (ReadOnlyUnbackedObservableList<Integer>) control.getCheckModel().getCheckedIndices();
selectedItems = (ReadOnlyUnbackedObservableList<T>) control.getCheckModel().getCheckedItems();
comboBox = new ComboBox<T>(items) {
@Override
protected javafx.scene.control.Skin<?> createDefaultSkin() {
return createComboBoxListViewSkin(this);
}
};
comboBox.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
comboBox.setCellFactory(listView -> {
CheckBoxListCell<T> result = new CheckBoxListCell<>(control::getItemBooleanProperty);
result.focusedProperty().addListener((o, ov, nv) -> {
if (nv)
result.getParent().requestFocus();
});
result.setOnMouseClicked(e -> {
T item = result.getItem();
if (control.getCheckModel().isChecked(item))
control.getCheckModel().clearCheck(item);
else
control.getCheckModel().check(item);
});
result.converterProperty().bind(control.converterProperty());
return result;
});
buttonCell = new ListCell<T>() {
@Override
protected void updateItem(T item, boolean empty) {
setText(getTextString());
}
};
comboBox.setButtonCell(buttonCell);
comboBox.setValue((T) getTextString());
selectedIndices.addListener((ListChangeListener<Integer>) c -> buttonCell.updateIndex(0));
getChildren().add(comboBox);
}
private String buildString() {
final StringBuilder sb = new StringBuilder();
for (int i = 0, max = selectedItems.size(); i < max; i++) {
T item = selectedItems.get(i);
if (control.getConverter() == null)
sb.append(item);
else
sb.append(control.getConverter().toString(item));
if (i < max - 1)
sb.append(", "); //$NON-NLS-1$
}
return sb.toString();
}
@LauncherAPI
@Override
protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
return getSkinnable().prefHeight(width);
}
@LauncherAPI
@Override
protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset,
double leftInset) {
return getSkinnable().prefWidth(height);
}
@LauncherAPI
@Override
protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
return comboBox.minHeight(width);
}
@LauncherAPI
@Override
protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset,
double leftInset) {
return comboBox.minWidth(height);
}
@LauncherAPI
@Override
protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
return comboBox.prefHeight(width);
}
@LauncherAPI
@Override
protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset,
double leftInset) {
return comboBox.prefWidth(height);
}
private Skin<?> createComboBoxListViewSkin(ComboBox<T> comboBox) {
final ComboBoxListViewSkin<T> comboBoxListViewSkin = new ComboBoxListViewSkin<T>(comboBox) {
@Override
protected boolean isHideOnClickEnabled() {
return false;
}
};
@SuppressWarnings("unchecked") final ListView<T> listView = (ListView<T>) comboBoxListViewSkin.getPopupContent();
listView.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.SPACE) {
T item = listView.getSelectionModel().getSelectedItem();
if (item != null) {
final IndexedCheckModel<T> checkModel = control.getCheckModel();
if (checkModel != null)
checkModel.toggleCheckState(item);
}
} else if (e.getCode() == KeyCode.ESCAPE)
hide();
});
return comboBoxListViewSkin;
}
@LauncherAPI
protected String getTextString() {
if (control.getTitle() != null)
return control.getTitle();
return buildString();
}
@LauncherAPI
public void hide() {
comboBox.hide();
}
@LauncherAPI
public void show() {
comboBox.show();
}
}

View file

@ -1,33 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import javafx.collections.ObservableList;
import ru.gravit.launcher.LauncherAPI;
public interface CheckModel<T> {
@LauncherAPI
void check(T item);
@LauncherAPI
void checkAll();
@LauncherAPI
void clearCheck(T item);
@LauncherAPI
void clearChecks();
@LauncherAPI
ObservableList<T> getCheckedItems();
@LauncherAPI
int getItemCount();
@LauncherAPI
boolean isChecked(T item);
@LauncherAPI
boolean isEmpty();
@LauncherAPI
void toggleCheckState(T item);
}

View file

@ -1,20 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import javafx.scene.control.Control;
abstract class ControlsFXControl extends Control {
private String stylesheet;
public ControlsFXControl() {
}
protected final String getUserAgentStylesheet(Class<?> clazz, String fileName) {
if (stylesheet == null)
stylesheet = clazz.getResource(fileName).toExternalForm();
return stylesheet;
}
}

View file

@ -1,31 +0,0 @@
package ru.gravit.launcher.gui.choosebox;
import javafx.collections.ObservableList;
import ru.gravit.launcher.LauncherAPI;
public interface IndexedCheckModel<T> extends CheckModel<T> {
@LauncherAPI
void check(int index);
@LauncherAPI
void checkIndices(int... indices);
@LauncherAPI
void clearCheck(int index);
@LauncherAPI
ObservableList<Integer> getCheckedIndices();
@LauncherAPI
T getItem(int index);
@LauncherAPI
int getItemIndex(T item);
@LauncherAPI
boolean isChecked(int index);
@LauncherAPI
void toggleCheckState(int index);
}

View file

@ -1,86 +0,0 @@
package ru.gravit.launcher.gui.indicator;
import com.sun.javafx.css.converters.SizeConverter;
import javafx.beans.property.DoubleProperty;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableProperty;
import javafx.scene.control.Control;
import javafx.scene.control.ProgressIndicator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
abstract class ProgressCircleIndicator extends ProgressIndicator {
public ProgressCircleIndicator() {
this.getStylesheets().add(ProgressCircleIndicator.class.getResource("/runtime/launcher/overlay/update/circleprogress.css").toExternalForm());
}
public final void setInnerCircleRadius(int value) {
innerCircleRadiusProperty().set(value);
}
public final DoubleProperty innerCircleRadiusProperty() {
return innerCircleRadius;
}
public final double getInnerCircleRadius() {
return innerCircleRadiusProperty().get();
}
/**
* radius of the inner circle
*/
private DoubleProperty innerCircleRadius = new StyleableDoubleProperty(60) {
@Override
public Object getBean() {
return ProgressCircleIndicator.this;
}
@Override
public String getName() {
return "innerCircleRadius";
}
@Override
public CssMetaData<ProgressCircleIndicator, Number> getCssMetaData() {
return StyleableProperties.INNER_CIRCLE_RADIUS;
}
};
private static class StyleableProperties {
private static final CssMetaData<ProgressCircleIndicator, Number> INNER_CIRCLE_RADIUS = new CssMetaData<ProgressCircleIndicator, Number>(
"-fx-inner-radius", SizeConverter.getInstance(), 60) {
@Override
public boolean isSettable(ProgressCircleIndicator n) {
return n.innerCircleRadiusProperty() == null || !n.innerCircleRadiusProperty().isBound();
}
@SuppressWarnings("unchecked")
@Override
public StyleableProperty<Number> getStyleableProperty(ProgressCircleIndicator n) {
return (StyleableProperty<Number>) n.innerCircleRadiusProperty();
}
};
public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(Control.getClassCssMetaData());
styleables.add(INNER_CIRCLE_RADIUS);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
return StyleableProperties.STYLEABLES;
}
@Override
public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
return StyleableProperties.STYLEABLES;
}
}

View file

@ -1,95 +0,0 @@
package ru.gravit.launcher.gui.indicator;
import com.sun.javafx.css.converters.SizeConverter;
import javafx.beans.property.DoubleProperty;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableProperty;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.utils.helper.LogHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RingProgressIndicator extends ProgressCircleIndicator {
public RingProgressIndicator() {
LogHelper.debug("Setting JVM dir name");
this.getStylesheets().add(RingProgressIndicator.class.getResource("/runtime/launcher/overlay/update/ringprogress.css").toExternalForm());
this.getStyleClass().add("ringindicator");
}
@Override
protected Skin<?> createDefaultSkin() {
return new RingProgressIndicatorSkin(this);
}
@LauncherAPI
public final void setRingWidth(int value) {
ringWidthProperty().set(value);
}
@LauncherAPI
public final DoubleProperty ringWidthProperty() {
return ringWidth;
}
@LauncherAPI
public final double getRingWidth() {
return ringWidthProperty().get();
}
/**
* thickness of the ring indicator.
*/
private DoubleProperty ringWidth = new StyleableDoubleProperty(22) {
@Override
public Object getBean() {
return RingProgressIndicator.this;
}
@Override
public String getName() {
return "ringWidth";
}
@Override
public CssMetaData<RingProgressIndicator, Number> getCssMetaData() {
return StyleableProperties.RING_WIDTH;
}
};
private static class StyleableProperties {
private static final CssMetaData<RingProgressIndicator, Number> RING_WIDTH = new CssMetaData<RingProgressIndicator, Number>(
"-fx-ring-width", SizeConverter.getInstance(), 22) {
@Override
public boolean isSettable(RingProgressIndicator n) {
return n.ringWidth == null || !n.ringWidth.isBound();
}
@SuppressWarnings("unchecked")
@Override
public StyleableProperty<Number> getStyleableProperty(RingProgressIndicator n) {
return (StyleableProperty<Number>) n.ringWidth;
}
};
public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(Control.getClassCssMetaData());
styleables.addAll(getClassCssMetaData());
styleables.add(RING_WIDTH);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
@Override
public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
return StyleableProperties.STYLEABLES;
}
}

View file

@ -1,124 +0,0 @@
package ru.gravit.launcher.gui.indicator;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.RotateTransition;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Skin;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Arc;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
/**
* Skin of the ring progress indicator where an arc grows and by the progress value up to 100% where the arc becomes a ring.
*
* @author Andrea Vacondio
*/
public class RingProgressIndicatorSkin implements Skin<RingProgressIndicator> {
private final RingProgressIndicator indicator;
private final Label percentLabel = new Label();
private final Circle innerCircle = new Circle();
private final Circle outerCircle = new Circle();
private final StackPane container = new StackPane();
private final Arc fillerArc = new Arc();
private final RotateTransition transition = new RotateTransition(Duration.millis(2000), fillerArc);
public RingProgressIndicatorSkin(final RingProgressIndicator indicator) {
this.indicator = indicator;
initContainer(indicator);
initFillerArc();
container.widthProperty().addListener((o, oldVal, newVal) -> fillerArc.setCenterX(newVal.intValue() / 2));
container.heightProperty().addListener((o, oldVal, newVal) -> fillerArc.setCenterY(newVal.intValue() / 2));
innerCircle.getStyleClass().add("ringindicator-inner-circle");
outerCircle.getStyleClass().add("ringindicator-outer-circle-secondary");
updateRadii();
this.indicator.indeterminateProperty().addListener((o, oldVal, newVal) -> initIndeterminate(newVal));
this.indicator.progressProperty().addListener((o, oldVal, newVal) -> {
if (newVal.intValue() >= 0) {
fillerArc.setLength(newVal.doubleValue() * -360);
}
});
this.indicator.ringWidthProperty().addListener((o, oldVal, newVal) -> updateRadii());
innerCircle.strokeWidthProperty().addListener((e) -> updateRadii());
innerCircle.radiusProperty().addListener((e) -> updateRadii());
initTransition();
initIndeterminate(indicator.isIndeterminate());
indicator.visibleProperty().addListener((o, oldVal, newVal) -> {
if (newVal && this.indicator.isIndeterminate()) {
transition.play();
} else {
transition.pause();
}
});
container.getChildren().addAll(fillerArc, outerCircle, innerCircle, percentLabel);
}
private void initTransition() {
transition.setAutoReverse(false);
transition.setCycleCount(Animation.INDEFINITE);
transition.setDelay(Duration.ZERO);
transition.setInterpolator(Interpolator.LINEAR);
transition.setByAngle(360);
}
private void initFillerArc() {
fillerArc.setManaged(false);
fillerArc.getStyleClass().add("ringindicator-filler");
fillerArc.setStartAngle(90);
fillerArc.setLength(indicator.getProgress() * -360);
}
private void initContainer(final RingProgressIndicator indicator) {
container.getStylesheets().addAll(indicator.getStylesheets());
container.getStyleClass().addAll("circleindicator-container");
container.setMaxHeight(Region.USE_PREF_SIZE);
container.setMaxWidth(Region.USE_PREF_SIZE);
}
private void updateRadii() {
double ringWidth = indicator.getRingWidth();
double innerCircleHalfStrokeWidth = innerCircle.getStrokeWidth() / 2;
double innerCircleRadius = indicator.getInnerCircleRadius();
outerCircle.setRadius(innerCircleRadius + innerCircleHalfStrokeWidth + ringWidth);
fillerArc.setRadiusY(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2));
fillerArc.setRadiusX(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2));
fillerArc.setStrokeWidth(ringWidth);
innerCircle.setRadius(innerCircleRadius);
}
private void initIndeterminate(boolean newVal) {
percentLabel.setVisible(!newVal);
if (newVal) {
fillerArc.setLength(360);
fillerArc.getStyleClass().add("indeterminate");
if (indicator.isVisible()) {
transition.play();
}
} else {
fillerArc.getStyleClass().remove("indeterminate");
fillerArc.setRotate(0);
transition.stop();
}
}
@Override
public RingProgressIndicator getSkinnable() {
return indicator;
}
@Override
public Node getNode() {
return container;
}
@Override
public void dispose() {
transition.stop();
}
}

View file

@ -17,7 +17,6 @@
import ru.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

View file

@ -13,7 +13,6 @@
import ru.gravit.launcher.serialize.HOutput;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class ProfilesRequest extends Request<ProfilesRequestEvent> implements RequestInterface {

View file

@ -12,9 +12,7 @@
import ru.gravit.utils.helper.IOHelper;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public final class UpdateListRequest extends Request<UpdateListRequestEvent> implements RequestInterface {
@LauncherAPI

View file

@ -1,11 +1,9 @@
package ru.gravit.launcher.events.request;
import ru.gravit.launcher.LauncherNetworkAPI;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.request.ResultInterface;
import ru.gravit.utils.event.EventInterface;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.UUID;

@ -1 +1 @@
Subproject commit 9a7e59fb8df543305a2b708822a398dcabcac4b9
Subproject commit 14d93a04d551ae36f68bd74d61445d8c7d7bd076