forked from External/mage
GUI: added changeable card popup mode for chats/logs by card name clicks (alternative to mouse wheel from game cards);
other: fixed duplicated chat popups in game, added miss error logs from popup related code, added additional checks for good code usage;
This commit is contained in:
parent
785f6973b9
commit
4500b79008
12 changed files with 129 additions and 70 deletions
|
|
@ -2,7 +2,6 @@ package mage.cards.action;
|
|||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
|
||||
public interface ActionCallback {
|
||||
|
||||
|
|
@ -20,7 +19,7 @@ public interface ActionCallback {
|
|||
|
||||
void mouseExited(MouseEvent e, TransferData data);
|
||||
|
||||
void mouseWheelMoved(MouseWheelEvent e, TransferData data);
|
||||
void mouseWheelMoved(int mouseWheelRotation, TransferData data);
|
||||
|
||||
void hideOpenComponents();
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class EmptyCallback implements ActionCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e, TransferData data) {
|
||||
public void mouseWheelMoved(int mouseWheelRotation, TransferData data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import mage.util.CardUtil;
|
|||
import mage.util.MultiAmountMessage;
|
||||
import mage.util.RandomUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.text.DateFormat;
|
||||
|
|
@ -917,4 +918,11 @@ public final class SystemUtil {
|
|||
throw new IllegalArgumentException("Wrong code usage: client commands code must run in CALL threads, but used in " + name, new Throwable());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureRunInGUISwingThread() {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
// hot-to fix: run GUI changeable code by SwingUtilities.invokeLater(() -> {xxx})
|
||||
throw new IllegalArgumentException("Wrong code usage: GUI related code must run in SWING thread by SwingUtilities.invokeLater", new Throwable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,66 +1,65 @@
|
|||
package mage.utils;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* Util method to work with threads.
|
||||
*
|
||||
* @author ayrat
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ThreadUtils {
|
||||
|
||||
public static final ThreadPoolExecutor threadPool;
|
||||
public static final ThreadPoolExecutor threadPool2;
|
||||
public static final ThreadPoolExecutor threadPool3;
|
||||
private static final Logger logger = Logger.getLogger(ThreadUtils.class);
|
||||
|
||||
public static final ThreadPoolExecutor threadPoolSounds;
|
||||
public static final ThreadPoolExecutor threadPoolPopups;
|
||||
private static int threadCount;
|
||||
|
||||
static {
|
||||
/**
|
||||
* used in CardInfoPaneImpl
|
||||
*
|
||||
*/
|
||||
threadPool = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
threadPoolSounds = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
threadCount++;
|
||||
Thread thread = new Thread(runnable, "Util" + threadCount);
|
||||
Thread thread = new Thread(runnable, "SOUND-" + threadCount);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
threadPool.prestartAllCoreThreads();
|
||||
}) {
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
super.afterExecute(r, t);
|
||||
t = findRealException(r, t);
|
||||
if (t != null) {
|
||||
// TODO: show sound errors in client logs?
|
||||
//logger.error("Catch unhandled error in SOUND thread: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
};
|
||||
threadPoolSounds.prestartAllCoreThreads();
|
||||
|
||||
/**
|
||||
* Used for MageActionCallback
|
||||
*/
|
||||
threadPool2 = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
threadPoolPopups = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
threadCount++;
|
||||
Thread thread = new Thread(runnable, "TP2" + threadCount);
|
||||
Thread thread = new Thread(runnable, "POPUP-" + threadCount);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
threadPool2.prestartAllCoreThreads();
|
||||
/**
|
||||
* Used for Enlarged view
|
||||
*/
|
||||
}) {
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
super.afterExecute(r, t);
|
||||
|
||||
threadPool3 = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
threadCount++;
|
||||
Thread thread = new Thread(runnable, "EV" + threadCount);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
// catch errors in popup threads (example: card popup over cards or chat/log messages)
|
||||
t = findRealException(r, t);
|
||||
if (t != null) {
|
||||
logger.error("Catch unhandled error in POPUP thread: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
});
|
||||
threadPool3.prestartAllCoreThreads();
|
||||
};
|
||||
threadPoolPopups.prestartAllCoreThreads();
|
||||
}
|
||||
|
||||
public static void sleep(int millis) {
|
||||
|
|
@ -78,4 +77,28 @@ public final class ThreadUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find real exception object after thread task completed. Can be used in afterExecute
|
||||
*
|
||||
* @param r
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public static Throwable findRealException(Runnable r, Throwable t) {
|
||||
// executer.submit - return exception in result
|
||||
// executer.execute - return exception in t
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Object result = ((Future<?>) r).get();
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt(); // ignore/reset
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue