package net.classicube.launcher.gui;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class ErrorScreen extends javax.swing.JDialog {
private static final String
SUPPORT_FULL_URL = "https://github.com/fragmer/ClassiCubeLauncher/issues?labels=&page=1&state=open",
SUPPORT_SHORTCUT_URL = "http://is.gd/CCL_bugs";
public static void show(final String title, final String message, final Throwable ex) {
new ErrorScreen(title, message, ex).setVisible(true);
}
private ErrorScreen(final String title, final String message, final Throwable ex) {
// set title, add border
super((Frame) null, title, true);
// set background
final ImagePanel bgPanel = new ImagePanel(null, true);
bgPanel.setGradient(true);
bgPanel.setImage(Resources.getClassiCubeBackground());
bgPanel.setGradientColor(Resources.ccGradient);
bgPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
setContentPane(bgPanel);
initComponents();
this.lMessage.setText("<html><div width=400><b>" + message);
// fill in exception info (if available)
if (ex != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
this.tDetails.setText(sw.toString());
this.tDetails.selectAll();
this.tDetails.setCaretPosition(0);
CutCopyPasteAdapter.addToComponent(tDetails, true, false);
} else {
this.bDetails.setVisible(false);
}
this.detailsContainer.setVisible(false);
// focus & highlight [Close]
getRootPane().setDefaultButton(bClose);
// Show GridBagLayout who's boss.
this.imgErrorIcon.setImage(Resources.getErrorIcon());
this.imgErrorIcon.setMinimumSize(new Dimension(64, 64));
this.imgErrorIcon.setPreferredSize(new Dimension(64, 64));
this.imgErrorIcon.setSize(new Dimension(64, 64));
// Add a support link, if there is an exception.
if (ex != null) {
if (isBrowsingSupported()) {
lContactSupport.setText("<html><b>If this problem persists, please "
+ "<a href=\"" + SUPPORT_FULL_URL + "\" color=\"#2d203a\">"
+ "contact tech support</a>.");
lContactSupport.setCursor(new Cursor(Cursor.HAND_CURSOR));
lContactSupport.addMouseListener(new LinkMouseListener());
} else {
lContactSupport.setText("<html><div width=400>If this problem persists, please contact support at: " + SUPPORT_SHORTCUT_URL);
}
} else {
lContactSupport.setVisible(false);
}
// Set window icon and location
this.setIconImages(Resources.getWindowIcons());
pack();
setLocationRelativeTo(null);
}
// based on code by Stefan Ganzer @ http://stackoverflow.com/a/8387251/383361
private static boolean isBrowsingSupported() {
if (!Desktop.isDesktopSupported()) {
return false;
}
boolean result = false;
Desktop desktop = java.awt.Desktop.getDesktop();
if (desktop.isSupported(Desktop.Action.BROWSE)) {
result = true;
}
return result;
}
// based on code by Stefan Ganzer @ http://stackoverflow.com/a/8387251/383361
private static class LinkMouseListener extends MouseAdapter {
@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
JLabel label = (JLabel) evt.getSource();
try {
(new LinkRunner(new URI(SUPPORT_FULL_URL))).execute();
} catch (URISyntaxException use) {
throw new AssertionError(use + ": " + label.getText()); //NOI18N
}
}
}
// based on code by Stefan Ganzer @ http://stackoverflow.com/a/8387251/383361
private static class LinkRunner extends SwingWorker<Void, Void> {
private final URI uri;
private LinkRunner(URI uri) {
if (uri == null) {
throw new NullPointerException();
}
this.uri = uri;
}
@Override
protected Void doInBackground() throws Exception {
Desktop desktop = java.awt.Desktop.getDesktop();
desktop.browse(uri);
return null;
}
@Override
protected void done() {
try {
get();
} catch (ExecutionException | InterruptedException ex) {
handleException(uri, ex);
}
}
private static void handleException(URI uri, Exception ex) {
JOptionPane.showMessageDialog(null,
"Sorry, a problem occurred while trying to open this link in your system's standard browser.",
"A problem occured",
JOptionPane.ERROR_MESSAGE);
}
}
/**
* 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 regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
detailsContainer = new javax.swing.JScrollPane();
tDetails = new javax.swing.JTextArea();
lMessage = new javax.swing.JLabel();
bDetails = new net.classicube.launcher.gui.JNiceLookingToggleButton();
bClose = new net.classicube.launcher.gui.JNiceLookingButton();
imgErrorIcon = new net.classicube.launcher.gui.ImagePanel();
javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
lContactSupport = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setType(java.awt.Window.Type.UTILITY);
getContentPane().setLayout(new java.awt.GridBagLayout());
tDetails.setEditable(false);
tDetails.setColumns(20);
tDetails.setRows(6);
detailsContainer.setViewportView(tDetails);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 0.1;
gridBagConstraints.weighty = 0.1;
gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
getContentPane().add(detailsContainer, gridBagConstraints);
lMessage.setForeground(new java.awt.Color(255, 255, 255));
lMessage.setText("Someone set up us the bomb!");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
getContentPane().add(lMessage, gridBagConstraints);
bDetails.setText("+ Details");
bDetails.setToolTipText("Show technical details of this error.\nWhen reporting a bug, please include this information.");
bDetails.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
bDetailsItemStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_END;
getContentPane().add(bDetails, gridBagConstraints);
bClose.setText("Close");
bClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bCloseActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_END;
getContentPane().add(bClose, gridBagConstraints);
imgErrorIcon.setMaximumSize(new java.awt.Dimension(64, 64));
imgErrorIcon.setMinimumSize(new java.awt.Dimension(64, 64));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridheight = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 10);
getContentPane().add(imgErrorIcon, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 0.1;
getContentPane().add(filler2, gridBagConstraints);
lContactSupport.setForeground(new java.awt.Color(255, 255, 255));
lContactSupport.setText("<contact support link>");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(6, 0, 6, 0);
getContentPane().add(lContactSupport, gridBagConstraints);
pack();
}// </editor-fold>//GEN-END:initComponents
private void bCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bCloseActionPerformed
this.dispose();
}//GEN-LAST:event_bCloseActionPerformed
private void bDetailsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_bDetailsItemStateChanged
if (evt.getStateChange() == ItemEvent.SELECTED) {
this.detailsContainer.setVisible(true);
this.tDetails.selectAll();
this.tDetails.requestFocus();
} else if (evt.getStateChange() == ItemEvent.DESELECTED) {
this.detailsContainer.setVisible(false);
}
pack();
}//GEN-LAST:event_bDetailsItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private net.classicube.launcher.gui.JNiceLookingButton bClose;
private net.classicube.launcher.gui.JNiceLookingToggleButton bDetails;
private javax.swing.JScrollPane detailsContainer;
private net.classicube.launcher.gui.ImagePanel imgErrorIcon;
private javax.swing.JLabel lContactSupport;
private javax.swing.JLabel lMessage;
private javax.swing.JTextArea tDetails;
// End of variables declaration//GEN-END:variables
}