mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-24 18:50:52 +08:00
fixed crashing when removing mods
This commit is contained in:
parent
e3f0254736
commit
3471b4fec7
HMCL/src/main/java/org/jackhuang/hellominecraft/launcher
launch
utils
version
views
HMCLAPI/src/main
java
org/jackhuang/hellominecraft/views
rx
resources/org/jackhuang/hellominecraft/launcher
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2013 huangyuhui
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@ -38,5 +38,5 @@ public abstract class IMinecraftModService extends IMinecraftService {
|
||||
|
||||
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.
|
||||
* Copyright (C) 2013 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
|
||||
@ -88,6 +88,11 @@ public class ModInfo implements Comparable<ModInfo> {
|
||||
return location.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFileName();
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
String n = location.getName();
|
||||
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();
|
||||
i.location = f;
|
||||
List<ModInfo> m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||
new TypeToken<List<ModInfo>>() {
|
||||
}.getType());
|
||||
new TypeToken<List<ModInfo>>() {
|
||||
}.getType());
|
||||
if (m != null && m.size() > 0) {
|
||||
i = m.get(0);
|
||||
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 {
|
||||
ModInfo m = C.gson.fromJson(new InputStreamReader(jar.getInputStream(entry)),
|
||||
ModInfo.class);
|
||||
if (m == null) m = new ModInfo();
|
||||
ModInfo.class);
|
||||
if (m == null)
|
||||
m = new ModInfo();
|
||||
m.location = f;
|
||||
return m;
|
||||
}
|
||||
|
@ -104,13 +104,14 @@ public class MinecraftModService extends IMinecraftModService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMod(int[] rows) {
|
||||
Arrays.sort(rows);
|
||||
for (int idx : rows) {
|
||||
ModInfo mi = getMods().get(idx);
|
||||
File f = mi.location;
|
||||
f.delete();
|
||||
}
|
||||
public void removeMod(Object[] rows) {
|
||||
if (rows.length == 0)
|
||||
return;
|
||||
for (Object r : rows)
|
||||
if (r instanceof ModInfo)
|
||||
((ModInfo) r).location.delete();
|
||||
else if (r instanceof Number)
|
||||
getMods().get(((Number) r).intValue()).location.delete();
|
||||
recacheMods();
|
||||
}
|
||||
|
||||
|
@ -615,9 +615,6 @@
|
||||
<TableColumnModel selectionModel="1"/>
|
||||
</Property>
|
||||
<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">
|
||||
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
|
||||
</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.setColumnSelectionAllowed(true);
|
||||
lstExternalMods.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
lstExternalMods.getTableHeader().setReorderingAllowed(false);
|
||||
lstExternalMods.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||
public void keyPressed(java.awt.event.KeyEvent evt) {
|
||||
@ -1069,7 +1068,7 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
||||
}//GEN-LAST:event_btnAddModActionPerformed
|
||||
|
||||
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();
|
||||
}//GEN-LAST:event_btnRemoveModActionPerformed
|
||||
|
||||
@ -1248,12 +1247,13 @@ public final class GameSettingsPanel extends AnimatedPanel implements DropTarget
|
||||
reloadingMods = true;
|
||||
DefaultTableModel model = SwingUtils.clearDefaultTable(lstExternalMods);
|
||||
Observable.<List<ModInfo>>createWithEmptySubscription(
|
||||
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
||||
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
||||
.flatMap(t -> Observable.from(t))
|
||||
.subscribe(t -> model.addRow(new Object[] {t.isActive(), t.getFileName(), t.version}),
|
||||
null,
|
||||
() -> reloadingMods = false);
|
||||
t -> t.onNext(getProfile().getMinecraftProvider().getModService().recacheMods()))
|
||||
.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue())
|
||||
.subscribe(t -> {
|
||||
for (ModInfo x : t)
|
||||
model.addRow(new Object[]{x.isActive(), x, x.version});
|
||||
reloadingMods = false;
|
||||
});
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
|
@ -139,7 +139,7 @@ public final class MainFrame extends DraggableFrame {
|
||||
|
||||
if (enableShadow)
|
||||
try {
|
||||
//setBackground(new Color(0, 0, 0, 0));
|
||||
setBackground(new Color(0, 0, 0, 0));
|
||||
getRootPane().setBorder(border = new DropShadowBorder(borderColor, 4));
|
||||
} catch (Throwable ex) {
|
||||
HMCLog.err("Failed to set window transparent.", ex);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2013 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
|
||||
@ -42,16 +42,16 @@ public class SwingUtils {
|
||||
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
|
||||
* DefaultTableModel.
|
||||
*
|
||||
* @param titleA The title of each column.
|
||||
* @param typesA The type of each column value.
|
||||
* @param titleA The title of each column.
|
||||
* @param typesA The type of each column value.
|
||||
* @param canEditA Is column editable?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) {
|
||||
return new DefaultTableModel(
|
||||
new Object[][] {},
|
||||
titleA) {
|
||||
new Object[][]{},
|
||||
titleA) {
|
||||
Class[] types = typesA;
|
||||
boolean[] canEdit = canEditA;
|
||||
|
||||
@ -114,7 +114,7 @@ public class SwingUtils {
|
||||
/**
|
||||
* Append new element to JList
|
||||
*
|
||||
* @param list the JList
|
||||
* @param list the JList
|
||||
* @param element the Element
|
||||
*/
|
||||
public static void appendLast(JList list, Object element) {
|
||||
@ -154,6 +154,14 @@ public class SwingUtils {
|
||||
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) {
|
||||
DefaultTableModel model = (DefaultTableModel) table.getModel();
|
||||
model.removeRow(row);
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -17,8 +17,9 @@ package rx;
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
|
||||
@ -28,9 +29,8 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* A constructor used to represent an onNext notification.
|
||||
*
|
||||
* @param value
|
||||
* The data passed to the onNext method.
|
||||
*
|
||||
* @param value The data passed to the onNext method.
|
||||
*/
|
||||
public Notification(T value) {
|
||||
this.value = value;
|
||||
@ -40,9 +40,8 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* A constructor used to represent an onError notification.
|
||||
*
|
||||
* @param exception
|
||||
* The exception passed to the onError notification.
|
||||
*
|
||||
* @param exception The exception passed to the onError notification.
|
||||
*/
|
||||
public Notification(Exception exception) {
|
||||
this.exception = exception;
|
||||
@ -61,7 +60,7 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* Retrieves the exception associated with an onError notification.
|
||||
*
|
||||
*
|
||||
* @return The exception associated with an onError notification.
|
||||
*/
|
||||
public Exception getException() {
|
||||
@ -70,7 +69,7 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* Retrieves the data associated with an onNext notification.
|
||||
*
|
||||
*
|
||||
* @return The data associated with an onNext notification.
|
||||
*/
|
||||
public T getValue() {
|
||||
@ -79,7 +78,7 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* Retrieves a value indicating whether this notification has a value.
|
||||
*
|
||||
*
|
||||
* @return a value indicating whether this notification has a value.
|
||||
*/
|
||||
public boolean hasValue() {
|
||||
@ -88,7 +87,7 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* Retrieves a value indicating whether this notification has an exception.
|
||||
*
|
||||
*
|
||||
* @return a value indicating whether this notification has an exception.
|
||||
*/
|
||||
public boolean hasException() {
|
||||
@ -97,7 +96,7 @@ public class Notification<T> {
|
||||
|
||||
/**
|
||||
* The kind of notification: OnNext, OnError, OnCompleted
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Kind getKind() {
|
||||
@ -150,12 +149,8 @@ public class Notification<T> {
|
||||
if (obj.getClass() != getClass())
|
||||
return false;
|
||||
Notification<?> notification = (Notification<?>) obj;
|
||||
if (notification.getKind() != getKind())
|
||||
if (notification.getKind() != getKind() || hasValue() && !getValue().equals(notification.getValue()))
|
||||
return false;
|
||||
if (hasValue() && !getValue().equals(notification.getValue()))
|
||||
return false;
|
||||
if (hasException() && !getException().equals(notification.getException()))
|
||||
return false;
|
||||
return true;
|
||||
return !(hasException() && !getException().equals(notification.getException()));
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -23,7 +23,8 @@ import rx.subscriptions.Subscriptions;
|
||||
import rx.util.functions.Action0;
|
||||
import rx.util.functions.Func0;
|
||||
|
||||
/* package */abstract class AbstractScheduler implements Scheduler {
|
||||
/* package */
|
||||
abstract class AbstractScheduler implements Scheduler {
|
||||
|
||||
@Override
|
||||
public Subscription schedule(Action0 action) {
|
||||
@ -41,12 +42,9 @@ import rx.util.functions.Func0;
|
||||
}
|
||||
|
||||
private static Func0<Subscription> asFunc0(final Action0 action) {
|
||||
return new Func0<Subscription>() {
|
||||
@Override
|
||||
public Subscription call() {
|
||||
action.call();
|
||||
return Subscriptions.empty();
|
||||
}
|
||||
return () -> {
|
||||
action.call();
|
||||
return Subscriptions.empty();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -27,26 +27,30 @@ import rx.Subscription;
|
||||
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>
|
||||
* 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 {
|
||||
|
||||
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;
|
||||
|
||||
static {
|
||||
int count = Runtime.getRuntime().availableProcessors();
|
||||
if (count > 8) {
|
||||
if (count > 8)
|
||||
count = count / 2;
|
||||
}
|
||||
// we don't need more than 8 to handle just scheduling and doing no work
|
||||
if (count > 8) {
|
||||
if (count > 8)
|
||||
count = 8;
|
||||
}
|
||||
SYSTEM_SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(count, new ThreadFactory() {
|
||||
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
@ -74,37 +78,18 @@ public class ExecutorScheduler extends AbstractScheduler {
|
||||
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
|
||||
final DiscardableAction discardableAction = new DiscardableAction(action);
|
||||
|
||||
if (executor instanceof ScheduledExecutorService) {
|
||||
((ScheduledExecutorService) executor).schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
discardableAction.call();
|
||||
}
|
||||
if (executor instanceof ScheduledExecutorService)
|
||||
((ScheduledExecutorService) executor).schedule(discardableAction::call, 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(() -> {
|
||||
// now execute on the real Executor
|
||||
executor.execute(discardableAction::call);
|
||||
}, 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;
|
||||
}
|
||||
|
||||
@ -112,12 +97,7 @@ public class ExecutorScheduler extends AbstractScheduler {
|
||||
public Subscription schedule(Func0<Subscription> action) {
|
||||
final DiscardableAction discardableAction = new DiscardableAction(action);
|
||||
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
discardableAction.call();
|
||||
}
|
||||
});
|
||||
executor.execute(discardableAction::call);
|
||||
|
||||
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.Scheduler;
|
||||
import rx.Subscription;
|
||||
import rx.util.functions.Action0;
|
||||
import rx.util.functions.Func1;
|
||||
|
||||
|
||||
public class OperationSubscribeOn {
|
||||
|
||||
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 final Observable<T> source;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
@ -45,6 +44,7 @@ public class OperationSubscribeOn {
|
||||
}
|
||||
|
||||
private static class ScheduledSubscription implements Subscription {
|
||||
|
||||
private final Subscription underlying;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
@ -59,4 +59,4 @@ public class OperationSubscribeOn {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -19,7 +19,9 @@ import rx.Observer;
|
||||
import rx.Scheduler;
|
||||
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 Scheduler scheduler;
|
||||
|
||||
@ -30,31 +32,20 @@ import rx.util.functions.Action0;
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
scheduler.schedule(new Action0() {
|
||||
@Override
|
||||
public void call() {
|
||||
underlying.onCompleted();
|
||||
}
|
||||
scheduler.schedule(() -> {
|
||||
underlying.onCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(final Exception e) {
|
||||
scheduler.schedule(new Action0() {
|
||||
@Override
|
||||
public void call() {
|
||||
underlying.onError(e);
|
||||
}
|
||||
});
|
||||
scheduler.schedule(() -> underlying.onError(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(final T args) {
|
||||
scheduler.schedule(new Action0() {
|
||||
@Override
|
||||
public void call() {
|
||||
underlying.onNext(args);
|
||||
}
|
||||
scheduler.schedule(() -> {
|
||||
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;
|
||||
|
||||
public class Subject<T> extends Observable<T> implements Observer<T> {
|
||||
|
||||
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>() {
|
||||
@Override
|
||||
public Subscription call(Observer<T> observer) {
|
||||
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
Func1<Observer<T>, Subscription> onSubscribe = observer -> {
|
||||
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
|
||||
|
||||
subscription.wrap(new Subscription() {
|
||||
@Override
|
||||
public void unsubscribe() {
|
||||
// on unsubscribe remove it from the map of outbound observers to notify
|
||||
observers.remove(subscription);
|
||||
}
|
||||
});
|
||||
subscription.wrap(() -> {
|
||||
// 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
|
||||
observers.put(subscription, new SynchronizedObserver<T>(observer, subscription));
|
||||
return subscription;
|
||||
}
|
||||
// on subscribe add it to the map of outbound observers to notify
|
||||
observers.put(subscription, new SynchronizedObserver<>(observer, subscription));
|
||||
return subscription;
|
||||
};
|
||||
|
||||
return new Subject<T>(onSubscribe, observers);
|
||||
return new Subject<>(onSubscribe, observers);
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<Subscription, Observer<T>> observers;
|
||||
@ -43,23 +38,20 @@ public class Subject<T> extends Observable<T> implements Observer<T> {
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
for (Observer<T> observer : observers.values()) {
|
||||
for (Observer<T> observer : observers.values())
|
||||
observer.onCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
for (Observer<T> observer : observers.values()) {
|
||||
for (Observer<T> observer : observers.values())
|
||||
observer.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(T args) {
|
||||
for (Observer<T> observer : observers.values()) {
|
||||
for (Observer<T> observer : observers.values())
|
||||
observer.onNext(args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -21,19 +21,22 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
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>
|
||||
* Also used to:
|
||||
* <p>
|
||||
* <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>
|
||||
* </ul>
|
||||
*/
|
||||
public final class AtomicObservableSubscription implements Subscription {
|
||||
|
||||
private AtomicReference<Subscription> actualSubscription = new AtomicReference<Subscription>();
|
||||
private AtomicBoolean unsubscribed = new AtomicBoolean(false);
|
||||
private final AtomicReference<Subscription> actualSubscription = new AtomicReference<>();
|
||||
private final AtomicBoolean unsubscribed = new AtomicBoolean(false);
|
||||
|
||||
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
|
||||
* @throws IllegalStateException
|
||||
* if trying to set more than once (or use this method after setting via constructor)
|
||||
* @throws IllegalStateException if trying to set more than once (or use
|
||||
* this method after setting via constructor)
|
||||
*/
|
||||
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.");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
@ -23,7 +23,8 @@ import java.util.List;
|
||||
/**
|
||||
* Exception that is a composite of 1 or more other exceptions.
|
||||
* <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 {
|
||||
|
||||
@ -34,16 +35,14 @@ public class CompositeException extends RuntimeException {
|
||||
|
||||
public CompositeException(String messagePrefix, Collection<Exception> errors) {
|
||||
StringBuilder _message = new StringBuilder();
|
||||
if (messagePrefix != null) {
|
||||
if (messagePrefix != null)
|
||||
_message.append(messagePrefix).append(" => ");
|
||||
}
|
||||
|
||||
List<Exception> _exceptions = new ArrayList<Exception>();
|
||||
List<Exception> _exceptions = new ArrayList<>();
|
||||
for (Exception e : errors) {
|
||||
_exceptions.add(e);
|
||||
if (_message.length() > 0) {
|
||||
if (_message.length() > 0)
|
||||
_message.append(", ");
|
||||
}
|
||||
_message.append(e.getClass().getSimpleName()).append(":").append(e.getMessage());
|
||||
}
|
||||
this.exceptions = Collections.unmodifiableList(_exceptions);
|
||||
@ -62,4 +61,4 @@ public class CompositeException extends RuntimeException {
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ launcher.update_launcher=Check for update
|
||||
launcher.enable_shadow=Enable Window Shadow
|
||||
launcher.theme=Theme
|
||||
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.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.theme=\u4e3b\u9898
|
||||
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.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.theme=\u4e3b\u9898
|
||||
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.main=\u4e3b\u9875
|
||||
|
Loading…
x
Reference in New Issue
Block a user