mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
GUI: reworked error dialog:
* added client version and improved stack trace; * added copy to clipboard button; * added button to create new issue on github (with prefilled form fields like error text); * added GUI size settings support; * some old errors now use new error dialog instead message box;
This commit is contained in:
parent
2631b31b8a
commit
6c0f7ebb90
11 changed files with 284 additions and 125 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package mage.client;
|
package mage.client;
|
||||||
|
|
||||||
import mage.MageException;
|
import mage.MageException;
|
||||||
|
import mage.cards.RateCard;
|
||||||
import mage.cards.action.ActionCallback;
|
import mage.cards.action.ActionCallback;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.cards.repository.CardRepository;
|
import mage.cards.repository.CardRepository;
|
||||||
|
|
@ -38,7 +39,6 @@ import mage.client.util.stats.UpdateMemUsageTask;
|
||||||
import mage.components.ImagePanel;
|
import mage.components.ImagePanel;
|
||||||
import mage.components.ImagePanelStyle;
|
import mage.components.ImagePanelStyle;
|
||||||
import mage.constants.PlayerAction;
|
import mage.constants.PlayerAction;
|
||||||
import mage.cards.RateCard;
|
|
||||||
import mage.interfaces.MageClient;
|
import mage.interfaces.MageClient;
|
||||||
import mage.interfaces.callback.CallbackClient;
|
import mage.interfaces.callback.CallbackClient;
|
||||||
import mage.interfaces.callback.ClientCallback;
|
import mage.interfaces.callback.ClientCallback;
|
||||||
|
|
@ -72,14 +72,13 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client app
|
* Client app
|
||||||
|
|
@ -1356,11 +1355,52 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
userRequestDialog.showDialog(userRequestMessage);
|
userRequestDialog.showDialog(userRequestMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showErrorDialog(final String title, final String message) {
|
public void showErrorDialog(String errorType, Exception e) {
|
||||||
|
String errorMessage = e.getMessage();
|
||||||
|
if (errorMessage == null || errorMessage.isEmpty() || errorMessage.equals("Null")) {
|
||||||
|
errorMessage = e.getClass().getSimpleName() + " - look at server or client logs for more details";
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxLines = 10;
|
||||||
|
String newLine = "\n";
|
||||||
|
|
||||||
|
// main error
|
||||||
|
String mainError = Arrays.stream(e.getStackTrace())
|
||||||
|
.map(StackTraceElement::toString)
|
||||||
|
.limit(maxLines)
|
||||||
|
.collect(Collectors.joining(newLine));
|
||||||
|
if (e.getStackTrace().length > maxLines) {
|
||||||
|
mainError += newLine + "and other " + (e.getStackTrace().length - maxLines) + " lines";
|
||||||
|
}
|
||||||
|
|
||||||
|
// root error
|
||||||
|
String rootError = "";
|
||||||
|
Throwable root = ThreadUtils.findRootException(e);
|
||||||
|
if (root != e) {
|
||||||
|
rootError = Arrays.stream(root.getStackTrace())
|
||||||
|
.map(StackTraceElement::toString)
|
||||||
|
.limit(maxLines)
|
||||||
|
.collect(Collectors.joining(newLine));
|
||||||
|
if (root.getStackTrace().length > maxLines) {
|
||||||
|
rootError += newLine + "and other " + (root.getStackTrace().length - maxLines) + " lines";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String allErrors = mainError;
|
||||||
|
if (!rootError.isEmpty()) {
|
||||||
|
allErrors += newLine + "Root caused by:" + newLine + rootError;
|
||||||
|
}
|
||||||
|
showErrorDialog(errorType,
|
||||||
|
e.getClass().getSimpleName(),
|
||||||
|
errorMessage + newLine + newLine + "Stack trace:" + newLine + allErrors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showErrorDialog(String errorType, String errorTitle, String errorText) {
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
errorDialog.showDialog(title, message);
|
errorDialog.showDialog(errorType, errorTitle, errorText);
|
||||||
} else {
|
} else {
|
||||||
SwingUtilities.invokeLater(() -> errorDialog.showDialog(title, message));
|
SwingUtilities.invokeLater(() -> errorDialog.showDialog(errorType, errorTitle, errorText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1813,21 +1853,14 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.connectDialog.changeGUISize();
|
||||||
|
this.errorDialog.changeGUISize();
|
||||||
|
|
||||||
updateTooltipContainerSizes();
|
updateTooltipContainerSizes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showWhatsNewDialog() {
|
public static void showWhatsNewDialog() {
|
||||||
try {
|
AppUtil.openUrlInBrowser("https://jaydi85.github.io/xmage-web-news/news.html");
|
||||||
URI newsURI = new URI("https://jaydi85.github.io/xmage-web-news/news.html");
|
|
||||||
Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
|
|
||||||
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
|
|
||||||
desktop.browse(newsURI);
|
|
||||||
}
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
LOGGER.error("URI Syntax error when creating news link", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.error("IOException while loading news page", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGameFrameActive(UUID gameId) {
|
public boolean isGameFrameActive(UUID gameId) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import mage.client.dialog.PreferencesDialog;
|
||||||
import mage.client.util.gui.ColorsChooser;
|
import mage.client.util.gui.ColorsChooser;
|
||||||
import mage.client.util.gui.FastSearchUtil;
|
import mage.client.util.gui.FastSearchUtil;
|
||||||
import mage.client.util.sets.ConstructedFormats;
|
import mage.client.util.sets.ConstructedFormats;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.CompoundBorder;
|
import javax.swing.border.CompoundBorder;
|
||||||
|
|
@ -25,6 +26,8 @@ import static mage.cards.decks.DeckFormats.XMAGE;
|
||||||
*/
|
*/
|
||||||
public class DeckGeneratorDialog {
|
public class DeckGeneratorDialog {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(DeckGeneratorDialog.class);
|
||||||
|
|
||||||
private static JDialog dlg;
|
private static JDialog dlg;
|
||||||
private static String selectedColors;
|
private static String selectedColors;
|
||||||
private static JComboBox cbSets, cbDeckSize, cbCMC;
|
private static JComboBox cbSets, cbDeckSize, cbCMC;
|
||||||
|
|
@ -332,7 +335,8 @@ public class DeckGeneratorDialog {
|
||||||
cleanUp();
|
cleanUp();
|
||||||
return tmp.getAbsolutePath();
|
return tmp.getAbsolutePath();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
MageFrame.getInstance().showError("Couldn't generate deck. Try again.");
|
logger.error("Can't generate deck due " + e, e);
|
||||||
|
MageFrame.getInstance().showErrorDialog("CLIENT - error on random deck save", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@ import mage.cards.decks.DeckFormats;
|
||||||
import mage.cards.decks.exporter.DeckExporter;
|
import mage.cards.decks.exporter.DeckExporter;
|
||||||
import mage.client.MageFrame;
|
import mage.client.MageFrame;
|
||||||
import mage.client.dialog.MageDialog;
|
import mage.client.dialog.MageDialog;
|
||||||
|
import mage.client.util.AppUtil;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.datatransfer.StringSelection;
|
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -62,15 +61,6 @@ public class DeckExportClipboardDialog extends MageDialog {
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setClipboardStringData(String text) {
|
|
||||||
try {
|
|
||||||
StringSelection data = new StringSelection(text);
|
|
||||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data, data);
|
|
||||||
} catch (HeadlessException e) {
|
|
||||||
//e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOK() {
|
private void onOK() {
|
||||||
onCopyToClipboard();
|
onCopyToClipboard();
|
||||||
this.removeDialog();
|
this.removeDialog();
|
||||||
|
|
@ -95,7 +85,7 @@ public class DeckExportClipboardDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCopyToClipboard() {
|
private void onCopyToClipboard() {
|
||||||
setClipboardStringData(editData.getText());
|
AppUtil.setClipboardData(editData.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import mage.choices.ChoiceImpl;
|
||||||
import mage.client.MageFrame;
|
import mage.client.MageFrame;
|
||||||
import mage.client.SessionHandler;
|
import mage.client.SessionHandler;
|
||||||
import mage.client.preference.MagePreferences;
|
import mage.client.preference.MagePreferences;
|
||||||
|
import mage.client.util.AppUtil;
|
||||||
import mage.client.util.ClientDefaultSettings;
|
import mage.client.util.ClientDefaultSettings;
|
||||||
import mage.client.util.gui.countryBox.CountryItemEditor;
|
import mage.client.util.gui.countryBox.CountryItemEditor;
|
||||||
import mage.remote.Connection;
|
import mage.remote.Connection;
|
||||||
|
|
@ -738,13 +739,7 @@ public class ConnectDialog extends MageDialog {
|
||||||
}//GEN-LAST:event_btnFlagSearchActionPerformed
|
}//GEN-LAST:event_btnFlagSearchActionPerformed
|
||||||
|
|
||||||
private void btnCheckStatusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckStatusActionPerformed
|
private void btnCheckStatusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckStatusActionPerformed
|
||||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
AppUtil.openUrlInBrowser("http://xmage.today/servers/");
|
||||||
try {
|
|
||||||
Desktop.getDesktop().browse(new URI("http://xmage.today/servers/"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//GEN-LAST:event_btnCheckStatusActionPerformed
|
}//GEN-LAST:event_btnCheckStatusActionPerformed
|
||||||
|
|
||||||
private void btnWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnWhatsNewActionPerformed
|
private void btnWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnWhatsNewActionPerformed
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.1" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
|
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
|
@ -26,19 +26,17 @@
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Component id="pnlInfo" alignment="0" max="32767" attributes="1"/>
|
||||||
<Component id="jScrollPane2" pref="647" max="32767" attributes="1"/>
|
<Component id="pnlError" alignment="0" max="32767" attributes="1"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="jScrollPane1" pref="647" max="32767" attributes="1"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<Component id="btnOK" min="-2" pref="60" max="-2" attributes="0"/>
|
<Component id="btnCopyToClipboard" min="-2" pref="202" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="btnOpenGithub" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
<Component id="btnOK" min="-2" pref="96" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
|
|
@ -46,11 +44,15 @@
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||||
<Component id="jScrollPane2" pref="43" max="32767" attributes="0"/>
|
<Component id="pnlInfo" min="-2" pref="73" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="jScrollPane1" pref="237" max="32767" attributes="0"/>
|
<Component id="pnlError" pref="225" max="32767" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="btnOK" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="btnCopyToClipboard" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="btnOpenGithub" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
@ -59,26 +61,32 @@
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JButton" name="btnOK">
|
<Component class="javax.swing.JButton" name="btnOK">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="OK"/>
|
<Property name="text" type="java.lang.String" value="Close"/>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[59, 33]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[59, 33]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[59, 33]"/>
|
||||||
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOKActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOKActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
<Container class="javax.swing.JScrollPane" name="pnlError">
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JTextArea" name="lblMessage">
|
<Component class="javax.swing.JTextArea" name="textError">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="columns" type="int" value="20"/>
|
|
||||||
<Property name="editable" type="boolean" value="false"/>
|
<Property name="editable" type="boolean" value="false"/>
|
||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
<Property name="columns" type="int" value="20"/>
|
||||||
<Font name="Arial" size="10" style="0"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="lineWrap" type="boolean" value="true"/>
|
<Property name="lineWrap" type="boolean" value="true"/>
|
||||||
<Property name="rows" type="int" value="5"/>
|
<Property name="rows" type="int" value="5"/>
|
||||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
||||||
|
|
@ -86,25 +94,43 @@
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
|
<Container class="javax.swing.JScrollPane" name="pnlInfo">
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JTextArea" name="jTextArea1">
|
<Component class="javax.swing.JTextArea" name="textInfo">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="columns" type="int" value="20"/>
|
|
||||||
<Property name="editable" type="boolean" value="false"/>
|
<Property name="editable" type="boolean" value="false"/>
|
||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
<Property name="lineWrap" type="boolean" value="true"/>
|
||||||
<Font name="Arial" size="10" style="0"/>
|
<Property name="text" type="java.lang.String" value="[bug report instructions]"/>
|
||||||
</Property>
|
|
||||||
<Property name="rows" type="int" value="2"/>
|
|
||||||
<Property name="text" type="java.lang.String" value="An error has occurred on the MAGE server. Your last action will be rollbacked.
Please post the following report here: http://www.slightlymagic.net/forum/posting.php?mode=reply&f=70&t=3116"/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
|
<Component class="javax.swing.JButton" name="btnCopyToClipboard">
|
||||||
|
<Properties>
|
||||||
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/buttons/copy_24.png"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" value="Copy error to clipboard"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCopyToClipboardActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="btnOpenGithub">
|
||||||
|
<Properties>
|
||||||
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/buttons/search_24.png"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" value="Open github and create bug report"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOpenGithubActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,40 @@
|
||||||
package mage.client.dialog;
|
package mage.client.dialog;
|
||||||
|
|
||||||
|
import mage.client.MageFrame;
|
||||||
|
import mage.client.util.AppUtil;
|
||||||
|
import mage.client.util.GUISizeHelper;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game GUI: error dialog
|
* GUI: error dialog with copyable error message
|
||||||
*
|
*
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
public class ErrorDialog extends MageDialog {
|
public class ErrorDialog extends MageDialog {
|
||||||
|
|
||||||
/** Creates new form ErrorDialog */
|
private final String GITHUB_ISSUES_PAGE = "https://github.com/magefree/mage/issues";
|
||||||
|
|
||||||
public ErrorDialog() {
|
public ErrorDialog() {
|
||||||
initComponents();
|
initComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showDialog(String title, String message) {
|
public void showDialog(String errorType, String errorTitle, String errorText) {
|
||||||
this.setTitle(title);
|
this.textInfo.setText("You can report bugs and create new feature requests at github: " + GITHUB_ISSUES_PAGE);
|
||||||
this.lblMessage.setText(message);
|
this.textInfo.setCaretPosition(0);
|
||||||
this.lblMessage.setCaretPosition(0);
|
|
||||||
|
String fullTitle = errorType + " - " + errorTitle;
|
||||||
|
this.setTitle(fullTitle);
|
||||||
|
|
||||||
|
// add additional info
|
||||||
|
String fullError = "Error type: " + fullTitle + "\n"
|
||||||
|
+ "Client version: " + MageFrame.getInstance().getVersion().toString() + "\n"
|
||||||
|
+ "\n"
|
||||||
|
+ errorText;
|
||||||
|
this.textError.setText(fullError);
|
||||||
|
this.textError.setCaretPosition(0);
|
||||||
|
|
||||||
|
this.changeGUISize();
|
||||||
|
|
||||||
this.pack();
|
this.pack();
|
||||||
this.revalidate();
|
this.revalidate();
|
||||||
this.repaint();
|
this.repaint();
|
||||||
|
|
@ -23,6 +42,31 @@ public class ErrorDialog extends MageDialog {
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changeGUISize() {
|
||||||
|
super.changeGUISize();
|
||||||
|
|
||||||
|
this.textError.setFont(GUISizeHelper.menuFont);
|
||||||
|
this.textInfo.setFont(GUISizeHelper.menuFont);
|
||||||
|
this.btnCopyToClipboard.setFont(GUISizeHelper.menuFont);
|
||||||
|
this.btnOpenGithub.setFont(GUISizeHelper.menuFont);
|
||||||
|
this.btnOK.setFont(GUISizeHelper.menuFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openGithub() {
|
||||||
|
// create new issue on github with predefined fields
|
||||||
|
String title = this.getTitle();
|
||||||
|
String body = this.textError.getText();
|
||||||
|
String labels = "bug";
|
||||||
|
String url = String.format("%s/new?labels=%s&title=%s&body=%s",
|
||||||
|
GITHUB_ISSUES_PAGE,
|
||||||
|
CardUtil.urlEncode(labels),
|
||||||
|
CardUtil.urlEncode(title),
|
||||||
|
CardUtil.urlEncode(body)
|
||||||
|
);
|
||||||
|
AppUtil.openUrlInBrowser(url);
|
||||||
|
}
|
||||||
|
|
||||||
/** This method is called from within the constructor to
|
/** This method is called from within the constructor to
|
||||||
* initialize the form.
|
* initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is
|
* WARNING: Do NOT modify this code. The content of this method is
|
||||||
|
|
@ -33,31 +77,53 @@ public class ErrorDialog extends MageDialog {
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
btnOK = new javax.swing.JButton();
|
btnOK = new javax.swing.JButton();
|
||||||
jScrollPane1 = new javax.swing.JScrollPane();
|
pnlError = new javax.swing.JScrollPane();
|
||||||
lblMessage = new javax.swing.JTextArea();
|
textError = new javax.swing.JTextArea();
|
||||||
jScrollPane2 = new javax.swing.JScrollPane();
|
pnlInfo = new javax.swing.JScrollPane();
|
||||||
jTextArea1 = new javax.swing.JTextArea();
|
textInfo = new javax.swing.JTextArea();
|
||||||
|
btnCopyToClipboard = new javax.swing.JButton();
|
||||||
|
btnOpenGithub = new javax.swing.JButton();
|
||||||
|
|
||||||
setResizable(true);
|
setResizable(true);
|
||||||
setTitle("Error");
|
setTitle("Error");
|
||||||
|
|
||||||
btnOK.setText("OK");
|
btnOK.setText("Close");
|
||||||
btnOK.addActionListener(this::btnOKActionPerformed);
|
btnOK.setMaximumSize(new java.awt.Dimension(59, 33));
|
||||||
|
btnOK.setMinimumSize(new java.awt.Dimension(59, 33));
|
||||||
|
btnOK.setPreferredSize(new java.awt.Dimension(59, 33));
|
||||||
|
btnOK.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
btnOKActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
lblMessage.setColumns(20);
|
textError.setEditable(false);
|
||||||
lblMessage.setEditable(false);
|
textError.setColumns(20);
|
||||||
lblMessage.setFont(new java.awt.Font("Arial", 0, 10)); // NOI18N
|
textError.setLineWrap(true);
|
||||||
lblMessage.setLineWrap(true);
|
textError.setRows(5);
|
||||||
lblMessage.setRows(5);
|
textError.setWrapStyleWord(true);
|
||||||
lblMessage.setWrapStyleWord(true);
|
pnlError.setViewportView(textError);
|
||||||
jScrollPane1.setViewportView(lblMessage);
|
|
||||||
|
|
||||||
jTextArea1.setColumns(20);
|
textInfo.setEditable(false);
|
||||||
jTextArea1.setEditable(false);
|
textInfo.setLineWrap(true);
|
||||||
jTextArea1.setFont(new java.awt.Font("Arial", 0, 10)); // NOI18N
|
textInfo.setText("[bug report instructions]");
|
||||||
jTextArea1.setRows(2);
|
pnlInfo.setViewportView(textInfo);
|
||||||
jTextArea1.setText("An error has occurred on the MAGE server. Your last action will be rollbacked.\nPlease post the following report here: https://github.com/magefree/mage/issues");
|
|
||||||
jScrollPane2.setViewportView(jTextArea1);
|
btnCopyToClipboard.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/copy_24.png"))); // NOI18N
|
||||||
|
btnCopyToClipboard.setText("Copy error to clipboard");
|
||||||
|
btnCopyToClipboard.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
btnCopyToClipboardActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btnOpenGithub.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N
|
||||||
|
btnOpenGithub.setText("Open github and create bug report");
|
||||||
|
btnOpenGithub.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
btnOpenGithubActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||||
getContentPane().setLayout(layout);
|
getContentPane().setLayout(layout);
|
||||||
|
|
@ -66,25 +132,28 @@ public class ErrorDialog extends MageDialog {
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addComponent(pnlInfo)
|
||||||
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)
|
.addComponent(pnlError)
|
||||||
.addContainerGap())
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)
|
|
||||||
.addContainerGap())
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(btnCopyToClipboard, javax.swing.GroupLayout.PREFERRED_SIZE, 202, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())))
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnOpenGithub)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
|
.addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 96, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addGap(6, 6, 6)
|
.addGap(6, 6, 6)
|
||||||
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 43, Short.MAX_VALUE)
|
.addComponent(pnlInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addGap(18, 18, 18)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE)
|
.addComponent(pnlError, javax.swing.GroupLayout.DEFAULT_SIZE, 225, Short.MAX_VALUE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(btnOK)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(btnCopyToClipboard)
|
||||||
|
.addComponent(btnOpenGithub))
|
||||||
.addGap(12, 12, 12))
|
.addGap(12, 12, 12))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -95,13 +164,23 @@ public class ErrorDialog extends MageDialog {
|
||||||
this.hideDialog();
|
this.hideDialog();
|
||||||
}//GEN-LAST:event_btnOKActionPerformed
|
}//GEN-LAST:event_btnOKActionPerformed
|
||||||
|
|
||||||
|
private void btnCopyToClipboardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCopyToClipboardActionPerformed
|
||||||
|
AppUtil.setClipboardData(textError.getText());
|
||||||
|
}//GEN-LAST:event_btnCopyToClipboardActionPerformed
|
||||||
|
|
||||||
|
private void btnOpenGithubActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOpenGithubActionPerformed
|
||||||
|
openGithub();
|
||||||
|
}//GEN-LAST:event_btnOpenGithubActionPerformed
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JButton btnCopyToClipboard;
|
||||||
private javax.swing.JButton btnOK;
|
private javax.swing.JButton btnOK;
|
||||||
private javax.swing.JScrollPane jScrollPane1;
|
private javax.swing.JButton btnOpenGithub;
|
||||||
private javax.swing.JScrollPane jScrollPane2;
|
private javax.swing.JScrollPane pnlError;
|
||||||
private javax.swing.JTextArea jTextArea1;
|
private javax.swing.JScrollPane pnlInfo;
|
||||||
private javax.swing.JTextArea lblMessage;
|
private javax.swing.JTextArea textError;
|
||||||
|
private javax.swing.JTextArea textInfo;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -786,9 +786,9 @@ public class NewTableDialog extends MageDialog {
|
||||||
this.repaint();
|
this.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleError(Exception ex) {
|
private void handleError(Exception e) {
|
||||||
logger.fatal("Error loading deck", ex);
|
logger.fatal("Can't join table due " + e, e);
|
||||||
MageFrame.getInstance().showErrorDialog("Error loading deck", ex.getMessage());
|
MageFrame.getInstance().showErrorDialog("CLIENT - error on join table", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showDialog(UUID roomId) {
|
public void showDialog(UUID roomId) {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ import java.awt.event.KeyEvent;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Client side implementation (process commands from a server)
|
||||||
|
*
|
||||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||||
*/
|
*/
|
||||||
public class CallbackClientImpl implements CallbackClient {
|
public class CallbackClientImpl implements CallbackClient {
|
||||||
|
|
@ -266,7 +268,7 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
case GAME_ERROR: {
|
case GAME_ERROR: {
|
||||||
frame.showErrorDialog("Game Error", (String) callback.getData());
|
frame.showErrorDialog("SERVER", "game error", (String) callback.getData());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -693,12 +695,8 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleException(Exception ex) {
|
private void handleException(Exception e) {
|
||||||
logger.fatal("Client error\n", ex);
|
logger.fatal("General error\n", e);
|
||||||
String errorMessage = ex.getMessage();
|
frame.showErrorDialog("General error", e);
|
||||||
if (errorMessage == null || errorMessage.isEmpty() || errorMessage.equals("Null")) {
|
|
||||||
errorMessage = ex.getClass().getSimpleName() + " - look at server or client logs for more details";
|
|
||||||
}
|
|
||||||
frame.showError("Server's error: " + errorMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,24 @@
|
||||||
package mage.client.util;
|
package mage.client.util;
|
||||||
|
|
||||||
import mage.client.MageFrame;
|
import mage.client.MageFrame;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Helper class for client side app
|
||||||
|
*
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
public class AppUtil {
|
public class AppUtil {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AppUtil.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application is active in operation system (got user focus)
|
* Application is active in operation system (got user focus)
|
||||||
*/
|
*/
|
||||||
|
|
@ -25,4 +35,29 @@ public class AppUtil {
|
||||||
public static boolean isGameActive(UUID gameId) {
|
public static boolean isGameActive(UUID gameId) {
|
||||||
return MageFrame.getInstance().isGameFrameActive(gameId);
|
return MageFrame.getInstance().isGameFrameActive(gameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save text to clipboard
|
||||||
|
*/
|
||||||
|
public static void setClipboardData(String text) {
|
||||||
|
try {
|
||||||
|
StringSelection data = new StringSelection(text);
|
||||||
|
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data, data);
|
||||||
|
} catch (HeadlessException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openUrlInBrowser(String url) {
|
||||||
|
Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
|
||||||
|
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
try {
|
||||||
|
URI uri = new URI(url);
|
||||||
|
desktop.browse(uri);
|
||||||
|
} catch (IOException | URISyntaxException e) {
|
||||||
|
logger.error("Can't open url in browser: " + url, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Can't open url in browser: non supported desktop mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,7 @@ public class URLHandler {
|
||||||
try {
|
try {
|
||||||
URI uri = new URI(url);
|
URI uri = new URI(url);
|
||||||
desktop.browse(uri);
|
desktop.browse(uri);
|
||||||
} catch (IOException | URISyntaxException ex) {
|
} catch (IOException | URISyntaxException ignore) {
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1648,12 +1648,12 @@ public class SessionImpl implements Session {
|
||||||
|
|
||||||
private void handleMageException(MageException ex) {
|
private void handleMageException(MageException ex) {
|
||||||
logger.fatal("Server error", ex);
|
logger.fatal("Server error", ex);
|
||||||
client.showError(ex.getMessage());
|
client.showError("Server error: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleGameException(GameException ex) {
|
private void handleGameException(GameException ex) {
|
||||||
logger.warn(ex.getMessage());
|
logger.warn(ex.getMessage());
|
||||||
client.showError(ex.getMessage());
|
client.showError("Game error: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue