package games.strategy.triplea.ai.proAI.logging;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.logging.Level;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import games.strategy.triplea.ui.TripleAFrame;
import games.strategy.ui.SwingAction;
/**
* GUI class used to display logging window and logging settings.
*/
public class ProLogWindow extends javax.swing.JDialog {
private static final long serialVersionUID = -5989598624017028122L;
/** Creates new form ProLogWindow. */
public ProLogWindow(final TripleAFrame frame) {
super(frame);
initComponents();
}
public void clear() {
this.dispose();
v_tabPaneMain = null;
v_logHolderTabbedPane = null;
}
private void initComponents() {
final java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
java.awt.GridBagConstraints gridBagConstraints;
final JPanel jPanel7 = new JPanel();
final JButton v_restoreDefaultsButton = new JButton();
final JButton v_settingsDetailsButton = new JButton();
final JPanel jPanel14 = new JPanel();
final JPanel jPanel13 = new JPanel();
final JButton v_cancelButton = new JButton();
final JButton v_okButton = new JButton();
v_tabPaneMain = new javax.swing.JTabbedPane();
final JPanel jPanel8 = new JPanel();
v_logHolderTabbedPane = new javax.swing.JTabbedPane();
final JPanel jPanel9 = new JPanel();
final JScrollPane v_aiOutputLogAreaScrollPane = new JScrollPane();
v_aiOutputLogArea = new javax.swing.JTextArea();
v_enableAILogging = new javax.swing.JCheckBox();
final javax.swing.JLabel jLabel15 = new javax.swing.JLabel();
v_logDepth = new javax.swing.JComboBox<>();
v_limitLogHistoryToSpinner = new javax.swing.JSpinner();
v_limitLogHistoryCB = new javax.swing.JCheckBox();
final javax.swing.JLabel jLabel46 = new javax.swing.JLabel();
final JPanel v_pauseAIs = new JPanel();
setTitle("Hard AI Settings");
setMinimumSize(new java.awt.Dimension(775, 400));
addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(final java.awt.event.WindowEvent evt) {
formWindowClosing();
}
@Override
public void windowOpened(final java.awt.event.WindowEvent evt) {
formWindowOpened();
}
});
getContentPane().setLayout(new java.awt.GridBagLayout());
jPanel7.setName("jPanel3");
jPanel7.setPreferredSize(new java.awt.Dimension(600, 45));
jPanel7.setLayout(new java.awt.GridBagLayout());
v_restoreDefaultsButton.setText("Restore Defaults");
v_restoreDefaultsButton.setMinimumSize(new java.awt.Dimension(118, 23));
v_restoreDefaultsButton.setName("v_restoreDefaultsButton");
v_restoreDefaultsButton.setPreferredSize(new java.awt.Dimension(118, 23));
v_restoreDefaultsButton.addActionListener(evt -> v_restoreDefaultsButtonActionPerformed());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(11, 0, 11, 0);
jPanel7.add(v_restoreDefaultsButton, gridBagConstraints);
v_settingsDetailsButton.setText("Settings Details");
v_settingsDetailsButton.setMinimumSize(new java.awt.Dimension(115, 23));
v_settingsDetailsButton.setName("v_settingsDetailsButton");
v_settingsDetailsButton.setPreferredSize(new java.awt.Dimension(115, 23));
v_settingsDetailsButton.addActionListener(evt -> v_settingsDetailsButtonActionPerformed());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(11, 6, 11, 0);
jPanel7.add(v_settingsDetailsButton, gridBagConstraints);
jPanel14.setName("jPanel14");
jPanel14.setLayout(new java.awt.GridBagLayout());
jPanel13.setName("jPanel13");
jPanel13.setLayout(new java.awt.GridBagLayout());
v_cancelButton.setText("Cancel");
v_cancelButton.setName("v_cancelButton");
v_cancelButton.addActionListener(evt -> v_cancelButtonActionPerformed());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
jPanel13.add(v_cancelButton, gridBagConstraints);
v_okButton.setText("OK");
v_okButton.setName("v_okButton");
v_okButton.addActionListener(evt -> v_okButtonActionPerformed());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
jPanel13.add(v_okButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
jPanel14.add(jPanel13, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 99.0;
gridBagConstraints.insets = new java.awt.Insets(11, 6, 11, 0);
jPanel7.add(jPanel14, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 99.0;
gridBagConstraints.insets = new java.awt.Insets(0, 7, 0, 7);
getContentPane().add(jPanel7, gridBagConstraints);
v_tabPaneMain.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
v_tabPaneMain.setName("v_tabPaneMain");
v_tabPaneMain.setPreferredSize(new java.awt.Dimension(500, screenSize.height - 200));
jPanel8.setName("jPanel8");
jPanel8.setPreferredSize(new java.awt.Dimension(500, 314));
jPanel8.setLayout(new java.awt.GridBagLayout());
v_logHolderTabbedPane.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
v_logHolderTabbedPane.setFont(new java.awt.Font("Segoe UI", 0, 10));
v_logHolderTabbedPane.setName("v_logHolderTabbedPane");
jPanel9.setName("jPanel9");
jPanel9.setLayout(new java.awt.GridLayout(1, 0));
v_aiOutputLogAreaScrollPane.setName("v_aiOutputLogAreaScrollPane");
v_aiOutputLogArea.setColumns(20);
v_aiOutputLogArea.setEditable(false);
v_aiOutputLogArea.setFont(new java.awt.Font("Segoe UI", 0, 10));
v_aiOutputLogArea.setRows(5);
v_aiOutputLogArea.setName("v_aiOutputLogArea");
v_aiOutputLogAreaScrollPane.setViewportView(v_aiOutputLogArea);
jPanel9.add(v_aiOutputLogAreaScrollPane);
v_logHolderTabbedPane.addTab("Pre-Game", jPanel9);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 7;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 99.0;
gridBagConstraints.weighty = 99.0;
gridBagConstraints.insets = new java.awt.Insets(7, 7, 7, 7);
jPanel8.add(v_logHolderTabbedPane, gridBagConstraints);
v_enableAILogging.setSelected(true);
v_enableAILogging.setText("Enable AI Logging");
v_enableAILogging.setName("v_enableAILogging");
v_enableAILogging.addChangeListener(evt -> v_enableAILoggingStateChanged());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(7, 7, 0, 0);
jPanel8.add(v_enableAILogging, gridBagConstraints);
jLabel15.setText("Log Depth:");
jLabel15.setName("jLabel15");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(7, 12, 0, 0);
jPanel8.add(jLabel15, gridBagConstraints);
v_logDepth.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] {"Fine", "Finer", "Finest"}));
v_logDepth.setSelectedItem(v_logDepth.getItemAt(2));
v_logDepth.setName("v_logDepth");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(7, 5, 0, 0);
jPanel8.add(v_logDepth, gridBagConstraints);
v_limitLogHistoryToSpinner.setModel(new javax.swing.SpinnerNumberModel(5, 1, 100, 1));
v_limitLogHistoryToSpinner.setMinimumSize(new java.awt.Dimension(60, 20));
v_limitLogHistoryToSpinner.setName("v_limitLogHistoryToSpinner");
v_limitLogHistoryToSpinner.setPreferredSize(new java.awt.Dimension(60, 20));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 5;
gridBagConstraints.gridy = 0;
gridBagConstraints.ipadx = 10;
gridBagConstraints.insets = new java.awt.Insets(7, 0, 0, 0);
jPanel8.add(v_limitLogHistoryToSpinner, gridBagConstraints);
v_limitLogHistoryCB.setSelected(true);
v_limitLogHistoryCB.setText("Limit Log History To:");
v_limitLogHistoryCB.setName("v_limitLogHistoryCB");
v_limitLogHistoryCB.addChangeListener(evt -> v_limitLogHistoryCBStateChanged());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(7, 0, 0, 12);
jPanel8.add(v_limitLogHistoryCB, gridBagConstraints);
jLabel46.setText("rounds");
jLabel46.setName("jLabel46");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 6;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(7, 5, 0, 7);
jPanel8.add(jLabel46, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.weightx = 99.0;
gridBagConstraints.insets = new java.awt.Insets(7, 0, 0, 0);
jPanel8.add(v_pauseAIs, gridBagConstraints);
v_tabPaneMain.addTab("Debugging", jPanel8);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 99.0;
gridBagConstraints.weighty = 99.0;
gridBagConstraints.insets = new java.awt.Insets(7, 7, 0, 7);
getContentPane().add(v_tabPaneMain, gridBagConstraints);
setBounds((screenSize.width - 800), 25, 775, 401);
}
private void formWindowOpened() {
loadSettings(ProLogSettings.loadSettings());
this.pack();
}
/**
* Loads the settings provided and displays it in this settings window.
*/
private void loadSettings(final ProLogSettings settings) {
v_enableAILogging.setSelected(settings.EnableAILogging);
if (settings.AILoggingDepth.equals(Level.FINE)) {
v_logDepth.setSelectedIndex(0);
} else if (settings.AILoggingDepth.equals(Level.FINER)) {
v_logDepth.setSelectedIndex(1);
} else if (settings.AILoggingDepth.equals(Level.FINEST)) {
v_logDepth.setSelectedIndex(2);
}
v_limitLogHistoryCB.setSelected(settings.LimitLogHistory);
v_limitLogHistoryToSpinner.setValue(settings.LimitLogHistoryTo);
}
public ProLogSettings createSettings() {
final ProLogSettings settings = new ProLogSettings();
settings.EnableAILogging = v_enableAILogging.isSelected();
if (v_logDepth.getSelectedIndex() == 0) {
settings.AILoggingDepth = Level.FINE;
} else if (v_logDepth.getSelectedIndex() == 1) {
settings.AILoggingDepth = Level.FINER;
} else if (v_logDepth.getSelectedIndex() == 2) {
settings.AILoggingDepth = Level.FINEST;
}
settings.LimitLogHistory = v_limitLogHistoryCB.isSelected();
settings.LimitLogHistoryTo = Integer.parseInt(v_limitLogHistoryToSpinner.getValue().toString());
return settings;
}
private void v_restoreDefaultsButtonActionPerformed() {
final int result = JOptionPane.showConfirmDialog(rootPane, "Are you sure you want to reset all AI settings?",
"Reset Default Settings", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
// Default settings are already contained in a new DSettings instance
final ProLogSettings defaultSettings = new ProLogSettings();
loadSettings(defaultSettings);
JOptionPane.showMessageDialog(rootPane,
"Default settings restored.\r\n\r\n(If you don't want to keep these default settings, just hit cancel)",
"Default Settings Restored", JOptionPane.INFORMATION_MESSAGE);
}
}
private void v_enableAILoggingStateChanged() {
v_logDepth.setEnabled(v_enableAILogging.isSelected());
v_limitLogHistoryCB.setEnabled(v_enableAILogging.isSelected());
}
private void v_limitLogHistoryCBStateChanged() {
v_limitLogHistoryToSpinner.setEnabled(v_limitLogHistoryCB.isSelected() && v_enableAILogging.isSelected());
}
private void formWindowClosing() {
v_cancelButtonActionPerformed();
}
private void v_okButtonActionPerformed() {
final ProLogSettings settings = createSettings();
ProLogSettings.saveSettings(settings);
this.setVisible(false);
}
private void v_cancelButtonActionPerformed() {
final ProLogSettings settings = ProLogSettings.loadSettings();
loadSettings(settings);
this.setVisible(false);
}
private void v_settingsDetailsButtonActionPerformed() {
final JDialog dialog = new JDialog(this, "Pro AI - Settings Details");
String message = "";
if (v_tabPaneMain.getSelectedIndex() == 0) { // Debugging
message = "Debugging\r\n" + "\r\n"
+ "AI Logging: When this is checked, the AI's will output their logs, as they come in, so you can see "
+ "exactly what the AI is thinking.\r\n"
+ "Note that if you check this on, you still have to press OK then reopen the settings window for the logs "
+ "to actually start displaying.\r\n"
+ "\r\n"
+ "Log Depth: This setting lets you choose how deep you want the AI logging to be. Fine only displays the "
+ "high-level events, like the start of a phase, etc.\r\n"
+ "Finer displays medium-level events, such as attacks, reinforcements, etc.\r\n"
+ "Finest displays all the AI logging available. Can be used for detailed ananlysis, but is a lot harder to "
+ "read through it.\r\n"
+ "\r\n"
+ "Pause AI's: This checkbox pauses all the AI's while it's checked, so you can look at the logs without the "
+ "AI's outputing floods of information.\r\n"
+ "\r\n"
+ "Limit Log History To X Rounds: If this is checked, the AI log information will be limited to X rounds of "
+ "information.\r\n";
}
final JTextArea label = new JTextArea(message);
label.setFont(new Font("Segoe UI", Font.PLAIN, 12));
label.setEditable(false);
label.setAutoscrolls(true);
label.setLineWrap(false);
label.setFocusable(false);
label.setWrapStyleWord(true);
label.setLocation(0, 0);
dialog.setBackground(label.getBackground());
dialog.setLayout(new BorderLayout());
final JScrollPane pane = new JScrollPane();
pane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
pane.setViewportView(label);
dialog.add(pane, BorderLayout.CENTER);
final JButton button = new JButton(SwingAction.of(e -> dialog.dispose()));
button.setText("Close");
button.setMinimumSize(new Dimension(100, 30));
dialog.add(button, BorderLayout.SOUTH);
dialog.setMinimumSize(new Dimension(500, 300));
dialog.setSize(new Dimension(800, 600));
dialog.setResizable(true);
dialog.setLocationRelativeTo(this);
dialog.setDefaultCloseOperation(2);
dialog.setVisible(true);
}
private JTextArea currentLogTextArea = null;
public void addMessage(final Level level, final String message) {
try {
if (currentLogTextArea == null) {
currentLogTextArea = v_aiOutputLogArea;
}
currentLogTextArea.append(message + "\r\n");
} catch (final NullPointerException ex) { // This is bad, but we don't want TripleA crashing because of this...
System.out.print("Error adding Pro log message! Level: " + level.getName() + " Message: " + message);
}
}
public void notifyNewRound(final int roundNumber, final String name) {
SwingAction.invokeAndWait(() -> {
final JPanel newPanel = new JPanel();
final JScrollPane newScrollPane = new JScrollPane();
final JTextArea newTextArea = new JTextArea();
newTextArea.setColumns(20);
newTextArea.setRows(5);
newTextArea.setFont(new java.awt.Font("Segoe UI", 0, 10));
newTextArea.setEditable(false);
newScrollPane.getHorizontalScrollBar().setEnabled(true);
newScrollPane.setViewportView(newTextArea);
newPanel.setLayout(new GridLayout());
newPanel.add(newScrollPane);
v_logHolderTabbedPane.addTab(Integer.toString(roundNumber) + "-" + name, newPanel);
currentLogTextArea = newTextArea;
});
// Now remove round logging that has 'expired'.
// Note that this method will also trim all but the first and last log panels if logging is turned off
// (We always keep first round's log panel, and we keep last because the user might turn logging back on in the
// middle of the round)
trimLogRoundPanels();
}
private void trimLogRoundPanels() {
// If we're logging and we have trimming enabled, or if we have logging turned off
if ((ProLogSettings.loadSettings().EnableAILogging && ProLogSettings.loadSettings().LimitLogHistory)
|| !ProLogSettings.loadSettings().EnableAILogging) {
final int maxHistoryRounds;
if (ProLogSettings.loadSettings().EnableAILogging) {
maxHistoryRounds = ProLogSettings.loadSettings().LimitLogHistoryTo;
} else {
maxHistoryRounds = 1; // If we're not logging, trim to 1
}
SwingAction.invokeAndWait(() -> {
for (int i = 0; i < v_logHolderTabbedPane.getTabCount(); i++) {
// Remember, we never remove last tab, in case user turns logging back on in the middle of a round
if (i != 0 && i < v_logHolderTabbedPane.getTabCount() - maxHistoryRounds) {
// Remove the tab and decrease i by one, so the next component will be checked
v_logHolderTabbedPane.removeTabAt(i);
i--;
}
}
});
}
}
private javax.swing.JTextArea v_aiOutputLogArea;
private javax.swing.JCheckBox v_enableAILogging;
private javax.swing.JCheckBox v_limitLogHistoryCB;
private javax.swing.JSpinner v_limitLogHistoryToSpinner;
private javax.swing.JComboBox<String> v_logDepth;
private javax.swing.JTabbedPane v_logHolderTabbedPane;
private javax.swing.JTabbedPane v_tabPaneMain;
}