4 * Copyright 2015 TJ <hacker@iam.tj>.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 package uk.ac.ntu.n0521366.wsyd.management;
26 import java.io.FileWriter;
27 import java.io.BufferedWriter;
29 import javax.swing.ImageIcon;
30 import java.awt.Desktop;
32 import java.io.IOException;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.net.DatagramPacket;
36 import java.net.DatagramSocket;
37 import java.net.InetSocketAddress;
38 import javax.swing.Timer;
39 import javax.swing.table.DefaultTableModel;
40 import java.net.UnknownHostException;
41 import java.util.logging.Logger;
42 import java.util.logging.Level;
43 import java.util.logging.LogRecord;
44 import java.util.logging.Filter;
45 import java.util.Date;
46 import java.text.SimpleDateFormat;
47 import java.text.MessageFormat;
48 import java.util.ArrayList;
49 import uk.ac.ntu.n0521366.wsyd.libs.logging.TableModelHandler;
50 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageLogRecord;
51 import uk.ac.ntu.n0521366.wsyd.libs.message.MessagePresence;
52 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageServerControl;
53 import uk.ac.ntu.n0521366.wsyd.libs.net.WSYD_SocketAddress.Protocol;
54 import uk.ac.ntu.n0521366.wsyd.libs.net.*;
58 * @author TJ <hacker@iam.tj>
60 public class ServerManagement extends javax.swing.JFrame implements NetworkMessageEventListener, Filter {
64 static final Logger LOGGER = Logger.getLogger("ServerManagement");
67 * Location of resource bundles, images, icons
69 private static final String resourcePath = "/uk/ac/ntu/n0521366/wsyd/resources";
72 * Readable/displayable name of this application
77 * The UDP listener address for incoming log messages
79 WSYD_SocketAddress _logServerSA = null;
82 * UDP multi-cast presence advertiser
84 WSYD_SocketAddress _multicastAdvertiserSA = null;
87 * Log service running in a SwingWorker thread.
89 NetworkServerUDP _logServer = null;
92 * Multi-cast neighbour advertise and discover service in a SwingWorker thread.
94 NetworkServerUDPMulticast _multicastServer = null;
98 * Enable or suspend logging
100 private boolean _doLogging;
103 * Enable or suspend table auto-scroll
105 private boolean _autoScroll;
108 * Regular presence announcements
110 Timer multicastAnnounce;
114 * Instantiating code <em>must</em> also call initListeners()
116 * @see #initListeners()
118 public ServerManagement() {
119 _title = "ServerManagement";
120 LOGGER.setLevel(Level.ALL);
124 setLocationRelativeTo(null); // center on screen
125 // XXX: workaround for bug in NetBeans that doesn't set the displayed background colour, only the component colour, from the Properties editor
126 gDialogAbout.getContentPane().setBackground(gDialogAbout.getBackground());
130 * Initialise listeners and other objects that require a reference to 'this'.
132 * Passing 'this' from within the constructor is unsafe since the object is not
133 * fully constructed, so do it here. The compiler and virtual machine are free to move 'final'
134 * properties outside the constructor which means they may not be correctly
135 * initialised before the constructor returns. This is especially problematic
136 * in multi-threading applications.
138 * @return a reference to 'this' so method calls can be chained (e.g. new ServerManagement().initListeners().setVisible(true) )
139 * @throws UnknownHostException
141 public ServerManagement initListeners() throws UnknownHostException {
142 LOGGER.addHandler(new TableModelHandler(this)); // send messages to the GUI log table
143 LOGGER.setUseParentHandlers(false); // don't send messages to the default error stream logger of the parent
144 LOGGER.log(Level.INFO, "Server Management starting");
146 _logServerSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP);
147 _logServer = new NetworkServerUDP(_logServerSA, "ServerLog", LOGGER);
148 _logServer.addNetworkMessageEventListener(this, "Log");
149 _logServer.setSimulate(false);
150 _logServer.execute();
151 _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP);
152 _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, "ServerLogMC", LOGGER);
153 _multicastServer.addNetworkMessageEventListener(this, "Neighbour");
154 _multicastServer.execute();
156 ActionListener multicastAnnounceActionListener = new ActionListener() {
158 * Activated by timer events to send multi-cast neighbour announcements for the Log Service.
162 public void actionPerformed(ActionEvent e) {
163 // Create local log report first
164 LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence");
165 record.setSourceClassName("ServerLog");
166 record.setMillis(System.currentTimeMillis());
169 // Announce the Log Server service
170 MessagePresence mp = new MessagePresence("ServerLog", Network.PORTS_SERVER_LOG);
171 NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp);
172 nm.setSender("ServerLog");
173 _multicastServer.queueMessage(nm);
175 // clean up the known hosts map and keep Server menu up-to-date
176 ArrayList<String> servicesRemoved = _multicastServer.cleanServiceToHostMap(5000);
177 for (String service: servicesRemoved) {
180 gMenuServerSocial.setEnabled(false);
183 gMenuServerChat.setEnabled(false);
190 multicastAnnounce = new Timer(1000, multicastAnnounceActionListener);
191 multicastAnnounce.setInitialDelay(100);
192 multicastAnnounce.start();
198 * Add a log record to the log table if logging is enabled.
200 * Abusing an already-existing logging interface. This method isn't filtering, it is called by
201 * the Logger's TableModelHandler to publish records.
203 * @see TableModelHandler
205 * @return true if logging is enabled
208 public boolean isLoggable(LogRecord record) {
210 if (record != null) {
211 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
212 // add the log record to the log table
213 ((DefaultTableModel)gLogTable.getModel()).addRow(
215 df.format(new Date(record.getMillis())),
216 record.getLevel().toString(),
217 record.getSourceClassName(),
221 if (_autoScroll) { // keep last record added in the view
222 int row = gLogTable.getModel().getRowCount();
223 gLogTable.scrollRectToVisible(gLogTable.getCellRect(row, 0, true));
230 protected boolean UDPSend(NetworkMessage message) {
231 boolean result = false;
233 if (message != null) {
234 InetSocketAddress address = this._multicastServer.getTargetAddress(message.getTarget());
235 if (address != null) {
236 message.setSender("ServerManagement");
238 byte[] dataSend = NetworkMessage.serialize(message);
239 DatagramPacket packetSend = new DatagramPacket(dataSend, dataSend.length);
240 // set target's remote host address and port
241 packetSend.setAddress(address.getAddress());
242 packetSend.setPort(address.getPort());
244 DatagramSocket socket = new DatagramSocket();
245 // acknowledge receipt
246 socket.send(packetSend);
247 System.err.println(MessageFormat.format("Sending packet for {0} to {1} ({3}:{4}) from {2}", message.getIntent(), message.getTarget(), message.getSender(), packetSend.getAddress().getHostAddress(), packetSend.getPort()));
249 result = true; // successful
250 } catch (IOException e) {
251 // TODO: serverSend() add IOException handler
260 * This method is called from within the constructor to initialize the form.
261 * WARNING: Do NOT modify this code. The content of this method is always
262 * regenerated by the Form Editor.
264 @SuppressWarnings("unchecked")
265 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
266 private void initComponents() {
268 buttonGroup1 = new javax.swing.ButtonGroup();
269 gDialogAbout = new javax.swing.JDialog();
270 gTextAreaAbout = new javax.swing.JTextArea();
271 gBtnAbout = new javax.swing.JButton();
272 gFileChooser = new javax.swing.JFileChooser();
273 gLogScroller = new javax.swing.JScrollPane();
274 gLogTable = new javax.swing.JTable();
275 gMenuBar = new javax.swing.JMenuBar();
276 gMenuFile = new javax.swing.JMenu();
277 gMenuFileSave = new javax.swing.JMenuItem();
278 gMenuLog = new javax.swing.JMenu();
279 gMenuLogClear = new javax.swing.JMenuItem();
280 gMenuLogControl = new javax.swing.JCheckBoxMenuItem();
281 gMenuLogAutoScroll = new javax.swing.JCheckBoxMenuItem();
282 gMenuServers = new javax.swing.JMenu();
283 gMenuServerSocial = new javax.swing.JMenu();
284 gMenuServerSocialRestart = new javax.swing.JMenuItem();
285 gMenuServerSocialStop = new javax.swing.JMenuItem();
286 gMenuServerChat = new javax.swing.JMenu();
287 gMenuServerChatRestart = new javax.swing.JMenuItem();
288 gMenuServerChatStop = new javax.swing.JMenuItem();
289 gMenuHelp = new javax.swing.JMenu();
290 gMenuHelpAbout = new javax.swing.JMenuItem();
292 gDialogAbout.setTitle("About");
293 gDialogAbout.setBackground(new java.awt.Color(255, 255, 255));
294 gDialogAbout.setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
295 gDialogAbout.setMinimumSize(new java.awt.Dimension(590, 340));
296 gDialogAbout.setResizable(false);
297 gDialogAbout.getContentPane().setLayout(null);
299 gTextAreaAbout.setEditable(false);
300 gTextAreaAbout.setColumns(20);
301 gTextAreaAbout.setRows(5);
302 gTextAreaAbout.setText("Server Management client\n© Copyright 2015 TJ <hacker@iam.tj>\n\n<<< Click on the mug to learn more!\n\nI will disappear in 20 seconds.\n\n");
303 gTextAreaAbout.setBorder(null);
304 gDialogAbout.getContentPane().add(gTextAreaAbout);
305 gTextAreaAbout.setBounds(310, 30, 270, 200);
307 gBtnAbout.setBackground(new java.awt.Color(255, 255, 255));
308 gBtnAbout.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
309 gBtnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ntu/n0521366/wsyd/resources/ScroogledKeepCalmMug.png"))); // NOI18N
310 gBtnAbout.setText("We Stealz Your Dataz");
311 gBtnAbout.setBorder(null);
312 gBtnAbout.setBorderPainted(false);
313 gBtnAbout.setContentAreaFilled(false);
314 gBtnAbout.setDefaultCapable(false);
315 gBtnAbout.setFocusPainted(false);
316 gBtnAbout.setRolloverEnabled(false);
317 gBtnAbout.setVerticalAlignment(javax.swing.SwingConstants.TOP);
318 gBtnAbout.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
319 gBtnAbout.addActionListener(new java.awt.event.ActionListener() {
320 public void actionPerformed(java.awt.event.ActionEvent evt) {
324 gDialogAbout.getContentPane().add(gBtnAbout);
325 gBtnAbout.setBounds(0, 0, 530, 324);
327 gFileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
328 gFileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
329 gFileChooser.setDialogTitle("Save As");
331 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
332 setTitle("We Stealz Your Dataz Servers Management");
333 setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
335 gLogScroller.setAutoscrolls(true);
337 gLogTable.setModel(new javax.swing.table.DefaultTableModel(
339 {null, null, null, null}
342 "Time", "Level", "Facility", "Message"
345 Class[] types = new Class [] {
346 java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
348 boolean[] canEdit = new boolean [] {
349 false, false, false, false
352 public Class getColumnClass(int columnIndex) {
353 return types [columnIndex];
356 public boolean isCellEditable(int rowIndex, int columnIndex) {
357 return canEdit [columnIndex];
360 gLogTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
361 gLogTable.setFillsViewportHeight(true);
362 gLogTable.getTableHeader().setReorderingAllowed(false);
363 gLogScroller.setViewportView(gLogTable);
364 if (gLogTable.getColumnModel().getColumnCount() > 0) {
365 gLogTable.getColumnModel().getColumn(0).setPreferredWidth(128);
366 gLogTable.getColumnModel().getColumn(1).setPreferredWidth(128);
367 gLogTable.getColumnModel().getColumn(2).setPreferredWidth(128);
370 getContentPane().add(gLogScroller, java.awt.BorderLayout.CENTER);
372 gMenuFile.setText("File");
374 gMenuFileSave.setText("Save...");
375 gMenuFileSave.setActionCommand("FileSave");
376 gMenuFileSave.addActionListener(new java.awt.event.ActionListener() {
377 public void actionPerformed(java.awt.event.ActionEvent evt) {
378 gMenuFileSaveActionPerformed(evt);
381 gMenuFile.add(gMenuFileSave);
383 gMenuBar.add(gMenuFile);
385 gMenuLog.setText("Log");
387 gMenuLogClear.setText("Clear");
388 gMenuLogClear.setActionCommand("LogTableClear");
389 gMenuLogClear.addActionListener(new java.awt.event.ActionListener() {
390 public void actionPerformed(java.awt.event.ActionEvent evt) {
391 gMenuLogClearActionPerformed(evt);
394 gMenuLog.add(gMenuLogClear);
396 gMenuLogControl.setSelected(true);
397 gMenuLogControl.setText("Running");
398 gMenuLogControl.setActionCommand("LogControl");
399 gMenuLogControl.addActionListener(new java.awt.event.ActionListener() {
400 public void actionPerformed(java.awt.event.ActionEvent evt) {
401 gMenuLogControlActionPerformed(evt);
404 gMenuLog.add(gMenuLogControl);
406 gMenuLogAutoScroll.setSelected(true);
407 gMenuLogAutoScroll.setText("Auto-scroll");
408 gMenuLogAutoScroll.setActionCommand("LogAutoScroll");
409 gMenuLogAutoScroll.addActionListener(new java.awt.event.ActionListener() {
410 public void actionPerformed(java.awt.event.ActionEvent evt) {
411 gMenuLogAutoScrollActionPerformed(evt);
414 gMenuLog.add(gMenuLogAutoScroll);
416 gMenuBar.add(gMenuLog);
418 gMenuServers.setText("Servers");
420 gMenuServerSocial.setText("Social");
421 gMenuServerSocial.setEnabled(false);
423 gMenuServerSocialRestart.setText("Restart");
424 gMenuServerSocialRestart.setActionCommand("SocialRestart");
425 gMenuServerSocialRestart.addActionListener(new java.awt.event.ActionListener() {
426 public void actionPerformed(java.awt.event.ActionEvent evt) {
427 gMenuServerSocialRestartActionPerformed(evt);
430 gMenuServerSocial.add(gMenuServerSocialRestart);
432 gMenuServerSocialStop.setText("Stop");
433 gMenuServerSocialStop.setActionCommand("SocialStop");
434 gMenuServerSocial.add(gMenuServerSocialStop);
436 gMenuServers.add(gMenuServerSocial);
438 gMenuServerChat.setText("Chat");
439 gMenuServerChat.setEnabled(false);
441 gMenuServerChatRestart.setText("Restart");
442 gMenuServerChatRestart.setActionCommand("ChatRestart");
443 gMenuServerChat.add(gMenuServerChatRestart);
445 gMenuServerChatStop.setText("Stop");
446 gMenuServerChatStop.setActionCommand("ChatStop");
447 gMenuServerChat.add(gMenuServerChatStop);
449 gMenuServers.add(gMenuServerChat);
451 gMenuBar.add(gMenuServers);
453 gMenuHelp.setText("Help");
455 gMenuHelpAbout.setText("About");
456 gMenuHelpAbout.addActionListener(new java.awt.event.ActionListener() {
457 public void actionPerformed(java.awt.event.ActionEvent evt) {
458 gMenuHelpAboutActionPerformed(evt);
461 gMenuHelp.add(gMenuHelpAbout);
463 gMenuBar.add(gMenuHelp);
465 setJMenuBar(gMenuBar);
468 }// </editor-fold>//GEN-END:initComponents
470 private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed
471 // TODO add your handling code here:
472 System.err.println("Requesting ServerSocial Restart");
473 MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES);
474 NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocial", mc);
475 nm.setSender("ServerLog");
479 }//GEN-LAST:event_gMenuServerSocialRestartActionPerformed
482 * When the (disguised) mug-icon button is pressed load a web page in the system default browser.
484 * Displays a news story about Microsoft Store's 'Scroogle' mug which coincidentally has a tag line
485 * that is almost identical to the chosen name of this application.
489 private void AboutAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AboutAction
491 Desktop.getDesktop().browse(URI.create("http://www.slate.com/blogs/future_tense/2013/11/20/microsoft_scroogled_gear_anti_google_t_shirts_mugs_say_keep_calm_while_we.html"));
492 } catch(IOException e) {
494 }//GEN-LAST:event_AboutAction
497 * Show the Help>About dialog and auto-close it after 20 seconds.
501 private void gMenuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuHelpAboutActionPerformed
502 ActionListener autoCloseAboutDlg = new ActionListener() {
504 public void actionPerformed(ActionEvent e) {
505 gDialogAbout.setVisible(false);
509 gDialogAbout.setLocationRelativeTo(this); // center in application window
510 gDialogAbout.setVisible(true);
511 Timer autoClose = new Timer(20000, autoCloseAboutDlg);
513 }//GEN-LAST:event_gMenuHelpAboutActionPerformed
516 * Save log entries to a file.
520 private void gMenuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuFileSaveActionPerformed
521 if (gFileChooser.showSaveDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
522 File saveAs = gFileChooser.getSelectedFile();
524 BufferedWriter writer = new BufferedWriter(new FileWriter(saveAs));
527 for (int row = 0; row < gLogTable.getModel().getRowCount(); row++) {
528 StringBuilder record = new StringBuilder();
529 int colMax = gLogTable.getModel().getColumnCount();
530 for (int col = 0; col < colMax; col++) {
531 record.append(gLogTable.getModel().getValueAt(row, col));
532 if (col < colMax - 1) {
536 writer.write(record.toString());
540 } catch (IOException e) {
541 System.err.println("Unable to write to file");
544 }//GEN-LAST:event_gMenuFileSaveActionPerformed
547 * Clear the log table.
550 private void gMenuLogClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogClearActionPerformed
551 ((DefaultTableModel)gLogTable.getModel()).setRowCount(0);
552 }//GEN-LAST:event_gMenuLogClearActionPerformed
555 * Enable or disable logging.
558 private void gMenuLogControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogControlActionPerformed
559 _doLogging = !_doLogging;
560 gMenuLogControl.setSelected(_doLogging);
561 }//GEN-LAST:event_gMenuLogControlActionPerformed
564 * Enable or disable automatic scrolling of the log table.
567 private void gMenuLogAutoScrollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogAutoScrollActionPerformed
568 _autoScroll = !_autoScroll;
569 gMenuLogAutoScroll.setSelected(_autoScroll);
570 }//GEN-LAST:event_gMenuLogAutoScrollActionPerformed
573 * Receive a NetworkMessageEvent and dispose of it
577 public void NetworkMessageReceived(NetworkMessageEvent event) {
578 NetworkMessage nm = event.getNetworkMessage();
579 if (nm == null || !_doLogging)
581 // is it a LogRecord?
582 switch (nm.getIntent()) {
584 MessageLogRecord m = (MessageLogRecord) nm.getMessage();
587 this.isLoggable(m.record);
590 // TODO: NetworkMessageReceived(): Test Multicast message received handler to enable menu items for recognised servers
591 String type = nm.getMessage().getMessageType();
592 if (type.equals(MessagePresence.getType())) { // Presence
593 MessagePresence mp = (MessagePresence)nm.getMessage();
594 switch (mp.serviceName) {
596 gMenuServerSocial.setEnabled(true);
599 gMenuServerChat.setEnabled(true);
605 default: // log all unhandled messages
606 LogRecord record = new LogRecord(Level.WARNING,
607 MessageFormat.format("Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"",
608 nm.getIntent(), nm.getSender(), nm.getTarget() )
610 record.setMillis(System.currentTimeMillis());
616 * @param args the command line arguments
618 public static void main(String args[]) {
619 /* Set the Nimbus look and feel */
620 //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
621 /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
622 * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
625 for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
626 if ("Nimbus".equals(info.getName())) {
627 javax.swing.UIManager.setLookAndFeel(info.getClassName());
631 } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|javax.swing.UnsupportedLookAndFeelException ex) {
632 java.util.logging.Logger.getLogger(ServerManagement.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
639 /* Create and display the form */
640 java.awt.EventQueue.invokeLater(new Runnable() {
644 new ServerManagement().initListeners().setVisible(true);
646 catch(UnknownHostException e) {
647 System.err.println("Error: cannot create log server listener socket");
653 // Variables declaration - do not modify//GEN-BEGIN:variables
654 private javax.swing.ButtonGroup buttonGroup1;
655 private javax.swing.JButton gBtnAbout;
656 private javax.swing.JDialog gDialogAbout;
657 private javax.swing.JFileChooser gFileChooser;
658 private javax.swing.JScrollPane gLogScroller;
659 private javax.swing.JTable gLogTable;
660 private javax.swing.JMenuBar gMenuBar;
661 private javax.swing.JMenu gMenuFile;
662 private javax.swing.JMenuItem gMenuFileSave;
663 private javax.swing.JMenu gMenuHelp;
664 private javax.swing.JMenuItem gMenuHelpAbout;
665 private javax.swing.JMenu gMenuLog;
666 private javax.swing.JCheckBoxMenuItem gMenuLogAutoScroll;
667 private javax.swing.JMenuItem gMenuLogClear;
668 private javax.swing.JCheckBoxMenuItem gMenuLogControl;
669 private javax.swing.JMenu gMenuServerChat;
670 private javax.swing.JMenuItem gMenuServerChatRestart;
671 private javax.swing.JMenuItem gMenuServerChatStop;
672 private javax.swing.JMenu gMenuServerSocial;
673 private javax.swing.JMenuItem gMenuServerSocialRestart;
674 private javax.swing.JMenuItem gMenuServerSocialStop;
675 private javax.swing.JMenu gMenuServers;
676 private javax.swing.JTextArea gTextAreaAbout;
677 // End of variables declaration//GEN-END:variables