mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-19 00:36:10 -04:00
fixed crashing when removing mods
This commit is contained in:
parent
e3f0254736
commit
3471b4fec7
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher.
|
* Hello Minecraft! Launcher.
|
||||||
* Copyright (C) 2013 huangyuhui
|
* Copyright (C) 2013 huangyuhui
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -38,5 +38,5 @@ public abstract class IMinecraftModService extends IMinecraftService {
|
|||||||
|
|
||||||
public abstract boolean addMod(File f);
|
public abstract boolean addMod(File f);
|
||||||
|
|
||||||
public abstract void removeMod(int[] index);
|
public abstract void removeMod(Object[] mods);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher.
|
* Hello Minecraft! Launcher.
|
||||||
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -88,6 +88,11 @@ public class ModInfo implements Comparable<ModInfo> {
|
|||||||
return location.hashCode();
|
return location.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getFileName();
|
||||||
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
String n = location.getName();
|
String n = location.getName();
|
||||||
return FileUtils.removeExtension(isActive() ? n : n.substring(0, n.length() - ".disabled".length()));
|
return FileUtils.removeExtension(isActive() ? n : n.substring(0, n.length() - ".disabled".length()));
|
||||||
@ -107,8 +112,8 @@ public class ModInfo implements Comparable<ModInfo> {
|
|||||||
ModInfo i = new ModInfo();
|
ModInfo i = new ModInfo();
|
||||||
i.location = f;
|
i.location = f;
|
||||||
List<ModInfo> m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
List<ModInfo> m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||||
new TypeToken<List<ModInfo>>() {
|
new TypeToken<List<ModInfo>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
if (m != null && m.size() > 0) {
|
if (m != null && m.size() > 0) {
|
||||||
i = m.get(0);
|
i = m.get(0);
|
||||||
i.location = f;
|
i.location = f;
|
||||||
@ -118,8 +123,9 @@ public class ModInfo implements Comparable<ModInfo> {
|
|||||||
|
|
||||||
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
|
||||||
ModInfo m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
ModInfo m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||||
ModInfo.class);
|
ModInfo.class);
|
||||||
if (m == null) m = new ModInfo();
|
if (m == null)
|
||||||
|
m = new ModInfo();
|
||||||
m.location = f;
|
m.location = f;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,14 @@ public class MinecraftModService extends IMinecraftModService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeMod(int[] rows) {
|
public void removeMod(Object[] rows) {
|
||||||
Arrays.sort(rows);
|
if (rows.length == 0)
|
||||||
for (int idx : rows) {
|
return;
|
||||||
ModInfo mi = getMods().get(idx);
|
for (Object r : rows)
|
||||||
File f = mi.location;
|
if (r instanceof ModInfo)
|
||||||
f.delete();
|
((ModInfo) r).location.delete();
|
||||||
}
|
else if (r instanceof Number)
|
||||||
|
getMods().get(((Number) r).intValue()).location.delete();
|
||||||
recacheMods();
|
recacheMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,9 +615,6 @@
|
|||||||
<TableColumnModel selectionModel="1"/>
|
<TableColumnModel selectionModel="1"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="columnSelectionAllowed" type="boolean" value="true"/>
|
<Property name="columnSelectionAllowed" type="boolean" value="true"/>
|
||||||
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
|
|
||||||
<JTableSelectionModel selectionMode="0"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
|
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
|
||||||
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
|
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
@ -610,7 +610,6 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
|||||||
|
|
||||||
lstExternalMods.setModel(SwingUtils.makeDefaultTableModel(new String[]{"", "Mod", C.i18n("ui.label.version")}, new Class[]{Boolean.class,String.class,String.class}, new boolean[]{true,false,false}));
|
lstExternalMods.setModel(SwingUtils.makeDefaultTableModel(new String[]{"", "Mod", C.i18n("ui.label.version")}, new Class[]{Boolean.class,String.class,String.class}, new boolean[]{true,false,false}));
|
||||||
lstExternalMods.setColumnSelectionAllowed(true);
|
lstExternalMods.setColumnSelectionAllowed(true);
|
||||||
lstExternalMods.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
lstExternalMods.getTableHeader().setReorderingAllowed(false);
|
lstExternalMods.getTableHeader().setReorderingAllowed(false);
|
||||||
lstExternalMods.addKeyListener(new java.awt.event.KeyAdapter() {
|
lstExternalMods.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||||
public void keyPressed(java.awt.event.KeyEvent evt) {
|
public void keyPressed(java.awt.event.KeyEvent evt) {
|
||||||
@ -1069,7 +1068,7 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
|||||||
}//GEN-LAST:event_btnAddModActionPerformed
|
}//GEN-LAST:event_btnAddModActionPerformed
|
||||||
|
|
||||||
private void btnRemoveModActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveModActionPerformed
|
private void btnRemoveModActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveModActionPerformed
|
||||||
getProfile().getMinecraftProvider().getModService().removeMod(lstExternalMods.getSelectedRows());
|
getProfile().getMinecraftProvider().getModService().removeMod(SwingUtils.getValueBySelectedRow(lstExternalMods, lstExternalMods.getSelectedRows(), 1));
|
||||||
reloadMods();
|
reloadMods();
|
||||||
}//GEN-LAST:event_btnRemoveModActionPerformed
|
}//GEN-LAST:event_btnRemoveModActionPerformed
|
||||||
|
|
||||||
@ -1248,12 +1247,13 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
|||||||
reloadingMods = true;
|
reloadingMods = true;
|
||||||
DefaultTableModel model = SwingUtils.clearDefaultTable(lstExternalMods);
|
DefaultTableModel model = SwingUtils.clearDefaultTable(lstExternalMods);
|
||||||
Observable.<List<ModInfo>>createWithEmptySubscription(
|
Observable.<List<ModInfo>>createWithEmptySubscription(
|
||||||
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
||||||
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
||||||
.flatMap(t -> Observable.from(t))
|
.subscribe(t -> {
|
||||||
.subscribe(t -> model.addRow(new Object[] {t.isActive(), t.getFileName(), t.version}),
|
for (ModInfo x : t)
|
||||||
null,
|
model.addRow(new Object[]{x.isActive(), x, x.version});
|
||||||
() -> reloadingMods = false);
|
reloadingMods = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
|
@ -139,7 +139,7 @@ public final class MainFrame extends DraggableFrame {
|
|||||||
|
|
||||||
if (enableShadow)
|
if (enableShadow)
|
||||||
try {
|
try {
|
||||||
//setBackground(new Color(0, 0, 0, 0));
|
setBackground(new Color(0, 0, 0, 0));
|
||||||
getRootPane().setBorder(border = new DropShadowBorder(borderColor, 4));
|
getRootPane().setBorder(border = new DropShadowBorder(borderColor, 4));
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
HMCLog.err("Failed to set window transparent.", ex);
|
HMCLog.err("Failed to set window transparent.", ex);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher.
|
* Hello Minecraft! Launcher.
|
||||||
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -42,16 +42,16 @@ public class SwingUtils {
|
|||||||
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
|
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
|
||||||
* DefaultTableModel.
|
* DefaultTableModel.
|
||||||
*
|
*
|
||||||
* @param titleA The title of each column.
|
* @param titleA The title of each column.
|
||||||
* @param typesA The type of each column value.
|
* @param typesA The type of each column value.
|
||||||
* @param canEditA Is column editable?
|
* @param canEditA Is column editable?
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) {
|
public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) {
|
||||||
return new DefaultTableModel(
|
return new DefaultTableModel(
|
||||||
new Object[][] {},
|
new Object[][]{},
|
||||||
titleA) {
|
titleA) {
|
||||||
Class[] types = typesA;
|
Class[] types = typesA;
|
||||||
boolean[] canEdit = canEditA;
|
boolean[] canEdit = canEditA;
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ public class SwingUtils {
|
|||||||
/**
|
/**
|
||||||
* Append new element to JList
|
* Append new element to JList
|
||||||
*
|
*
|
||||||
* @param list the JList
|
* @param list the JList
|
||||||
* @param element the Element
|
* @param element the Element
|
||||||
*/
|
*/
|
||||||
public static void appendLast(JList list, Object element) {
|
public static void appendLast(JList list, Object element) {
|
||||||
@ -154,6 +154,14 @@ public class SwingUtils {
|
|||||||
model.setValueAt(element, row, col);
|
model.setValueAt(element, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object[] getValueBySelectedRow(JTable table, int rows[], int col) {
|
||||||
|
DefaultTableModel model = (DefaultTableModel) table.getModel();
|
||||||
|
Object[] ret = new Object[rows.length];
|
||||||
|
for (int i = 0; i < rows.length; i++)
|
||||||
|
ret[i] = model.getValueAt(rows[i], col);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
public static void removeRow(JTable table, int row) {
|
public static void removeRow(JTable table, int row) {
|
||||||
DefaultTableModel model = (DefaultTableModel) table.getModel();
|
DefaultTableModel model = (DefaultTableModel) table.getModel();
|
||||||
model.removeRow(row);
|
model.removeRow(row);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -17,8 +17,9 @@ package rx;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An object representing a notification sent to an {@link Observable}.
|
* An object representing a notification sent to an {@link Observable}.
|
||||||
*
|
*
|
||||||
* For the Microsoft Rx equivalent see: http://msdn.microsoft.com/en-us/library/hh229462(v=vs.103).aspx
|
* For the Microsoft Rx equivalent see:
|
||||||
|
* http://msdn.microsoft.com/en-us/library/hh229462(v=vs.103).aspx
|
||||||
*/
|
*/
|
||||||
public class Notification<T> {
|
public class Notification<T> {
|
||||||
|
|
||||||
@ -28,9 +29,8 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructor used to represent an onNext notification.
|
* A constructor used to represent an onNext notification.
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value The data passed to the onNext method.
|
||||||
* The data passed to the onNext method.
|
|
||||||
*/
|
*/
|
||||||
public Notification(T value) {
|
public Notification(T value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@ -40,9 +40,8 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructor used to represent an onError notification.
|
* A constructor used to represent an onError notification.
|
||||||
*
|
*
|
||||||
* @param exception
|
* @param exception The exception passed to the onError notification.
|
||||||
* The exception passed to the onError notification.
|
|
||||||
*/
|
*/
|
||||||
public Notification(Exception exception) {
|
public Notification(Exception exception) {
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
@ -61,7 +60,7 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the exception associated with an onError notification.
|
* Retrieves the exception associated with an onError notification.
|
||||||
*
|
*
|
||||||
* @return The exception associated with an onError notification.
|
* @return The exception associated with an onError notification.
|
||||||
*/
|
*/
|
||||||
public Exception getException() {
|
public Exception getException() {
|
||||||
@ -70,7 +69,7 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the data associated with an onNext notification.
|
* Retrieves the data associated with an onNext notification.
|
||||||
*
|
*
|
||||||
* @return The data associated with an onNext notification.
|
* @return The data associated with an onNext notification.
|
||||||
*/
|
*/
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
@ -79,7 +78,7 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a value indicating whether this notification has a value.
|
* Retrieves a value indicating whether this notification has a value.
|
||||||
*
|
*
|
||||||
* @return a value indicating whether this notification has a value.
|
* @return a value indicating whether this notification has a value.
|
||||||
*/
|
*/
|
||||||
public boolean hasValue() {
|
public boolean hasValue() {
|
||||||
@ -88,7 +87,7 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a value indicating whether this notification has an exception.
|
* Retrieves a value indicating whether this notification has an exception.
|
||||||
*
|
*
|
||||||
* @return a value indicating whether this notification has an exception.
|
* @return a value indicating whether this notification has an exception.
|
||||||
*/
|
*/
|
||||||
public boolean hasException() {
|
public boolean hasException() {
|
||||||
@ -97,7 +96,7 @@ public class Notification<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The kind of notification: OnNext, OnError, OnCompleted
|
* The kind of notification: OnNext, OnError, OnCompleted
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Kind getKind() {
|
public Kind getKind() {
|
||||||
@ -150,12 +149,8 @@ public class Notification<T> {
|
|||||||
if (obj.getClass() != getClass())
|
if (obj.getClass() != getClass())
|
||||||
return false;
|
return false;
|
||||||
Notification<?> notification = (Notification<?>) obj;
|
Notification<?> notification = (Notification<?>) obj;
|
||||||
if (notification.getKind() != getKind())
|
if (notification.getKind() != getKind() || hasValue() && !getValue().equals(notification.getValue()))
|
||||||
return false;
|
return false;
|
||||||
if (hasValue() && !getValue().equals(notification.getValue()))
|
return !(hasException() && !getException().equals(notification.getException()));
|
||||||
return false;
|
|
||||||
if (hasException() && !getException().equals(notification.getException()))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -23,7 +23,8 @@ import rx.subscriptions.Subscriptions;
|
|||||||
import rx.util.functions.Action0;
|
import rx.util.functions.Action0;
|
||||||
import rx.util.functions.Func0;
|
import rx.util.functions.Func0;
|
||||||
|
|
||||||
/* package */abstract class AbstractScheduler implements Scheduler {
|
/* package */
|
||||||
|
abstract class AbstractScheduler implements Scheduler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Subscription schedule(Action0 action) {
|
public Subscription schedule(Action0 action) {
|
||||||
@ -41,12 +42,9 @@ import rx.util.functions.Func0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Func0<Subscription> asFunc0(final Action0 action) {
|
private static Func0<Subscription> asFunc0(final Action0 action) {
|
||||||
return new Func0<Subscription>() {
|
return () -> {
|
||||||
@Override
|
action.call();
|
||||||
public Subscription call() {
|
return Subscriptions.empty();
|
||||||
action.call();
|
|
||||||
return Subscriptions.empty();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -27,26 +27,30 @@ import rx.Subscription;
|
|||||||
import rx.util.functions.Func0;
|
import rx.util.functions.Func0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Scheduler} implementation that uses an {@link Executor} or {@link ScheduledExecutorService} implementation.
|
* A {@link Scheduler} implementation that uses an {@link Executor} or
|
||||||
|
* {@link ScheduledExecutorService} implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that if an {@link Executor} implementation is used instead of {@link ScheduledExecutorService} then a system-wide Timer will be used to handle delayed events.
|
* Note that if an {@link Executor} implementation is used instead of
|
||||||
|
* {@link ScheduledExecutorService} then a system-wide Timer will be used to
|
||||||
|
* handle delayed events.
|
||||||
*/
|
*/
|
||||||
public class ExecutorScheduler extends AbstractScheduler {
|
public class ExecutorScheduler extends AbstractScheduler {
|
||||||
|
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup a ScheduledExecutorService that we can use if someone provides an Executor instead of ScheduledExecutorService.
|
* Setup a ScheduledExecutorService that we can use if someone provides an
|
||||||
|
* Executor instead of ScheduledExecutorService.
|
||||||
*/
|
*/
|
||||||
private final static ScheduledExecutorService SYSTEM_SCHEDULED_EXECUTOR;
|
private final static ScheduledExecutorService SYSTEM_SCHEDULED_EXECUTOR;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
int count = Runtime.getRuntime().availableProcessors();
|
int count = Runtime.getRuntime().availableProcessors();
|
||||||
if (count > 8) {
|
if (count > 8)
|
||||||
count = count / 2;
|
count = count / 2;
|
||||||
}
|
|
||||||
// we don't need more than 8 to handle just scheduling and doing no work
|
// we don't need more than 8 to handle just scheduling and doing no work
|
||||||
if (count > 8) {
|
if (count > 8)
|
||||||
count = 8;
|
count = 8;
|
||||||
}
|
|
||||||
SYSTEM_SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(count, new ThreadFactory() {
|
SYSTEM_SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(count, new ThreadFactory() {
|
||||||
|
|
||||||
final AtomicInteger counter = new AtomicInteger();
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
@ -74,37 +78,18 @@ public class ExecutorScheduler extends AbstractScheduler {
|
|||||||
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
|
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
|
||||||
final DiscardableAction discardableAction = new DiscardableAction(action);
|
final DiscardableAction discardableAction = new DiscardableAction(action);
|
||||||
|
|
||||||
if (executor instanceof ScheduledExecutorService) {
|
if (executor instanceof ScheduledExecutorService)
|
||||||
((ScheduledExecutorService) executor).schedule(new Runnable() {
|
((ScheduledExecutorService) executor).schedule(discardableAction::call, dueTime, unit);
|
||||||
@Override
|
else if (dueTime == 0)
|
||||||
public void run() {
|
// no delay so put on the thread-pool right now
|
||||||
discardableAction.call();
|
return (schedule(action));
|
||||||
}
|
else
|
||||||
|
// there is a delay and this isn't a ScheduledExecutorService so we'll use a system-wide ScheduledExecutorService
|
||||||
|
// to handle the scheduling and once it's ready then execute on this Executor
|
||||||
|
SYSTEM_SCHEDULED_EXECUTOR.schedule(() -> {
|
||||||
|
// now execute on the real Executor
|
||||||
|
executor.execute(discardableAction::call);
|
||||||
}, dueTime, unit);
|
}, dueTime, unit);
|
||||||
} else {
|
|
||||||
if (dueTime == 0) {
|
|
||||||
// no delay so put on the thread-pool right now
|
|
||||||
return (schedule(action));
|
|
||||||
} else {
|
|
||||||
// there is a delay and this isn't a ScheduledExecutorService so we'll use a system-wide ScheduledExecutorService
|
|
||||||
// to handle the scheduling and once it's ready then execute on this Executor
|
|
||||||
SYSTEM_SCHEDULED_EXECUTOR.schedule(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// now execute on the real Executor
|
|
||||||
executor.execute(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
discardableAction.call();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, dueTime, unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return discardableAction;
|
return discardableAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,12 +97,7 @@ public class ExecutorScheduler extends AbstractScheduler {
|
|||||||
public Subscription schedule(Func0<Subscription> action) {
|
public Subscription schedule(Func0<Subscription> action) {
|
||||||
final DiscardableAction discardableAction = new DiscardableAction(action);
|
final DiscardableAction discardableAction = new DiscardableAction(action);
|
||||||
|
|
||||||
executor.execute(new Runnable() {
|
executor.execute(discardableAction::call);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
discardableAction.call();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return discardableAction;
|
return discardableAction;
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013 Netflix, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Rx Schedulers
|
|
||||||
*/
|
|
||||||
package rx.concurrency;
|
|
@ -19,10 +19,8 @@ import rx.Observable;
|
|||||||
import rx.Observer;
|
import rx.Observer;
|
||||||
import rx.Scheduler;
|
import rx.Scheduler;
|
||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
import rx.util.functions.Action0;
|
|
||||||
import rx.util.functions.Func1;
|
import rx.util.functions.Func1;
|
||||||
|
|
||||||
|
|
||||||
public class OperationSubscribeOn {
|
public class OperationSubscribeOn {
|
||||||
|
|
||||||
public static <T> Func1<Observer<T>, Subscription> subscribeOn(Observable<T> source, Scheduler scheduler) {
|
public static <T> Func1<Observer<T>, Subscription> subscribeOn(Observable<T> source, Scheduler scheduler) {
|
||||||
@ -30,6 +28,7 @@ public class OperationSubscribeOn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class SubscribeOn<T> implements Func1<Observer<T>, Subscription> {
|
private static class SubscribeOn<T> implements Func1<Observer<T>, Subscription> {
|
||||||
|
|
||||||
private final Observable<T> source;
|
private final Observable<T> source;
|
||||||
private final Scheduler scheduler;
|
private final Scheduler scheduler;
|
||||||
|
|
||||||
@ -45,6 +44,7 @@ public class OperationSubscribeOn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class ScheduledSubscription implements Subscription {
|
private static class ScheduledSubscription implements Subscription {
|
||||||
|
|
||||||
private final Subscription underlying;
|
private final Subscription underlying;
|
||||||
private final Scheduler scheduler;
|
private final Scheduler scheduler;
|
||||||
|
|
||||||
@ -59,4 +59,4 @@ public class OperationSubscribeOn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -19,7 +19,9 @@ import rx.Observer;
|
|||||||
import rx.Scheduler;
|
import rx.Scheduler;
|
||||||
import rx.util.functions.Action0;
|
import rx.util.functions.Action0;
|
||||||
|
|
||||||
/* package */class ScheduledObserver<T> implements Observer<T> {
|
/* package */
|
||||||
|
class ScheduledObserver<T> implements Observer<T> {
|
||||||
|
|
||||||
private final Observer<T> underlying;
|
private final Observer<T> underlying;
|
||||||
private final Scheduler scheduler;
|
private final Scheduler scheduler;
|
||||||
|
|
||||||
@ -30,31 +32,20 @@ import rx.util.functions.Action0;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
scheduler.schedule(new Action0() {
|
scheduler.schedule(() -> {
|
||||||
@Override
|
underlying.onCompleted();
|
||||||
public void call() {
|
|
||||||
underlying.onCompleted();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(final Exception e) {
|
public void onError(final Exception e) {
|
||||||
scheduler.schedule(new Action0() {
|
scheduler.schedule(() -> underlying.onError(e));
|
||||||
@Override
|
|
||||||
public void call() {
|
|
||||||
underlying.onError(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(final T args) {
|
public void onNext(final T args) {
|
||||||
scheduler.schedule(new Action0() {
|
scheduler.schedule(() -> {
|
||||||
@Override
|
underlying.onNext(args);
|
||||||
public void call() {
|
|
||||||
underlying.onNext(args);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013 Netflix, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* <p>Rx Observables</p>
|
|
||||||
*
|
|
||||||
* <p>A library that enables subscribing to and composing asynchronous events and
|
|
||||||
* callbacks.</p>
|
|
||||||
* <p>The Observable/Observer interfaces and associated operators (in
|
|
||||||
* the .operations package) are inspired by and attempt to conform to the
|
|
||||||
* Reactive Rx library in Microsoft .Net.</p>
|
|
||||||
* <p>
|
|
||||||
* More information can be found at <a
|
|
||||||
* href="http://msdn.microsoft.com/en-us/data/gg577609">http://msdn.microsoft.com/en-us/data/gg577609</a>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* <p>Compared with the Microsoft implementation:
|
|
||||||
* <ul>
|
|
||||||
* <li>Observable == IObservable</li>
|
|
||||||
* <li>Observer == IObserver</li>
|
|
||||||
* <li>Subscription == IDisposable</li>
|
|
||||||
* <li>ObservableExtensions == Observable</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
* <p>Services which intend on exposing data asynchronously and wish
|
|
||||||
* to allow reactive processing and composition can implement the
|
|
||||||
* Watchable interface which then allows Watchers to subscribe to them
|
|
||||||
* and receive events.</p>
|
|
||||||
* <p>Usage examples can be found on the Watchable and Watcher
|
|
||||||
* classes.</p>
|
|
||||||
*/
|
|
||||||
package rx;
|
|
@ -9,29 +9,24 @@ import rx.util.SynchronizedObserver;
|
|||||||
import rx.util.functions.Func1;
|
import rx.util.functions.Func1;
|
||||||
|
|
||||||
public class Subject<T> extends Observable<T> implements Observer<T> {
|
public class Subject<T> extends Observable<T> implements Observer<T> {
|
||||||
|
|
||||||
public static <T> Subject<T> create() {
|
public static <T> Subject<T> create() {
|
||||||
final ConcurrentHashMap<Subscription, Observer<T>> observers = new ConcurrentHashMap<Subscription, Observer<T>>();
|
final ConcurrentHashMap<Subscription, Observer<T>> observers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
Func1<Observer<T>, Subscription> onSubscribe = new Func1<Observer<T>, Subscription>() {
|
Func1<Observer<T>, Subscription> onSubscribe = observer -> {
|
||||||
@Override
|
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||||
public Subscription call(Observer<T> observer) {
|
|
||||||
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
|
||||||
|
|
||||||
subscription.wrap(new Subscription() {
|
subscription.wrap(() -> {
|
||||||
@Override
|
// on unsubscribe remove it from the map of outbound observers to notify
|
||||||
public void unsubscribe() {
|
observers.remove(subscription);
|
||||||
// on unsubscribe remove it from the map of outbound observers to notify
|
});
|
||||||
observers.remove(subscription);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// on subscribe add it to the map of outbound observers to notify
|
// on subscribe add it to the map of outbound observers to notify
|
||||||
observers.put(subscription, new SynchronizedObserver<T>(observer, subscription));
|
observers.put(subscription, new SynchronizedObserver<>(observer, subscription));
|
||||||
return subscription;
|
return subscription;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Subject<T>(onSubscribe, observers);
|
return new Subject<>(onSubscribe, observers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ConcurrentHashMap<Subscription, Observer<T>> observers;
|
private final ConcurrentHashMap<Subscription, Observer<T>> observers;
|
||||||
@ -43,23 +38,20 @@ public class Subject<T> extends Observable<T> implements Observer<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
for (Observer<T> observer : observers.values()) {
|
for (Observer<T> observer : observers.values())
|
||||||
observer.onCompleted();
|
observer.onCompleted();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
for (Observer<T> observer : observers.values()) {
|
for (Observer<T> observer : observers.values())
|
||||||
observer.onError(e);
|
observer.onError(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(T args) {
|
public void onNext(T args) {
|
||||||
for (Observer<T> observer : observers.values()) {
|
for (Observer<T> observer : observers.values())
|
||||||
observer.onNext(args);
|
observer.onNext(args);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -21,19 +21,22 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread-safe wrapper around Observable Subscription that ensures unsubscribe can be called only once.
|
* Thread-safe wrapper around Observable Subscription that ensures unsubscribe
|
||||||
|
* can be called only once.
|
||||||
* <p>
|
* <p>
|
||||||
* Also used to:
|
* Also used to:
|
||||||
* <p>
|
* <p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>allow the AtomicObserver to have access to the subscription in asynchronous execution for checking if unsubscribed occurred without onComplete/onError.</li>
|
* <li>allow the AtomicObserver to have access to the subscription in
|
||||||
|
* asynchronous execution for checking if unsubscribed occurred without
|
||||||
|
* onComplete/onError.</li>
|
||||||
* <li>handle both synchronous and asynchronous subscribe() execution flows</li>
|
* <li>handle both synchronous and asynchronous subscribe() execution flows</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public final class AtomicObservableSubscription implements Subscription {
|
public final class AtomicObservableSubscription implements Subscription {
|
||||||
|
|
||||||
private AtomicReference<Subscription> actualSubscription = new AtomicReference<Subscription>();
|
private final AtomicReference<Subscription> actualSubscription = new AtomicReference<>();
|
||||||
private AtomicBoolean unsubscribed = new AtomicBoolean(false);
|
private final AtomicBoolean unsubscribed = new AtomicBoolean(false);
|
||||||
|
|
||||||
public AtomicObservableSubscription() {
|
public AtomicObservableSubscription() {
|
||||||
|
|
||||||
@ -44,16 +47,16 @@ public final class AtomicObservableSubscription implements Subscription {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the actual subscription once it exists (if it wasn't available when constructed)
|
* Wraps the actual subscription once it exists (if it wasn't available when
|
||||||
*
|
* constructed)
|
||||||
|
*
|
||||||
* @param actualSubscription
|
* @param actualSubscription
|
||||||
* @throws IllegalStateException
|
* @throws IllegalStateException if trying to set more than once (or use
|
||||||
* if trying to set more than once (or use this method after setting via constructor)
|
* this method after setting via constructor)
|
||||||
*/
|
*/
|
||||||
public AtomicObservableSubscription wrap(Subscription actualSubscription) {
|
public AtomicObservableSubscription wrap(Subscription actualSubscription) {
|
||||||
if (!this.actualSubscription.compareAndSet(null, actualSubscription)) {
|
if (!this.actualSubscription.compareAndSet(null, actualSubscription))
|
||||||
throw new IllegalStateException("Can not set subscription more than once.");
|
throw new IllegalStateException("Can not set subscription more than once.");
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013 Netflix, Inc.
|
* Copyright 2013 Netflix, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -23,7 +23,8 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Exception that is a composite of 1 or more other exceptions.
|
* Exception that is a composite of 1 or more other exceptions.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>getMessage()</code> will return a concatenation of the composite exceptions.
|
* The <code>getMessage()</code> will return a concatenation of the composite
|
||||||
|
* exceptions.
|
||||||
*/
|
*/
|
||||||
public class CompositeException extends RuntimeException {
|
public class CompositeException extends RuntimeException {
|
||||||
|
|
||||||
@ -34,16 +35,14 @@ public class CompositeException extends RuntimeException {
|
|||||||
|
|
||||||
public CompositeException(String messagePrefix, Collection<Exception> errors) {
|
public CompositeException(String messagePrefix, Collection<Exception> errors) {
|
||||||
StringBuilder _message = new StringBuilder();
|
StringBuilder _message = new StringBuilder();
|
||||||
if (messagePrefix != null) {
|
if (messagePrefix != null)
|
||||||
_message.append(messagePrefix).append(" => ");
|
_message.append(messagePrefix).append(" => ");
|
||||||
}
|
|
||||||
|
|
||||||
List<Exception> _exceptions = new ArrayList<Exception>();
|
List<Exception> _exceptions = new ArrayList<>();
|
||||||
for (Exception e : errors) {
|
for (Exception e : errors) {
|
||||||
_exceptions.add(e);
|
_exceptions.add(e);
|
||||||
if (_message.length() > 0) {
|
if (_message.length() > 0)
|
||||||
_message.append(", ");
|
_message.append(", ");
|
||||||
}
|
|
||||||
_message.append(e.getClass().getSimpleName()).append(":").append(e.getMessage());
|
_message.append(e.getClass().getSimpleName()).append(":").append(e.getMessage());
|
||||||
}
|
}
|
||||||
this.exceptions = Collections.unmodifiableList(_exceptions);
|
this.exceptions = Collections.unmodifiableList(_exceptions);
|
||||||
@ -62,4 +61,4 @@ public class CompositeException extends RuntimeException {
|
|||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,6 +254,7 @@ launcher.update_launcher=Check for update
|
|||||||
launcher.enable_shadow=Enable Window Shadow
|
launcher.enable_shadow=Enable Window Shadow
|
||||||
launcher.theme=Theme
|
launcher.theme=Theme
|
||||||
launcher.proxy=Proxy
|
launcher.proxy=Proxy
|
||||||
|
launcher.decorated=Enable system window border(in order to fix the problem that the ui become all gray in Linux OS)
|
||||||
|
|
||||||
launcher.title.game=Games
|
launcher.title.game=Games
|
||||||
launcher.title.main=Home
|
launcher.title.main=Home
|
||||||
|
@ -254,6 +254,7 @@ launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
|||||||
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548)
|
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548)
|
||||||
launcher.theme=\u4e3b\u9898
|
launcher.theme=\u4e3b\u9898
|
||||||
launcher.proxy=\u4ee3\u7406
|
launcher.proxy=\u4ee3\u7406
|
||||||
|
launcher.decorated=\u555f\u7528\u7a97\u53e3\u908a\u6846(Linux\u4e0b\u53ef\u89e3\u6c7a\u7a0b\u5e8f\u754c\u9762\u5168\u7070\u554f\u984c)
|
||||||
|
|
||||||
launcher.title.game=\u904a\u6232\u8a2d\u5b9a
|
launcher.title.game=\u904a\u6232\u8a2d\u5b9a
|
||||||
launcher.title.main=\u4e3b\u9801
|
launcher.title.main=\u4e3b\u9801
|
||||||
|
@ -251,6 +251,7 @@ launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
|||||||
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
||||||
launcher.theme=\u4e3b\u9898
|
launcher.theme=\u4e3b\u9898
|
||||||
launcher.proxy=\u4ee3\u7406
|
launcher.proxy=\u4ee3\u7406
|
||||||
|
launcher.decorated=\u542f\u7528\u7a97\u53e3\u8fb9\u6846(Linux\u4e0b\u53ef\u89e3\u51b3\u7a0b\u5e8f\u754c\u9762\u5168\u7070\u95ee\u9898)
|
||||||
|
|
||||||
launcher.title.game=\u6e38\u620f\u8bbe\u7f6e
|
launcher.title.game=\u6e38\u620f\u8bbe\u7f6e
|
||||||
launcher.title.main=\u4e3b\u9875
|
launcher.title.main=\u4e3b\u9875
|
||||||
|
Loading…
x
Reference in New Issue
Block a user