GUI: reworked GUI to support non-blocking UI:

- GUI: added non-blocking UI to almost all app and game dialogs;
- GUI: it allows to switch between UI dialogs and use any UI elements at any moment;
- GUI: it allows to use chat, card popup, battlefield, concede and other features while choosing (related to #12670);
- GUI: it allows to download images while playing (related to #4160, not fully tested);
- GUI: enabled by default, can be disabled by java option: -Dxmage.guiModalMode=true
- connection: auto-connect will be visible in main menu on startup;
- connection: removed some unused features (auto-connect by command line);
- connection: added <ESC> button to close connection dialog;
- download: added background images download (see non-blocking UI);
- download: improved cancel stability and fixes that it can't stop preparing/downloading process in some use cases;
- app: fixed freezes on macOS systems in some use cases (related to #12431, #11292, #9300, #4920);
This commit is contained in:
Oleg Agafonov 2024-09-08 00:40:13 +04:00
parent 2fc4e94b3a
commit 6625db1be1
40 changed files with 614 additions and 532 deletions

View file

@ -94,11 +94,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
private static final String LITE_MODE_ARG = "-lite";
private static final String GRAY_MODE_ARG = "-gray";
private static final String FULL_SCREEN_PROP = "xmage.fullScreen"; // -Dxmage.fullScreen=false
private static final String GUI_MODAL_MODE_PROP = "xmage.guiModalMode"; // -Dxmage.guiModalMode=false
private static final String SKIP_DONE_SYMBOLS = "-skipDoneSymbols";
private static final String USER_ARG = "-user";
private static final String PASSWORD_ARG = "-pw";
private static final String SERVER_ARG = "-server";
private static final String PORT_ARG = "-port";
private static final String DEBUG_ARG = "-debug"; // enable debug button in main menu
private static final String NOT_CONNECTED_TEXT = "<not connected>";
@ -121,11 +118,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
private static boolean grayMode = false;
private static boolean macOsFullScreenEnabled = true;
private static boolean skipSmallSymbolGenerationForExisting = false;
private static String startUser = null;
private static String startPassword = "";
private static String startServer = "localhost";
private static int startPort = -1;
private static boolean debugMode = false;
private static boolean guiModalModeEnabled = false; // non-blocking UI mode enabled by default
private JToggleButton switchPanelsButton = null; // from main menu
private static String SWITCH_PANELS_BUTTON_NAME = "Switch panels";
@ -167,6 +161,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
return skipSmallSymbolGenerationForExisting;
}
public static boolean isGuiModalModeEnabled() {
return guiModalModeEnabled;
}
@Override
public MageVersion getVersion() {
return VERSION;
@ -305,10 +303,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
SessionHandler.startSession(this);
callbackClient = new CallbackClientImpl(this);
connectDialog = new ConnectDialog();
desktopPane.add(connectDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(connectDialog, connectDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
errorDialog = new ErrorDialog();
errorDialog.setLocation(100, 100);
desktopPane.add(errorDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(errorDialog, errorDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
try {
this.whatsNewDialog = new WhatsNewDialog();
@ -387,15 +385,16 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
setGUISize();
setConnectButtonText(NOT_CONNECTED_BUTTON);
SwingUtilities.invokeLater(() -> {
disableButtons();
updateMemUsageTask.execute();
LOGGER.info("Client start up time: " + ((System.currentTimeMillis() - startTime) / 1000 + " seconds"));
if (autoConnect()) {
enableButtons();
if (Boolean.parseBoolean(MageFrame.getPreferences().get("autoConnect", "false"))) {
startAutoConnect();
} else {
connectDialog.showDialog();
connectDialog.showDialog(this::setWindowTitle);
}
setWindowTitle();
setWindowTitle(); // make sure title is actual on startup
});
// run what's new checks (loading in background)
@ -866,13 +865,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void showGameEndDialog(GameEndView gameEndView) {
GameEndDialog gameEndDialog = new GameEndDialog(gameEndView);
desktopPane.add(gameEndDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(gameEndDialog, gameEndDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
gameEndDialog.showDialog();
}
public void showTableWaitingDialog(UUID roomId, UUID tableId, boolean isTournament) {
TableWaitingDialog tableWaitingDialog = new TableWaitingDialog();
desktopPane.add(tableWaitingDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(tableWaitingDialog, tableWaitingDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
tableWaitingDialog.showDialog(roomId, tableId, isTournament);
}
@ -886,14 +885,23 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
return SessionHandler.stopConnecting();
}
public boolean autoConnect() {
boolean autoConnectParamValue = startUser != null || Boolean.parseBoolean(MageFrame.getPreferences().get("autoConnect", "false"));
boolean status = false;
if (autoConnectParamValue) {
LOGGER.info("Auto-connecting to " + MagePreferences.getServerAddress());
status = performConnect(false);
}
return status;
public void startAutoConnect() {
LOGGER.info("Auto-connecting to " + MagePreferences.getServerAddress());
setConnectButtonText("AUTO-CONNECT to " + MagePreferences.getLastServerAddress());
SwingUtilities.invokeLater(() -> {
// TODO: run it as task, not in GUI thread - it can help to enable auto-connect cancel button like ConnectionDialog
boolean isConnected = false;
try {
isConnected = performConnect(false);
} finally {
// on bad - change text manual
// on good - it will be changed inside connection code
if (!isConnected) {
setConnectButtonText(NOT_CONNECTED_BUTTON);
}
}
});
}
private boolean performConnect(boolean reconnect) {
@ -907,7 +915,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
ProxyType proxyType = ProxyType.valueByText(MageFrame.getPreferences().get("proxyType", "None"));
String proxyUsername = MageFrame.getPreferences().get("proxyUsername", "");
String proxyPassword = MageFrame.getPreferences().get("proxyPassword", "");
setCursor(new Cursor(Cursor.WAIT_CURSOR));
currentConnection = new Connection();
currentConnection.setUsername(userName);
currentConnection.setPassword(password);
@ -927,6 +934,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
setUserPrefsToConnection(currentConnection);
}
setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
LOGGER.debug("connecting (auto): " + currentConnection.getProxyType().toString()
+ ' ' + currentConnection.getProxyHost() + ' ' + currentConnection.getProxyPort() + ' ' + currentConnection.getProxyUsername());
@ -1172,13 +1180,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
if (SessionHandler.isConnected()) {
tryDisconnectOrExit(false);
} else {
connectDialog.showDialog();
setWindowTitle();
connectDialog.showDialog(this::setWindowTitle);
}
}//GEN-LAST:event_btnConnectActionPerformed
public void btnAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAboutActionPerformed
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.MODAL_LAYER);
JInternalFrame[] windows = desktopPane.getAllFrames();
for (JInternalFrame window : windows) {
if (window instanceof AboutDialog) {
// don't open the window twice.
@ -1186,7 +1193,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
AboutDialog aboutDialog = new AboutDialog();
desktopPane.add(aboutDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(aboutDialog, aboutDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
aboutDialog.showDialog(VERSION);
}//GEN-LAST:event_btnAboutActionPerformed
@ -1286,16 +1293,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
public void enableButtons() {
btnConnect.setEnabled(true);
btnDeckEditor.setEnabled(true);
}
public void disableButtons() {
btnConnect.setEnabled(true);
btnDeckEditor.setEnabled(true);
}
public void hideServerLobby() {
this.tablesPane.hideTables();
updateSwitchPanelsButton();
@ -1416,7 +1413,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
private void innerShowUserRequestDialog(final UserRequestMessage userRequestMessage) {
UserRequestDialog userRequestDialog = new UserRequestDialog();
userRequestDialog.setLocation(100, 100);
desktopPane.add(userRequestDialog, JLayeredPane.MODAL_LAYER);
desktopPane.add(userRequestDialog, userRequestDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
userRequestDialog.showDialog(userRequestMessage);
}
@ -1463,8 +1460,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void showErrorDialog(String errorType, String errorTitle, String errorText) {
if (SwingUtilities.isEventDispatchThread()) {
// calls from gui
errorDialog.showDialog(errorType, errorTitle, errorText);
} else {
// calls from another thread like download images or game events
SwingUtilities.invokeLater(() -> errorDialog.showDialog(errorType, errorTitle, errorText));
}
}
@ -1519,33 +1518,21 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
if (arg.startsWith(GRAY_MODE_ARG)) {
grayMode = true;
}
if (System.getProperty(FULL_SCREEN_PROP) != null) {
macOsFullScreenEnabled = Boolean.parseBoolean(System.getProperty(FULL_SCREEN_PROP));
}
if (arg.startsWith(SKIP_DONE_SYMBOLS)) {
skipSmallSymbolGenerationForExisting = true;
}
if (arg.startsWith(USER_ARG)) {
startUser = args[i + 1];
i++;
}
if (arg.startsWith(PASSWORD_ARG)) {
startPassword = args[i + 1];
i++;
}
if (arg.startsWith(SERVER_ARG)) {
startServer = args[i + 1];
i++;
}
if (arg.startsWith(PORT_ARG)) {
startPort = Integer.parseInt(args[i + 1]);
i++;
}
if (arg.startsWith(DEBUG_ARG)) {
debugMode = true;
}
}
if (System.getProperty(FULL_SCREEN_PROP) != null) {
macOsFullScreenEnabled = Boolean.parseBoolean(System.getProperty(FULL_SCREEN_PROP));
}
if (System.getProperty(GUI_MODAL_MODE_PROP) != null) {
guiModalModeEnabled = Boolean.parseBoolean(System.getProperty(GUI_MODAL_MODE_PROP));
}
// enable debug menu by default for developer build (if you run it from source code)
debugMode |= VERSION.isDeveloperBuild();
@ -1571,19 +1558,19 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
if (settingsVersion == 0) {
// fresh install or first run after 2024-08-14
// find best GUI size settings due screen resolution and DPI
LOGGER.info("settings: it's a first run, trying to apply GUI size settings");
LOGGER.info("Settings: it's a first run, trying to apply GUI size settings");
int screenDPI = Toolkit.getDefaultToolkit().getScreenResolution();
int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
LOGGER.info(String.format("settings: screen DPI - %d, screen height - %d", screenDPI, screenHeight));
LOGGER.info(String.format("Settings: screen DPI - %d, screen height - %d", screenDPI, screenHeight));
// find preset for
String preset = PreferencesDialog.getDefaultSizeSettings().findBestPreset(screenDPI, screenHeight);
if (preset != null) {
LOGGER.info("settings: selected preset " + preset);
LOGGER.info("Settings: selected preset " + preset);
PreferencesDialog.getDefaultSizeSettings().applyPreset(preset);
} else {
LOGGER.info("settings: WARNING, can't find compatible preset, use Preferences - GUI Size to setup your app");
LOGGER.info("Settings: WARNING, can't find compatible preset, use Preferences - GUI Size to setup your app");
}
PreferencesDialog.saveValue(PreferencesDialog.KEY_SETTINGS_VERSION, String.valueOf(1));
@ -1598,21 +1585,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
// debug menu
if (debugMode) {
LOGGER.info("Settings: debug menu enabled");
}
instance.separatorDebug.setVisible(debugMode);
instance.btnDebug.setVisible(debugMode);
if (startUser != null) {
instance.currentConnection = new Connection();
instance.currentConnection.setUsername(startUser);
instance.currentConnection.setHost(startServer);
if (startPort > 0) {
instance.currentConnection.setPort(startPort);
} else {
instance.currentConnection.setPort(MagePreferences.getServerPortWithDefault(ClientDefaultSettings.port));
}
PreferencesDialog.setProxyInformation(instance.currentConnection);
instance.currentConnection.setPassword(startPassword);
}
instance.setVisible(true);
});
}
@ -1735,7 +1713,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void connected(final String message) {
SwingUtilities.invokeLater(() -> {
setConnectButtonText(message);
enableButtons();
});
}
@ -1756,7 +1733,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
// TODO: why it ignore askToReconnect here, but use custom reconnect dialog later?! Need research
SessionHandler.disconnect(false, keepMySessionActive);
setConnectButtonText(NOT_CONNECTED_BUTTON);
disableButtons();
hideGames();
hideServerLobby();
if (askToReconnect) {
@ -1845,9 +1821,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
SessionHandler.removeTable(userRequestMessage.getRoomId(), userRequestMessage.getTableId());
break;
case CLIENT_RECONNECT:
if (performConnect(true)) {
enableButtons();
}
performConnect(true);
break;
case CLIENT_REPLAY_ACTION:
SessionHandler.stopReplay(userRequestMessage.getGameId());

View file

@ -224,7 +224,12 @@ public class DeckGeneratorDialog {
dlg = optionPane.createDialog("Generating Deck");
dlg.setResizable(false);
dlg.setVisible(true);
dlg.dispose();
if (dlg.isModal()) {
// on modal - it's done here
dlg.dispose();
} else {
// on non-modal - it's do nothing yet
}
}
private void enableAdvancedPanel(boolean enable) {

View file

@ -1468,44 +1468,45 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed
// search and check multiple items
int[] oldChecks = listCodeSelected.getCheckedIndices();
final int[] oldChecks = listCodeSelected.getCheckedIndices();
// call dialog
FastSearchUtil.showFastSearchForStringComboBox(listCodeSelected, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
int[] newChecks = listCodeSelected.getCheckedIndices();
if (Arrays.equals(oldChecks, newChecks)) {
// no changes or cancel
return;
}
isSetsFilterLoading = true;
try {
// delete old item
if (cbExpansionSet.getItemAt(0).startsWith(MULTI_SETS_SELECTION_TEXT)) {
cbExpansionSet.removeItemAt(0);
FastSearchUtil.showFastSearchForStringComboBox(listCodeSelected, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE, () -> {
// data update on good choice
int[] newChecks = listCodeSelected.getCheckedIndices();
if (Arrays.equals(oldChecks, newChecks)) {
// no changes or cancel
return;
}
// set new selection
if (newChecks.length == 0) {
// all
cbExpansionSet.setSelectedIndex(0);
} else if (newChecks.length == 1) {
// one
setSetsSelection(listCodeSelected.getModel().getElementAt(newChecks[0]).toString());
} else {
// multiple
// insert custom text
String message = String.format("%s: %d", MULTI_SETS_SELECTION_TEXT, newChecks.length);
cbExpansionSet.insertItemAt(message, 0);
cbExpansionSet.setSelectedIndex(0);
}
} finally {
isSetsFilterLoading = false;
}
isSetsFilterLoading = true;
try {
// delete old item
if (cbExpansionSet.getItemAt(0).startsWith(MULTI_SETS_SELECTION_TEXT)) {
cbExpansionSet.removeItemAt(0);
}
// update data
filterCards();
// set new selection
if (newChecks.length == 0) {
// all
cbExpansionSet.setSelectedIndex(0);
} else if (newChecks.length == 1) {
// one
setSetsSelection(listCodeSelected.getModel().getElementAt(newChecks[0]).toString());
} else {
// multiple
// insert custom text
String message = String.format("%s: %d", MULTI_SETS_SELECTION_TEXT, newChecks.length);
cbExpansionSet.insertItemAt(message, 0);
cbExpansionSet.setSelectedIndex(0);
}
} finally {
isSetsFilterLoading = false;
}
// update data
filterCards();
});
}//GEN-LAST:event_btnExpansionSearchActionPerformed
private void tbCommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbCommonActionPerformed

View file

@ -19,6 +19,7 @@ import mage.client.dialog.AddLandDialog;
import mage.client.dialog.PreferencesDialog;
import mage.client.plugins.impl.Plugins;
import mage.client.util.Event;
import mage.client.util.GUISizeHelper;
import mage.client.util.Listener;
import mage.client.util.audio.AudioManager;
import mage.components.CardInfoPane;
@ -30,6 +31,7 @@ import mage.util.XmageThreadFactory;
import mage.view.CardView;
import mage.view.SimpleCardView;
import org.apache.log4j.Logger;
import org.mage.card.arcane.ManaSymbols;
import javax.swing.*;
import javax.swing.border.Border;
@ -674,7 +676,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}
private void refreshDeck() {
refreshDeck(false);
if (this.isVisible()) { // TODO: test auto-close deck with active lands dialog, e.g. on timeout
refreshDeck(false);
}
}
private void refreshDeck(boolean useLayout) {
@ -786,31 +790,51 @@ public class DeckEditorPanel extends javax.swing.JPanel {
private void importFromClipboard(ActionEvent evt) {
final DeckImportClipboardDialog dialog = new DeckImportClipboardDialog();
dialog.showDialog();
dialog.showDialog(tempDeckPath -> {
if (!tempDeckPath.isEmpty()) {
loadDeck(tempDeckPath, false);
}
});
if (!dialog.getTmpPath().isEmpty()) {
loadDeck(dialog.getTmpPath(), false);
if (dialog.isModal()) {
// on modal - it's done here
dialog.dispose();
} else {
// on non-modal - it's do nothing yet
}
}
private void onImportReady(String deckPath) {
SwingUtilities.invokeLater(() -> {
if (deckPath.isEmpty()) {
loadDeck(deckPath, false);
}
});
}
private void importFromClipboardWithAppend(ActionEvent evt) {
final DeckImportClipboardDialog dialog = new DeckImportClipboardDialog();
dialog.showDialog();
if (!dialog.getTmpPath().isEmpty()) {
StringBuilder errorMessages = new StringBuilder();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
Deck deckToAppend = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages, false), true, true);
processAndShowImportErrors(errorMessages);
this.deck = Deck.append(deckToAppend, this.deck);
refreshDeck();
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
} finally {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
dialog.showDialog(tempDeckPath -> {
if (!tempDeckPath.isEmpty()) {
StringBuilder errorMessages = new StringBuilder();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
Deck deckToAppend = Deck.load(DeckImporter.importDeckFromFile(tempDeckPath, errorMessages, false), true, true);
processAndShowImportErrors(errorMessages);
this.deck = Deck.append(deckToAppend, this.deck);
refreshDeck();
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
} finally {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
});
if (dialog.isModal()) {
// on modal - it's done here
dialog.dispose();
} else {
// on non-modal - it's do nothing yet
}
}
@ -1462,9 +1486,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}//GEN-LAST:event_btnExitActionPerformed
private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed
AddLandDialog addLand = new AddLandDialog();
addLand.showDialog(deck, mode);
refreshDeck();
AddLandDialog dialog = new AddLandDialog();
dialog.showDialog(deck, mode, this::refreshDeck);
}//GEN-LAST:event_btnAddLandActionPerformed
private void btnGenDeckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGenDeckActionPerformed

View file

@ -48,11 +48,7 @@ public class DeckExportClipboardDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"

View file

@ -29,14 +29,18 @@ public class DeckImportClipboardDialog extends MageDialog {
"// Your current clipboard:\n" +
"\n";
private String tmpPath;
private DeckImportClipboardCallback callback = null;
public DeckImportClipboardDialog() {
initComponents();
}
public void showDialog() {
this.tmpPath = "";
public interface DeckImportClipboardCallback {
void onImportDone(String tempDeckPath);
}
public void showDialog(DeckImportClipboardCallback callback) {
this.callback = callback;
onRefreshClipboard();
this.setModal(true);
@ -45,11 +49,7 @@ public class DeckImportClipboardDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"
@ -70,17 +70,24 @@ public class DeckImportClipboardDialog extends MageDialog {
private void onOK() {
String decklist = editData.getText();
decklist = decklist.replace(FORMAT_TEXT, "");
String tempDeckPath;
// This dialog also accepts a paste in .mtga format
if (decklist.startsWith("Deck\n")) { // An .mtga list always starts with the first line being "Deck". This kind of paste is processed as .mtga
tmpPath = DeckUtil.writeTextToTempFile("cbimportdeck", ".mtga", decklist);
} else { // If the paste is not .mtga format, it's processed as plaintext
tmpPath = DeckUtil.writeTextToTempFile(decklist);
tempDeckPath = DeckUtil.writeTextToTempFile("cbimportdeck", ".mtga", decklist);
} else {
// If the paste is not .mtga format, it's processed as plaintext
tempDeckPath = DeckUtil.writeTextToTempFile(decklist);
}
this.removeDialog();
if (this.callback != null) {
callback.onImportDone(tempDeckPath);
}
onCancel();
}
private void onCancel() {
this.removeDialog();
this.removeDialog(); // TODO: combine hideDialog and removeDialog logic for all usages in all dialogs
}
private void onRefreshClipboard() {
@ -88,10 +95,6 @@ public class DeckImportClipboardDialog extends MageDialog {
editData.setCaretPosition(FORMAT_TEXT.length());
}
public String getTmpPath() {
return tmpPath;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always

View file

@ -20,7 +20,6 @@ public class AboutDialog extends MageDialog {
public AboutDialog() {
initComponents();
this.modal = false;
panelDevs.setText(devsList + " and hundreds of other developers from https://github.com/magefree/mage/graphs/contributors");
}
@ -30,11 +29,7 @@ public class AboutDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"

View file

@ -23,15 +23,15 @@ import java.util.TreeSet;
/**
* App GUI: adding new lands to the deck, uses in deck editor and drafting
*
* @author BetaSteward_at_googlemail.com
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class AddLandDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(MageDialog.class);
private Deck deck;
private DeckEditorMode mode;
private AddLandCallback callback = null;
private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40;
@ -40,9 +40,14 @@ public class AddLandDialog extends MageDialog {
this.setModal(true);
}
public void showDialog(Deck deck, DeckEditorMode mode) {
public interface AddLandCallback {
void onLandsAdded();
}
public void showDialog(Deck deck, DeckEditorMode mode, AddLandCallback callback) {
this.deck = deck;
this.mode = mode;
this.callback = callback;
SortedSet<String> landSetNames = new TreeSet<>();
String defaultSetName = null;
if (mode != DeckEditorMode.FREE_BUILDING) {
@ -126,11 +131,7 @@ public class AddLandDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"
@ -214,7 +215,11 @@ public class AddLandDialog extends MageDialog {
addLands("Plains", nPlains, useFullArt);
addLands("Swamp", nSwamp, useFullArt);
this.removeDialog();
if (this.callback != null) {
callback.onLandsAdded();
}
onCancel();
}
/**

View file

@ -14,6 +14,7 @@ import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.*;
import java.net.*;
import java.util.List;
@ -28,21 +29,20 @@ import static mage.client.dialog.PreferencesDialog.*;
/**
* App GUI: connection windows
*
* @author BetaSteward_at_googlemail.com
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class ConnectDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ConnectDialog.class);
private Connection connection;
private ConnectTask task;
private final RegisterUserDialog registerUserDialog;
private final ResetPasswordDialog resetPasswordDialog;
ConnectCallback callback = null;
private final ActionListener connectAction = evt -> btnConnectActionPerformed(evt);
/**
* Creates new form ConnectDialog
*/
public ConnectDialog() {
initComponents();
@ -51,14 +51,18 @@ public class ConnectDialog extends MageDialog {
this.txtUserName.addActionListener(connectAction);
this.txtPassword.addActionListener(connectAction);
registerUserDialog = new RegisterUserDialog(this);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.MODAL_LAYER);
registerUserDialog = new RegisterUserDialog();
MageFrame.getDesktop().add(registerUserDialog, registerUserDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
resetPasswordDialog = new ResetPasswordDialog(this);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.MODAL_LAYER);
resetPasswordDialog = new ResetPasswordDialog();
MageFrame.getDesktop().add(resetPasswordDialog, resetPasswordDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
public void showDialog() {
public interface ConnectCallback {
void onConnectClosed();
}
public void showDialog(ConnectCallback callback) {
this.lblStatus.setText("");
String serverAddress = MagePreferences.getServerAddressWithDefault(ClientDefaultSettings.serverName);
this.txtServer.setText(serverAddress);
@ -77,10 +81,32 @@ public class ConnectDialog extends MageDialog {
}
}
this.setModal(true);
this.setLocation(50, 50);
// windows settings
MageFrame.getDesktop().remove(this);
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
//this.makeWindowCentered();
this.setLocation(50, 50); // make sure it will be visible in any sizes
// Close on "ESC"
registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
this.setVisible(true);
}
private void onCancel() {
MageFrame.getPreferences().put("autoConnect", Boolean.toString(chkAutoConnect.isSelected()));
MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem());
if (task != null && !task.isDone()) {
task.cancel(true);
} else {
this.hideDialog();
if (callback != null) {
callback.onConnectClosed();
}
}
}
private void saveSettings() {
String serverAddress = txtServer.getText().trim();
MagePreferences.setServerAddress(serverAddress);
@ -535,13 +561,7 @@ public class ConnectDialog extends MageDialog {
}// </editor-fold>//GEN-END:initComponents
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
MageFrame.getPreferences().put("autoConnect", Boolean.toString(chkAutoConnect.isSelected()));
MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem());
if (task != null && !task.isDone()) {
task.cancel(true);
} else {
this.hideDialog();
}
onCancel();
}//GEN-LAST:event_btnCancelActionPerformed
private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed
@ -658,6 +678,9 @@ public class ConnectDialog extends MageDialog {
private void doAfterConnected() {
this.saveSettings();
this.hideDialog();
if (this.callback != null) {
this.callback.onConnectClosed();
}
}
private void keyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_keyTyped
@ -689,11 +712,11 @@ public class ConnectDialog extends MageDialog {
}//GEN-LAST:event_txtPasswordActionPerformed
private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed
registerUserDialog.showDialog();
registerUserDialog.showDialog(this.getServer(), this.getPort());
}//GEN-LAST:event_btnRegisterActionPerformed
private void btnForgotPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnForgotPasswordActionPerformed
resetPasswordDialog.showDialog();
resetPasswordDialog.showDialog(this.getServer(), this.getPort());
}//GEN-LAST:event_btnForgotPasswordActionPerformed
private void connectXmageDe(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFind1findPublicServerActionPerformed
@ -795,13 +818,14 @@ public class ConnectDialog extends MageDialog {
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
dlg.setWindowSize(300, 500);
dlg.showDialog(choice, needSelectValue);
if (choice.isChosen()) {
flagItem = new String[2];
flagItem[0] = choice.getChoiceValue();
flagItem[1] = choice.getChoiceKey();
flagModel.setSelectedItem(flagItem);
}
dlg.showDialog(choice, needSelectValue, () -> {
if (choice.isChosen()) {
String[] flag = new String[2];
flag[0] = choice.getChoiceValue();
flag[1] = choice.getChoiceKey();
flagModel.setSelectedItem(flag);
}
});
}
public String getServer() {

View file

@ -12,23 +12,17 @@ import java.util.HashMap;
import java.util.Map;
/**
* App GUI: download card images window
* App GUI: control dialog for card images downloader service
*
* @author JayDi85
*/
public class DownloadImagesDialog extends MageDialog {
public static final int RET_CANCEL = 0;
public static final int RET_OK = 1;
private final Dimension sizeModeMessageOnly;
private final Dimension sizeModeMessageAndControls;
private final Map<Component, Boolean> actionsControlStates = new HashMap<>();
private DownloadImagesCallback callback = null;
/**
* Creates new form DownloadImagesDialog
*/
public DownloadImagesDialog() {
initComponents();
this.setModal(true);
@ -51,7 +45,7 @@ public class DownloadImagesDialog extends MageDialog {
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() {
public void actionPerformed(ActionEvent e) {
doClose(RET_CANCEL);
onCancel();
}
});
}
@ -60,28 +54,27 @@ public class DownloadImagesDialog extends MageDialog {
this.setSize(new Dimension(width, heigth));
}
public void showDialog() {
showDialog(null);
public interface DownloadImagesCallback {
void onDownloadDone();
}
public void showDialog(MageDialogState mageDialogState) {
public void showDialog(DownloadImagesCallback callback) {
// window settings
this.callback = callback;
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
if (mageDialogState != null) mageDialogState.setStateToDialog(this);
else this.makeWindowCentered();
showDownloadControls(false); // call to change window size
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
showDownloadControls(false); // call to change window size and view mode
this.setVisible(true);
}
public void setGlobalInfo(String info) {
// workaround to keep auto-sizeable and centered text
Dimension newSize = new Dimension(Integer.MAX_VALUE, this.labelGlobal.getPreferredSize().height);
this.labelGlobal.setPreferredSize(newSize);
this.labelGlobal.setMaximumSize(newSize);
this.labelGlobal.setHorizontalAlignment(SwingConstants.CENTER);
this.labelGlobal.setText(info);
}
@ -188,13 +181,8 @@ public class DownloadImagesDialog extends MageDialog {
// TODO: add manual mode as tab
this.tabsList.getTabComponentAt(1).setEnabled(false);
this.tabsList.setEnabledAt(1, false);
}
/**
* @return the return status of this dialog - one of RET_OK or RET_CANCEL
*/
public int getReturnStatus() {
return returnStatus;
this.invalidate();
}
/**
@ -432,7 +420,7 @@ public class DownloadImagesDialog extends MageDialog {
* Closes the dialog
*/
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
doClose(RET_CANCEL);
onCancel();
}//GEN-LAST:event_closeDialog
private void buttonSearchSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSearchSetActionPerformed
@ -440,14 +428,15 @@ public class DownloadImagesDialog extends MageDialog {
}//GEN-LAST:event_buttonSearchSetActionPerformed
private void buttonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopActionPerformed
// TODO add your handling code here:
// TODO implement stop feature for cancel button
}//GEN-LAST:event_buttonStopActionPerformed
private void doClose(int retStatus) {
returnStatus = retStatus;
setVisible(false);
dispose();
private void onCancel() {
// it's only control GUI, all works in download service
hideDialog();
if (this.callback != null) {
this.callback.onDownloadDone();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
@ -493,6 +482,4 @@ public class DownloadImagesDialog extends MageDialog {
private javax.swing.JPanel tabMain;
private javax.swing.JTabbedPane tabsList;
// End of variables declaration//GEN-END:variables
private int returnStatus = RET_CANCEL;
}

View file

@ -7,6 +7,7 @@ import mage.util.CardUtil;
/**
* GUI: error dialog with copyable error message
* // TODO: add game logs and data for game errors (client side info from GameView)
*
* @author JayDi85
*/

View file

@ -194,7 +194,6 @@ public class FeedbackDialog extends javax.swing.JDialog {
}// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dialog.setVisible(false);
dialog.dispose();
}//GEN-LAST:event_cancelButtonActionPerformed

View file

@ -33,7 +33,7 @@
*/
public GameEndDialog(GameEndView gameEndView) {
initComponents();
this.modal = true;
setModal(true);
pnlText.setOpaque(true);
pnlText.setBackground(new Color(240, 240, 240, 140));

View file

@ -11,7 +11,7 @@ import javax.swing.*;
import java.util.UUID;
/**
* App GUI: join to the new game window
* App GUI: join to table (client side dialog to choose deck and enter pass)
*
* @author BetaSteward_at_googlemail.com
*/
@ -120,6 +120,7 @@ public class JoinTableDialog extends MageDialog {
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
Session session = SessionHandler.getSession();
try {
// remember pass for next joins
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, txtPassword.getText());
if (isTournament) {
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile(), true), this.txtPassword.getText());

View file

@ -16,13 +16,22 @@ import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
/**
* GUI: basic class for all dialogs
* <p>
* WARNING, make sure you don't wait results after showXXX call -- use callback function instead
* <p>
* TODO: research and make sure all dialogs can be called one time and clean on main form close
* bad example: deck editor can call multiple PickCheckBoxDialog instances (not critical)
* TODO: migrate all JInternalFrame and other dialogs to MageDialog and support non modal
* TODO: must add clean code on doClose for all dialogs? See PickPileDialog for example (cleanUp, removeDialog)
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class MageDialog extends javax.swing.JInternalFrame {
private static final Logger LOGGER = Logger.getLogger(MageDialog.class);
protected boolean modal = false;
private boolean modal = false; // warning, app can work in non-modal mode, so make sure result processing on callback
// GUI performance and bugs issues:
// TODO: swing components should override paintComponent() instead paint()
@ -232,7 +241,7 @@ public class MageDialog extends javax.swing.JInternalFrame {
}
public void setModal(boolean modal) {
this.modal = modal;
this.modal = MageFrame.isGuiModalModeEnabled() && modal;
}
public boolean isModal() {

View file

@ -35,7 +35,7 @@ public class NewTableDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(NewTableDialog.class);
private CustomOptionsDialog customOptions;
private final CustomOptionsDialog customOptions;
private TableView table;
private UUID playerId;
private UUID roomId;
@ -45,14 +45,11 @@ public class NewTableDialog extends MageDialog {
private static final String LIMITED = "Limited";
/**
* Creates new form NewTableDialog
*/
public NewTableDialog() {
lastSessionId = "";
initComponents();
this.customOptions = new CustomOptionsDialog(CustomOptionsDialog.SaveLoadKeys.TABLE, btnCustomOptions);
MageFrame.getDesktop().add(customOptions, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(customOptions, customOptions.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
player1Panel.showLevel(false);
this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1));
this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5));
@ -480,12 +477,19 @@ public class NewTableDialog extends MageDialog {
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.table = null;
this.playerId = null;
this.hideDialog();
doClose();
}//GEN-LAST:event_btnCancelActionPerformed
private void btnPreviousConfigurationActionPerformed(java.awt.event.ActionEvent evt, int i) {//GEN-FIRST:event_btnPreviousConfigurationActionPerformed
}//GEN-LAST:event_btnPreviousConfigurationActionPerformed
private void doClose() {
if (this.customOptions.isVisible()) {
this.customOptions.hideDialog();
}
this.hideDialog();
}
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
MatchOptions options = getMatchOptions();
@ -524,7 +528,7 @@ public class NewTableDialog extends MageDialog {
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile(), true),
this.txtPassword.getText())) {
// all fine, can close create dialog (join dialog will be opened after feedback from server)
this.hideDialog();
doClose();
return;
}
} catch (ClassNotFoundException | IOException ex) {

View file

@ -44,7 +44,7 @@ public class NewTournamentDialog extends MageDialog {
private UUID roomId;
private String lastSessionId;
private RandomPacksSelectorDialog randomPackSelector;
private CustomOptionsDialog customOptions;
private final CustomOptionsDialog customOptions;
private JTextArea txtRandomPacks;
private final java.util.List<TournamentPlayerPanel> players = new ArrayList<>();
private final java.util.List<JPanel> packPanels = new ArrayList<>();
@ -60,7 +60,7 @@ public class NewTournamentDialog extends MageDialog {
public NewTournamentDialog() {
initComponents();
this.customOptions = new CustomOptionsDialog(CustomOptionsDialog.SaveLoadKeys.TOURNEY, btnCustomOptions);
MageFrame.getDesktop().add(customOptions, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(customOptions, customOptions.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
lastSessionId = "";
txtName.setText("Tournament");
this.spnNumWins.setModel(new SpinnerNumberModel(2, 1, 5, 1));
@ -657,6 +657,13 @@ public class NewTournamentDialog extends MageDialog {
}//GEN-LAST:event_cbTournamentTypeActionPerformed
private void doClose() {
if (this.customOptions.isVisible()) {
this.customOptions.hideDialog();
}
this.hideDialog();
}
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed
// get settings
@ -714,7 +721,7 @@ public class NewTournamentDialog extends MageDialog {
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile(), true),
tOptions.getPassword())) {
// all fine, can close create dialog (join dialog will be opened after feedback from server)
this.hideDialog();
doClose();
return;
}
@ -726,7 +733,7 @@ public class NewTournamentDialog extends MageDialog {
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.table = null;
// this.playerId = null;
this.hideDialog();
doClose();
}//GEN-LAST:event_btnCancelActionPerformed
private void updateNumSeats() {

View file

@ -28,41 +28,30 @@ public class PickCheckBoxDialog extends MageDialog {
CheckBoxList tList;
int[] startingCheckboxes; // restore to it on cancel
PickCheckBoxCallback callback = null;
final private static String HTML_TEMPLATE = "<html><div style='text-align: center;'>%s</div></html>";
private void setFocus(CheckBoxList obj) {
if (!(obj instanceof java.awt.Component)) {
throw new IllegalArgumentException("Must be a java.awt.Component!");
}
this.scrollList.setViewportView(obj);
public interface PickCheckBoxCallback {
void onChoiceDone();
}
private javax.swing.JList get_a_Jlist_from_ScrollListView() {
return ((javax.swing.JList) this.scrollList.getViewport().getView());
public void showDialog(Choice choice, PickCheckBoxCallback callback) {
showDialog(choice, null, null, null, callback);
}
private void restoreData(Object dataFrom) {
this.allItems.forEach((item) -> {
((CheckBoxList.CheckBoxListModel) dataFrom).addElement(item.getObjectValue());
});
public void showDialog(Choice choice, String startSelectionValue, PickCheckBoxCallback callback) {
showDialog(choice, null, null, startSelectionValue, callback);
}
public void showDialog(Choice choice) {
showDialog(choice, null, null, null);
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, PickCheckBoxCallback callback) {
showDialog(choice, objectId, mageDialogState, null, callback);
}
public void showDialog(Choice choice, String startSelectionValue) {
showDialog(choice, null, null, startSelectionValue);
}
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) {
showDialog(choice, objectId, mageDialogState, null);
}
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) {
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue, PickCheckBoxCallback callback) {
this.choice = choice;
this.callback = callback;
KeyValueItem tempKeyValue;
int indexInTList;
@ -186,11 +175,7 @@ public class PickCheckBoxDialog extends MageDialog {
// window settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
if (mageDialogState != null) mageDialogState.setStateToDialog(this);
else this.makeWindowCentered();
@ -223,6 +208,23 @@ public class PickCheckBoxDialog extends MageDialog {
this.setVisible(true);
}
private void setFocus(CheckBoxList obj) {
if (!(obj instanceof java.awt.Component)) {
throw new IllegalArgumentException("Must be a java.awt.Component!");
}
this.scrollList.setViewportView(obj);
}
private javax.swing.JList get_a_Jlist_from_ScrollListView() {
return ((javax.swing.JList) this.scrollList.getViewport().getView());
}
private void restoreData(Object dataFrom) {
this.allItems.forEach((item) -> {
((CheckBoxList.CheckBoxListModel) dataFrom).addElement(item.getObjectValue());
});
}
public void setWindowSize(int width, int heigth) {
this.setSize(new Dimension(width, heigth));
}
@ -276,7 +278,7 @@ public class PickCheckBoxDialog extends MageDialog {
if ((tList != null) || (setChoice())) {
this.m_dataModel.clear();
restoreData(this.m_dataModel);
this.hideDialog();
doClose();
}
}
@ -289,14 +291,16 @@ public class PickCheckBoxDialog extends MageDialog {
this.listChoices.clearSelection();
this.choice.clearChoice();
hideDialog();
doClose();
}
private void doClose() {
this.hideDialog();
if (this.callback != null) {
this.callback.onChoiceDone();
}
}
/**
* Creates new form PickChoiceDialog
*
* @param list
*/
public PickCheckBoxDialog(CheckBoxList list) {
initComponents();
tList = list;

View file

@ -40,6 +40,7 @@ public class PickChoiceDialog extends MageDialog {
java.util.List<KeyValueItem> allItems = new ArrayList<>();
KeyValueItem biggestItem = null; // for render optimization
PickChoiceCallback callback = null;
final private static String HTML_HEADERS_TEMPLATE = "<html><div style='text-align: center;'>%s</div></html>";
@ -58,14 +59,19 @@ public class PickChoiceDialog extends MageDialog {
this.setModal(true);
}
public void showDialog(Choice choice, String startSelectionValue) {
showDialog(choice, startSelectionValue, null, null, null);
public interface PickChoiceCallback {
void onChoiceDone();
}
public void showDialog(Choice choice, String startSelectionValue, UUID objectId, MageDialogState mageDialogState, BigCard bigCard) {
public void showDialog(Choice choice, String startSelectionValue, PickChoiceCallback callback) {
showDialog(choice, startSelectionValue, null, null, null, callback);
}
public void showDialog(Choice choice, String startSelectionValue, UUID objectId, MageDialogState mageDialogState, BigCard bigCard, PickChoiceCallback callback) {
this.choice = choice;
this.bigCard = bigCard;
this.gameId = objectId;
this.callback = callback;
changeGUISize();
@ -244,11 +250,7 @@ public class PickChoiceDialog extends MageDialog {
// window settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
if (mageDialogState != null) {
mageDialogState.setStateToDialog(this);
} else {
@ -421,14 +423,21 @@ public class PickChoiceDialog extends MageDialog {
private void doChoose() {
if (setChoice()) {
this.hideDialog();
doClose();
}
}
private void doCancel() {
this.listChoices.clearSelection();
this.choice.clearChoice();
hideDialog();
doClose();
}
private void doClose() {
this.hideDialog();
if (this.callback != null) {
this.callback.onChoiceDone();
}
}
public boolean setChoice() {

View file

@ -14,12 +14,15 @@ import java.util.Map;
import java.util.stream.Collectors;
/**
* Game GUI: dialog to distribute values between multiple items
* (used for some cards and add lands in cheat menu, search by MultiAmountMessage)
*
* @author weirddan455
*/
public class PickMultiNumberDialog extends MageDialog {
private boolean cancel;
private PickMultiNumberCallback callback = null;
private List<JLabel> labelList = null;
private List<JSpinner> spinnerList = null;
@ -29,7 +32,14 @@ public class PickMultiNumberDialog extends MageDialog {
this.setModal(true);
}
public void showDialog(List<MultiAmountMessage> messages, int min, int max, Map<String, Serializable> options) {
public interface PickMultiNumberCallback {
void onChoiceDone();
}
public void showDialog(List<MultiAmountMessage> messages, int min, int max, Map<String, Serializable> options, PickMultiNumberCallback callback) {
this.cancel = false;
this.callback = callback;
this.header.setText("<html>" + ManaSymbols.replaceSymbolsWithHTML((String) options.get("header"), ManaSymbols.Type.DIALOG));
this.setTitle((String) options.get("title"));
@ -142,6 +152,13 @@ public class PickMultiNumberDialog extends MageDialog {
return cancel;
}
private void doClose() {
this.hideDialog();
if (this.callback != null) {
this.callback.onChoiceDone();
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -231,12 +248,12 @@ public class PickMultiNumberDialog extends MageDialog {
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed
this.cancel = false;
this.hideDialog();
doClose();
}//GEN-LAST:event_btnOkActionPerformed
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.cancel = true;
this.hideDialog();
doClose();
}//GEN-LAST:event_btnCancelActionPerformed

View file

@ -9,13 +9,14 @@ import java.util.ArrayList;
import java.util.List;
/**
* Game GUI: choose number
* Game GUI: choose number dialog
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class PickNumberDialog extends MageDialog {
private boolean cancel;
private PickNumberCallback callback = null;
public PickNumberDialog() {
initComponents();
@ -24,10 +25,15 @@ public class PickNumberDialog extends MageDialog {
this.setModal(true);
}
public void showDialog(int min, int max, String message) {
public interface PickNumberCallback {
void onChoiceDone();
}
public void showDialog(int min, int max, String message, PickNumberCallback callback) {
this.editAmount.setModel(new SpinnerNumberModel(min, min, max, 1));
this.textMessage.setContentType("text/html");
this.textMessage.setText(message);
this.callback = callback;
List<String> limits = new ArrayList<>();
if (min != Integer.MIN_VALUE) {
@ -42,11 +48,7 @@ public class PickNumberDialog extends MageDialog {
// window settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.getRootPane().setDefaultButton(this.buttonOk); // restore default button after root panel change (no need actually)
@ -73,7 +75,7 @@ public class PickNumberDialog extends MageDialog {
this.makeWindowCentered();
// TODO: need to fix focus restore on second popup (it's not focues, test on Manamorphose)
// TODO: need to fix focus restore on second popup (it's not get focus, test on Manamorphose)
this.setVisible(true);
}
@ -85,6 +87,13 @@ public class PickNumberDialog extends MageDialog {
return cancel;
}
private void doClose() {
this.hideDialog();
if (this.callback != null) {
this.callback.onChoiceDone();
}
}
/**
* This method is called from within the constructor to
* initialize the form.
@ -188,12 +197,12 @@ public class PickNumberDialog extends MageDialog {
private void buttonOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOkActionPerformed
this.cancel = false;
this.hideDialog();
doClose();
}//GEN-LAST:event_buttonOkActionPerformed
private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed
this.cancel = true;
this.hideDialog();
doClose();
}//GEN-LAST:event_buttonCancelActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables

View file

@ -5,14 +5,13 @@ import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.cards.CardArea;
import mage.view.CardsView;
import org.mage.card.arcane.CardPanel;
import javax.swing.*;
import java.awt.*;
import java.util.UUID;
/**
* Game GUI: pile choosing (select a 1 pile from a 2 piles)
* Game GUI: pile choose dialog (one from two)
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
@ -23,10 +22,8 @@ public class PickPileDialog extends MageDialog {
private boolean pickedPile1 = false;
private boolean pickedOK = false;
private PickPileCallback callback = null;
/**
* Create the frame.
*/
public PickPileDialog() {
getContentPane().setLayout(new BorderLayout(0, 0));
@ -53,6 +50,29 @@ public class PickPileDialog extends MageDialog {
panel_1.add(btnChoosePile2, BorderLayout.NORTH);
}
public interface PickPileCallback {
void onChoiceDone();
}
public void showDialog(String name, CardsView pile1, CardsView pile2, BigCard bigCard, UUID gameId, PickPileCallback callback) {
this.pickedOK = false;
this.pickedPile1 = false;
this.title = name;
this.pile1.loadCardsNarrow(pile1, bigCard, gameId);
this.pile2.loadCardsNarrow(pile2, bigCard, gameId);
this.callback = callback;
this.setModal(true);
pack();
// windows settings
MageFrame.getDesktop().remove(this);
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
this.setVisible(true);
}
public void cleanUp() {
for (Component comp : pile1.getComponents()) {
if (comp instanceof MageCard) {
@ -68,38 +88,25 @@ public class PickPileDialog extends MageDialog {
}
}
public void loadCards(String name, CardsView pile1, CardsView pile2, BigCard bigCard, UUID gameId) {
this.pickedOK = false;
this.pickedPile1 = false;
this.title = name;
this.pile1.loadCardsNarrow(pile1, bigCard, gameId);
this.pile2.loadCardsNarrow(pile2, bigCard, gameId);
this.setModal(true);
pack();
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
private void doClose() {
this.hideDialog();
if (this.callback != null) {
this.callback.onChoiceDone();
}
this.makeWindowCentered();
this.setVisible(true);
this.cleanUp();
this.removeDialog();
}
private void btnPile1ActionPerformed(java.awt.event.ActionEvent evt) {
pickedPile1 = true;
pickedOK = true;
this.hideDialog();
doClose();
}
private void btnPile2ActionPerformed(java.awt.event.ActionEvent evt) {
pickedPile1 = false;
pickedOK = true;
this.hideDialog();
doClose();
}
public boolean isPickedPile1() {

View file

@ -19,22 +19,17 @@ import java.util.concurrent.TimeoutException;
*/
public class RegisterUserDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ConnectDialog.class);
private final ConnectDialog connectDialog;
private static final Logger logger = Logger.getLogger(RegisterUserDialog.class);
private Connection connection;
private ConnectTask task;
/**
* Creates new form RegisterUserDialog
*/
public RegisterUserDialog(ConnectDialog connectDialog) {
public RegisterUserDialog() {
initComponents();
this.connectDialog = connectDialog;
}
public void showDialog() {
this.txtServer.setText(this.connectDialog.getServer());
this.txtPort.setText(this.connectDialog.getPort());
public void showDialog(String server, String port) {
this.txtServer.setText(server);
this.txtPort.setText(port);
this.lblStatus.setText("");
this.setModal(true);

View file

@ -20,24 +20,18 @@ import java.util.concurrent.TimeoutException;
public class ResetPasswordDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ResetPasswordDialog.class);
private final ConnectDialog connectDialog;
private Connection connection;
private GetAuthTokenTask getAuthTokenTask;
private ResetPasswordTask resetPasswordTask;
/**
* Creates new form ResetPasswordDialog
*/
public ResetPasswordDialog(ConnectDialog connectDialog) {
public ResetPasswordDialog() {
initComponents();
this.connectDialog = connectDialog;
}
public void showDialog() {
String serverAddress = this.connectDialog.getServer();
this.txtServer.setText(serverAddress);
this.txtPort.setText(this.connectDialog.getPort());
this.txtEmail.setText(MagePreferences.getEmail(serverAddress));
public void showDialog(String server, String port) {
this.txtServer.setText(server);
this.txtPort.setText(port);
this.txtEmail.setText(MagePreferences.getEmail(server));
this.lblStatus.setText("");
this.setModal(true);

View file

@ -21,17 +21,17 @@
/**
* Game GUI: choose target card from the cards list (example: exile and choose card to cast, choose triggers order, etc)
* <p>
* Used by feedback's connected dialog, send command on card clicks, so no need callback on close
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class ShowCardsDialog extends MageDialog {
// remember if this dialog was already auto positioned, so don't do it after the first time
// TODO: buggy, must remember by window title? Don't work with multiple triggers https://github.com/magefree/mage/issues/12281
private boolean positioned;
/**
* Creates new form ShowCardsDialog
*/
public ShowCardsDialog() {
this.positioned = false;
@ -91,7 +91,6 @@
});
}
public void loadCards(String name, CardsView showCards, BigCard bigCard,
UUID gameId, boolean modal, Map<String, Serializable> options,
JPopupMenu popupMenu, Listener<Event> eventListener) {
@ -127,11 +126,7 @@
// window settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
private void initComponents() {

View file

@ -34,6 +34,8 @@ import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_4
/**
* App GUI: waiting other players before join to a table
* <p>
* Do not use modal/callback, send direct commands to server
*
* @author BetaSteward_at_googlemail.com
*/
@ -101,7 +103,7 @@ public class TableWaitingDialog extends MageDialog {
this.btnMoveUp.setEnabled(false);
break;
default:
closeDialog();
doClose();
return;
}
int row = this.jTableSeats.getSelectedRow();
@ -113,10 +115,10 @@ public class TableWaitingDialog extends MageDialog {
this.jTableSeats.repaint();
this.jTableSeats.getSelectionModel().setSelectionInterval(row, row);
} else {
closeDialog();
doClose();
}
} catch (Exception ex) {
closeDialog();
doClose();
}
}
@ -149,11 +151,11 @@ public class TableWaitingDialog extends MageDialog {
GuiDisplayUtil.restoreDividerLocations(currentBounds, tournamentChatDivider, jSplitPane1);
} else {
closeDialog();
doClose();
}
}
public void closeDialog() {
public void doClose() {
if (updateTask != null) {
updateTask.cancel(true);
}
@ -249,10 +251,10 @@ public class TableWaitingDialog extends MageDialog {
private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed
if (!isTournament) {
if (SessionHandler.startMatch(roomId, tableId)) {
closeDialog();
doClose();
}
} else if (SessionHandler.startTournament(roomId, tableId)) {
closeDialog();
doClose();
}
}//GEN-LAST:event_btnStartActionPerformed
@ -265,7 +267,7 @@ public class TableWaitingDialog extends MageDialog {
//swallow exception
LOGGER.error(e);
}
closeDialog();
doClose();
}//GEN-LAST:event_btnCancelActionPerformed
private void btnMoveDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMoveDownActionPerformed
@ -401,7 +403,7 @@ class UpdateSeatsTask extends SwingWorker<Void, TableView> {
if (tableView.isPresent()) {
tableView.ifPresent(this::publish);
} else {
dialog.closeDialog();
dialog.doClose();
}
TimeUnit.SECONDS.sleep(1);
}

View file

@ -113,11 +113,7 @@ public class TestCardRenderDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"

View file

@ -41,11 +41,7 @@ public class TestModalDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"

View file

@ -36,11 +36,7 @@ public class TestModalSampleDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
Point p = this.getLocation();
p.x = p.x + offsetX;

View file

@ -10,7 +10,7 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
import java.awt.*;
/**
* GUI: global window message with additional action to choose (example: close the app)
* App GUI: global window message with additional action to choose (example: close the app)
* Can be used in any places (in games, in app, etc)
*
* @author BetaSteward_at_googlemail.com
@ -19,9 +19,6 @@ public class UserRequestDialog extends MageDialog {
private UserRequestMessage userRequestMessage;
/**
* Creates new form AskDialog
*/
public UserRequestDialog() {
initComponents();
setGUISize();

View file

@ -69,11 +69,7 @@ public class WhatsNewDialog extends MageDialog {
// windows settings
MageFrame.getDesktop().remove(this);
if (this.isModal()) {
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
} else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
MageFrame.getDesktop().add(this, this.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.makeWindowCentered();
// Close on "ESC"

View file

@ -277,10 +277,10 @@ public final class GamePanel extends javax.swing.JPanel {
pnlShortCuts.add(btnStopWatching);
pickNumber = new PickNumberDialog();
MageFrame.getDesktop().add(pickNumber, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(pickNumber, pickNumber.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
pickMultiNumber = new PickMultiNumberDialog();
MageFrame.getDesktop().add(pickMultiNumber, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(pickMultiNumber, pickMultiNumber.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
this.feedbackPanel.setConnectedChatPanel(this.userChatPanel);
@ -1226,7 +1226,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (exileWindow == null) {
exileWindow = new CardInfoWindowDialog(ShowType.EXILE, exile.getName());
exiles.put(exile.getId(), exileWindow);
MageFrame.getDesktop().add(exileWindow, JLayeredPane.PALETTE_LAYER);
MageFrame.getDesktop().add(exileWindow, exileWindow.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
exileWindow.show();
}
exileWindow.loadCardsAndShow(exile, bigCard, gameId);
@ -1607,7 +1607,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName);
graveyardWindows.put(playerName, newGraveyard);
MageFrame.getDesktop().add(newGraveyard, JLayeredPane.PALETTE_LAYER);
MageFrame.getDesktop().add(newGraveyard, newGraveyard.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
// use graveyards to sync selection (don't use player data here)
newGraveyard.loadCardsAndShow(graveyards.get(playerName), bigCard, gameId, false);
}
@ -1632,7 +1632,7 @@ public final class GamePanel extends javax.swing.JPanel {
newDialog.setSize(GUISizeHelper.dialogGuiScaleSize(newDialog.getSize()));
newDialog.setGameData(this.lastGameData.game, this.gameId, this.bigCard);
cardHintsWindows.put(code + UUID.randomUUID(), newDialog);
MageFrame.getDesktop().add(newDialog, JLayeredPane.PALETTE_LAYER);
MageFrame.getDesktop().add(newDialog, newDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
newDialog.loadHints(lastGameData.game);
}
@ -1661,7 +1661,7 @@ public final class GamePanel extends javax.swing.JPanel {
CardInfoWindowDialog windowDialog = new CardInfoWindowDialog(ShowType.SIDEBOARD, playerView.getName());
sideboardWindows.put(playerView.getName(), windowDialog);
MageFrame.getDesktop().add(windowDialog, JLayeredPane.PALETTE_LAYER);
MageFrame.getDesktop().add(windowDialog, windowDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
// use sideboards to sync selection (don't use player data here)
windowDialog.loadCardsAndShow(sideboards.get(playerView.getName()), bigCard, gameId, false);
}
@ -1714,7 +1714,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (!windowMap.containsKey(name)) {
cardInfoWindowDialog = new CardInfoWindowDialog(showType, name);
windowMap.put(name, cardInfoWindowDialog);
MageFrame.getDesktop().add(cardInfoWindowDialog, JLayeredPane.PALETTE_LAYER);
MageFrame.getDesktop().add(cardInfoWindowDialog, cardInfoWindowDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
} else {
cardInfoWindowDialog = windowMap.get(name);
}
@ -2153,12 +2153,13 @@ public final class GamePanel extends javax.swing.JPanel {
hideAll();
DialogManager.getManager(gameId).fadeOut();
pickNumber.showDialog(min, max, message);
if (pickNumber.isCancel()) {
SessionHandler.sendPlayerBoolean(gameId, false);
} else {
SessionHandler.sendPlayerInteger(gameId, pickNumber.getAmount());
}
pickNumber.showDialog(min, max, message, () -> {
if (pickNumber.isCancel()) {
SessionHandler.sendPlayerBoolean(gameId, false);
} else {
SessionHandler.sendPlayerInteger(gameId, pickNumber.getAmount());
}
});
}
public void getMultiAmount(int messageId, GameView gameView, List<MultiAmountMessage> messages, Map<String, Serializable> options,
@ -2167,12 +2168,13 @@ public final class GamePanel extends javax.swing.JPanel {
hideAll();
DialogManager.getManager(gameId).fadeOut();
pickMultiNumber.showDialog(messages, min, max, lastGameData.options);
if (pickMultiNumber.isCancel()) {
SessionHandler.sendPlayerBoolean(gameId, false);
} else {
SessionHandler.sendPlayerString(gameId, pickMultiNumber.getMultiAmount());
}
pickMultiNumber.showDialog(messages, min, max, lastGameData.options, () -> {
if (pickMultiNumber.isCancel()) {
SessionHandler.sendPlayerBoolean(gameId, false);
} else {
SessionHandler.sendPlayerString(gameId, pickMultiNumber.getMultiAmount());
}
});
}
public void getChoice(int messageId, GameView gameView, Map<String, Serializable> options, Choice choice, UUID objectId) {
@ -2182,23 +2184,23 @@ public final class GamePanel extends javax.swing.JPanel {
// TODO: remember last choices and search incremental for same events?
PickChoiceDialog pickChoice = new PickChoiceDialog();
pickChoice.showDialog(choice, null, objectId, choiceWindowState, bigCard);
pickChoice.showDialog(choice, null, objectId, choiceWindowState, bigCard, () -> {
// special mode adds # to the answer (server side code must process that prefix, see replacementEffectChoice)
String specialPrefix = choice.isChosenSpecial() ? "#" : "";
// special mode adds # to the answer (server side code must process that prefix, see replacementEffectChoice)
String specialPrefix = choice.isChosenSpecial() ? "#" : "";
String valueToSend;
if (choice.isKeyChoice()) {
valueToSend = choice.getChoiceKey();
} else {
valueToSend = choice.getChoice();
}
SessionHandler.sendPlayerString(gameId, valueToSend == null ? null : specialPrefix + valueToSend);
String valueToSend;
if (choice.isKeyChoice()) {
valueToSend = choice.getChoiceKey();
} else {
valueToSend = choice.getChoice();
}
SessionHandler.sendPlayerString(gameId, valueToSend == null ? null : specialPrefix + valueToSend);
// keep dialog position
choiceWindowState = new MageDialogState(pickChoice);
// keep dialog position
choiceWindowState = new MageDialogState(pickChoice);
pickChoice.removeDialog();
pickChoice.removeDialog();
});
}
public void pickPile(int messageId, GameView gameView, Map<String, Serializable> options, String message, CardsView pile1, CardsView pile2) {
@ -2212,12 +2214,11 @@ public final class GamePanel extends javax.swing.JPanel {
PickPileDialog pickPileDialog = new PickPileDialog();
this.pickPile.add(pickPileDialog);
pickPileDialog.loadCards(message, pile1, pile2, bigCard, gameId);
if (pickPileDialog.isPickedOK()) {
SessionHandler.sendPlayerBoolean(gameId, pickPileDialog.isPickedPile1());
}
pickPileDialog.cleanUp();
pickPileDialog.removeDialog();
pickPileDialog.showDialog(message, pile1, pile2, bigCard, gameId, () -> {
if (pickPileDialog.isPickedOK()) {
SessionHandler.sendPlayerBoolean(gameId, pickPileDialog.isPickedPile1());
}
});
}
public Map<UUID, PlayAreaPanel> getPlayers() {

View file

@ -57,6 +57,8 @@ import java.util.concurrent.TimeUnit;
import static mage.client.dialog.PreferencesDialog.*;
/**
* GUI: lobby's main component
*
* @author BetaSteward_at_googlemail.com
*/
public class TablesPanel extends javax.swing.JPanel {
@ -140,9 +142,12 @@ public class TablesPanel extends javax.swing.JPanel {
private UpdateTablesTask updateTablesTask;
private UpdatePlayersTask updatePlayersTask;
private UpdateMatchesTask updateMatchesTask;
// no needs in multiple create/join tables dialogs, it's a client side action
private JoinTableDialog joinTableDialog;
private NewTableDialog newTableDialog;
private NewTournamentDialog newTournamentDialog;
private final GameChooser gameChooser;
private java.util.List<String> messages;
private int currentMessage;
@ -439,14 +444,18 @@ public class TablesPanel extends javax.swing.JPanel {
LOGGER.info("Joining tournament " + tableId);
if (!gameType.startsWith("Constructed")) {
if (TablesTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) {
// need enter password
joinTableDialog.showDialog(roomId, tableId, true, !gameType.startsWith("Constructed"));
} else {
// direct join (no pass, no deck)
SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, "");
}
} else {
// need choose deck
joinTableDialog.showDialog(roomId, tableId, true, !gameType.startsWith("Constructed"));
}
} else {
// need choose deck
LOGGER.info("Joining table " + tableId);
joinTableDialog.showDialog(roomId, tableId, false, false);
}
@ -758,15 +767,15 @@ public class TablesPanel extends javax.swing.JPanel {
}
if (newTableDialog == null) {
newTableDialog = new NewTableDialog();
MageFrame.getDesktop().add(newTableDialog, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(newTableDialog, newTableDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (newTournamentDialog == null) {
newTournamentDialog = new NewTournamentDialog();
MageFrame.getDesktop().add(newTournamentDialog, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(newTournamentDialog, newTournamentDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (joinTableDialog == null) {
joinTableDialog = new JoinTableDialog();
MageFrame.getDesktop().add(joinTableDialog, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(joinTableDialog, joinTableDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (chatRoomId != null) {
this.chatPanelMain.getUserChatPanel().connect(chatRoomId);
@ -810,7 +819,7 @@ public class TablesPanel extends javax.swing.JPanel {
this.saveDividerLocations();
for (Component component : MageFrame.getDesktop().getComponents()) {
if (component instanceof TableWaitingDialog) {
((TableWaitingDialog) component).closeDialog();
((TableWaitingDialog) component).doClose();
}
}
stopTasks();

View file

@ -36,10 +36,9 @@ public class FastSearchUtil {
DefaultComboBoxModel comboModel = (DefaultComboBoxModel) combo.getModel();
Map<String, String> choiceItems = new HashMap<>(comboModel.getSize());
Map<String, Integer> choiceSorting = new HashMap<>(comboModel.getSize());
String item;
for (int i = 0; i < comboModel.getSize(); i++) {
item = comboModel.getElementAt(i).toString();
String item = comboModel.getElementAt(i).toString();
choiceItems.put(item, item);
choiceSorting.put(item, i); // need so sorting
}
@ -55,17 +54,18 @@ public class FastSearchUtil {
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
dlg.setWindowSize(windowWidth, windowHeight);
dlg.showDialog(choice, needSelectValue);
if (choice.isChosen()) {
item = choice.getChoiceKey();
dlg.showDialog(choice, needSelectValue, () -> {
if (choice.isChosen()) {
String item = choice.getChoiceKey();
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
for (int i = 0; i < comboModel.getSize(); i++) {
if (comboModel.getElementAt(i).toString().equals(item)) {
combo.setSelectedIndex(i);
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
for (int i = 0; i < comboModel.getSize(); i++) {
if (comboModel.getElementAt(i).toString().equals(item)) {
combo.setSelectedIndex(i);
}
}
}
}
});
}
/**
@ -73,8 +73,9 @@ public class FastSearchUtil {
*
* @param combo CheckBoxList control with default data model
* @param chooseMessage caption message for dialog
* @param additionalCallbackOnDone will be called after choice done
*/
public static void showFastSearchForStringComboBox(CheckBoxList combo, String chooseMessage) {
public static void showFastSearchForStringComboBox(CheckBoxList combo, String chooseMessage, PickCheckBoxDialog.PickCheckBoxCallback additionalCallbackOnDone) {
// fast search/choice dialog for string combobox
mage.choices.Choice choice = new ChoiceImpl(false);
@ -83,10 +84,9 @@ public class FastSearchUtil {
DefaultListModel comboModel = (DefaultListModel) combo.getModel();
Map<String, String> choiceItems = new HashMap<>(comboModel.getSize());
Map<String, Integer> choiceSorting = new HashMap<>(comboModel.getSize());
String item;
for (int i = 0; i < comboModel.size(); i++) {
item = comboModel.getElementAt(i).toString();
String item = comboModel.getElementAt(i).toString();
choiceItems.put(item, item);
choiceSorting.put(item, i); // need so sorting
}
@ -105,16 +105,18 @@ public class FastSearchUtil {
PickCheckBoxDialog dlg = new PickCheckBoxDialog(combo);
dlg.setWindowSize(300, 500);
dlg.showDialog(choice, needSelectValue);
if (choice.isChosen()) {
item = choice.getChoiceKey();
dlg.showDialog(choice, needSelectValue, () -> {
if (choice.isChosen()) {
String item = choice.getChoiceKey();
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
for (int i = 0; i < comboModel.getSize(); i++) {
if (comboModel.getElementAt(i).toString().equals(item)) {
combo.setSelectedIndex(i);
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
for (int i = 0; i < comboModel.getSize(); i++) {
if (comboModel.getElementAt(i).toString().equals(item)) {
combo.setSelectedIndex(i);
}
}
}
}
additionalCallbackOnDone.onChoiceDone();
});
}
}

View file

@ -513,7 +513,7 @@ public final class GuiDisplayUtil {
// re-render existing components with new style
for (Frame frame : Frame.getFrames()) {
refreshLookAndFill(frame);
refreshLookAndFeel(frame);
}
// re-render hidden/shared components
@ -528,9 +528,9 @@ public final class GuiDisplayUtil {
});
}
private static void refreshLookAndFill(Window window) {
private static void refreshLookAndFeel(Window window) {
for (Window childWindow : window.getOwnedWindows()) {
refreshLookAndFill(childWindow);
refreshLookAndFeel(childWindow);
}
SwingUtilities.updateComponentTreeUI(window);
}

View file

@ -17,7 +17,5 @@ public interface DownloadServiceInfo {
void updateProgressMessage(String text, int progressCurrent, int progressNeed);
void showDownloadControls(boolean needToShow);
Object getSync();
}

View file

@ -54,7 +54,7 @@ public class CopyPasteImageSourceDialog extends JDialog {
StreamUtils.closeQuietly(bw);
}
dispose();
onCancel();
}
private void onCancel() {

View file

@ -311,11 +311,14 @@ public class ScryfallImageSource implements CardImageSource {
}
// if up to date
if (isBulkDataPrepared()) {
if (isBulkDataPrepared(downloadServiceInfo)) {
return true;
}
// NEED TO DOWNLOAD
if (downloadServiceInfo.isNeedCancel()) {
return false;
}
// clean
TFile bulkTempFile = prepareTempFileForBulkData();
@ -424,16 +427,20 @@ public class ScryfallImageSource implements CardImageSource {
}
}
return isBulkDataPrepared();
return isBulkDataPrepared(downloadServiceInfo);
}
private boolean isBulkDataPrepared() {
private boolean isBulkDataPrepared(DownloadServiceInfo downloadServiceInfo) {
// already loaded
if (bulkCardsDatabaseAll.size() > 0) {
return true;
}
if (downloadServiceInfo.isNeedCancel()) {
return false;
}
// file not exists
Path textBulkPath = Paths.get(getBulkStaticFileName());
if (!Files.exists(textBulkPath)) {
@ -462,6 +469,10 @@ public class ScryfallImageSource implements CardImageSource {
jsonReader.beginArray();
while (jsonReader.hasNext()) {
if (downloadServiceInfo.isNeedCancel()) {
return false;
}
ScryfallApiCard card = gson.fromJson(jsonReader, ScryfallApiCard.class);
// prepare data

View file

@ -45,13 +45,15 @@ import java.util.stream.Collectors;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* Images downloader
* App GUI: card images downloader service (for GUI control see DownloadImagesDialog)
*
* @author JayDi85
*/
public class DownloadPicturesService extends DefaultBoundedRangeModel implements DownloadServiceInfo, Runnable {
private static DownloadPicturesService instance;
private static DownloadPicturesService instance = null;
private static Thread loadMissingDataThread = null;
private static final Logger logger = Logger.getLogger(DownloadPicturesService.class);
private static final String ALL_IMAGES = "- ALL images from selected source (can be slow)";
@ -79,7 +81,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
private final List<CardDownloadData> cardsDownloadQueue;
private final List<String> selectedSets = new ArrayList<>();
private static CardImageSource selectedSource;
private CardImageSource selectedSource;
private final Object sync = new Object();
@ -114,31 +116,47 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
return instance;
}
public static void main(String[] args) {
startDownload();
}
public static void startDownload() {
// load images info in background task
instance = new DownloadPicturesService(MageFrame.getInstance());
new Thread(new LoadMissingCardDataNew(instance)).start();
// workaround to keep first db connection in main thread (not images thread) - so it will keep connection after close
// TODO: no needs?
CardRepository.instance.getNonLandAndNonCreatureNames();
// show dialog
// load images info in background task
if (instance == null) {
instance = new DownloadPicturesService();
}
if (loadMissingDataThread != null) {
// stop old thread
//loadMissingDataThread.interrupt();
}
// refresh ui
instance.uiDialog.setGlobalInfo("Initializing image download...");
instance.uiDialog.getProgressBar().setValue(0);
// start new thread
loadMissingDataThread = new Thread(new LoadMissingCardDataNew(instance));
loadMissingDataThread.setDaemon(true);
loadMissingDataThread.start();
// show control dialog
instance.setNeedCancel(false);
instance.resetErrorCount();
instance.uiDialog.showDialog();
instance.uiDialog.dispose();
instance.setNeedCancel(true);
instance.uiDialog.showDialog(() -> {
// on finish/close/cancel
doStopAndClose();
});
}
// IMAGES CHECK (download process can broke some files, so fix it here too)
// code executes on cancel/close download dialog (but not executes on app's close -- it's ok)
logger.info("Images: search broken files...");
CardImageUtils.checkAndFixImageFiles();
static private void doStopAndClose() {
instance.setNeedCancel(true);
instance.uiDialog.hideDialog();
}
@Override
public boolean isNeedCancel() {
return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL);
return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL) || Thread.interrupted();
}
private void setNeedCancel(boolean needCancel) {
@ -158,16 +176,13 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
this.errorCount = 0;
}
public DownloadPicturesService(JFrame frame) {
public DownloadPicturesService() {
// init service and dialog
cardsAll = Collections.synchronizedList(new ArrayList<>());
cardsMissing = Collections.synchronizedList(new ArrayList<>());
cardsDownloadQueue = Collections.synchronizedList(new ArrayList<>());
uiDialog = new DownloadImagesDialog();
// MESSAGE
uiDialog.setGlobalInfo("Initializing image download...");
// SOURCES - scryfall is default source
uiDialog.getSourcesCombo().setModel(new DefaultComboBoxModel(DownloadSources.values()));
uiDialog.getSourcesCombo().setSelectedItem(DownloadSources.SCRYFALL_NORM);
@ -215,11 +230,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
});
// BUTTON CANCEL (dialog and loading)
uiDialog.getCancelButton().addActionListener(e -> uiDialog.setVisible(false));
uiDialog.getStopButton().addActionListener(e -> uiDialog.setVisible(false));
// PROGRESS BAR
uiDialog.getProgressBar().setValue(0);
uiDialog.getCancelButton().addActionListener(e -> doStopAndClose());
uiDialog.getStopButton().addActionListener(e -> doStopAndClose());
}
public void findMissingCards() {
@ -228,21 +240,30 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
this.cardsMissing.clear();
this.cardsDownloadQueue.clear();
updateGlobalMessage("Loading cards list...");
this.cardsAll = Collections.synchronizedList(CardRepository.instance.findCards(
new CardCriteria().nightCard(null) // meld cards need to be in the target cards, so we allow for night cards
));
try {
updateGlobalMessage("Loading cards list...");
this.cardsAll.addAll(CardRepository.instance.findCards(
new CardCriteria().nightCard(null) // meld cards need to be in the target cards, so we allow for night cards
));
if (isNeedCancel()) {
// fast stop on cancel
return;
}
updateGlobalMessage("Finding missing images...");
this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected());
updateGlobalMessage("Finding missing images...");
this.cardsMissing.addAll(prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()));
if (isNeedCancel()) {
// fast stop on cancel
return;
}
updateGlobalMessage("Finding available sets from selected source...");
this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString());
this.uiDialog.showDownloadControls(true);
updateGlobalMessage("");
showDownloadControls(true);
updateGlobalMessage("Finding available sets from selected source...");
this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString());
} finally {
updateGlobalMessage("");
this.uiDialog.showDownloadControls(true);
}
}
private void reloadLanguagesForSelectedSource() {
@ -286,12 +307,6 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
this.uiDialog.getProgressBar().setValue(progressCurrent);
}
@Override
public void showDownloadControls(boolean needToShow) {
// auto-size form on show
this.uiDialog.showDownloadControls(needToShow);
}
private String getSetNameWithYear(ExpansionSet exp) {
return exp.getName() + " (" + exp.getCode() + ", " + exp.getReleaseYear() + ")";
}
@ -419,7 +434,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
this.cardsMissing.clear();
this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected());
this.cardsMissing.addAll(prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()));
reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString());
} finally {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
@ -577,7 +592,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
allCardsUrls.add(card);
});
} catch (Exception e) {
logger.error(e);
logger.error("Error on prepare images list: " + e, e);
}
// find missing files
@ -691,12 +706,15 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
executor.shutdown();
while (!executor.isTerminated()) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ignore) {
}
try {
executor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException ignore) {
}
// IMAGES CHECK (download process can break some files, so fix it here too)
// code executes on finish/cancel download (but not executes on app's close -- it's ok)
logger.info("Images: search broken files...");
CardImageUtils.checkAndFixImageFiles();
}
} catch (Throwable e) {
logger.error("Catch unknown error while downloading: " + e, e);
@ -998,8 +1016,4 @@ class LoadMissingCardDataNew implements Runnable {
public void run() {
downloadPicturesService.findMissingCards();
}
public static void main() {
(new Thread(new LoadMissingCardDataNew(downloadPicturesService))).start();
}
}