2 * Copyright (C) 2015 Roland Haeder
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package org.mxchange.addressbook.client.gui;
19 import java.awt.BorderLayout;
20 import java.awt.GridLayout;
21 import java.awt.event.ActionEvent;
22 import java.awt.event.ActionListener;
23 import java.awt.event.MouseAdapter;
24 import java.awt.event.MouseEvent;
25 import java.awt.event.WindowAdapter;
26 import java.awt.event.WindowEvent;
27 import java.io.IOException;
28 import java.sql.SQLException;
29 import java.text.MessageFormat;
30 import javax.swing.BorderFactory;
31 import javax.swing.BoxLayout;
32 import javax.swing.DefaultComboBoxModel;
33 import javax.swing.JButton;
34 import javax.swing.JComboBox;
35 import javax.swing.JDialog;
36 import javax.swing.JFormattedTextField;
37 import javax.swing.JFrame;
38 import javax.swing.JLabel;
39 import javax.swing.JMenu;
40 import javax.swing.JMenuBar;
41 import javax.swing.JMenuItem;
42 import javax.swing.JPanel;
43 import javax.swing.JScrollPane;
44 import javax.swing.JTable;
45 import javax.swing.JTextArea;
46 import javax.swing.JTextField;
47 import javax.swing.border.TitledBorder;
48 import javax.swing.table.TableModel;
49 import org.mxchange.addressbook.BaseAddressbookSystem;
50 import org.mxchange.addressbook.application.AddressbookApplication;
51 import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
52 import org.mxchange.addressbook.manager.contact.ManageableAddressbookContact;
53 import org.mxchange.jcore.client.Client;
54 import org.mxchange.jcore.client.gui.ClientFrame;
55 import org.mxchange.jcore.contact.Contact;
56 import org.mxchange.jcore.contact.Gender;
57 import org.mxchange.jcore.exceptions.BadTokenException;
58 import org.mxchange.jcore.exceptions.FrameAlreadyInitializedException;
59 import org.mxchange.jcore.model.swing.contact.ContactTableModel;
63 * @author Roland Haeder
65 public class AddressbookFrame extends BaseAddressbookSystem implements ClientFrame {
70 private static ClientFrame self;
73 * Singelton getter for this frame instance.
75 * @param client Client instance
76 * @return Returns a singelton instance of this frame
78 public static final ClientFrame getSelfInstance (final Client client) {
80 if (!(self instanceof ClientFrame)) {
81 // Create new instance
82 self = new AddressbookFrame(client);
90 * Dialog box "add contact"
92 private JDialog addContact;
95 * Frame instance for "add own data"
97 private JMenuItem addOwnItem;
100 * Instance to table model
102 private TableModel dataModel;
107 private JTable dataTable;
110 * Frame instance for "edit own data"
112 private JMenuItem editOwnItem;
117 private final JFrame frame;
120 * Whether this frame has been initialized
122 private boolean initialized;
125 * Status label needs to be updated
127 private JLabel statusLabel;
130 * Creates an instance of this frame with a client instance
134 private AddressbookFrame (final Client client) {
136 this.getLogger().trace(MessageFormat.format("client={0}: CALLED!", client)); //NOI18N
138 // Set frame instance
139 this.frame = new JFrame();
140 this.frame.setTitle(this.generateFrameTitle("main")); //NOI18N
143 this.setClient(client);
146 this.getLogger().trace("EXIT!"); //NOI18N
150 public Contact doEnterOwnData () {
152 this.getLogger().trace("CALLED!"); //NOI18N
154 // Is the "add contact" window visible?
155 if (this.addContact.isVisible()) {
156 // Something bad happened
157 throw new IllegalStateException("Window addContact is already visible."); //NOI18N
160 // Disable main window
161 this.frame.setEnabled(false);
163 // Make other window visible
164 this.addContact.setVisible(true);
167 this.getLogger().trace("Returning null : EXIT!"); //NOI18N
169 // Return value is not supported
174 * Shutdown this frame
177 public void doShutdown () {
179 this.getLogger().trace("CALLED!"); //NOI18N
181 // First only show shutdown status
182 this.updateStatus("shutdown"); //NOI18N
185 this.getLogger().trace("EXIT!"); //NOI18N
190 * Enables main window (frame)
193 public void enableMainWindow () {
195 this.getLogger().trace("CALLED!"); //NOI18N
198 this.frame.setEnabled(true);
200 // Request focus for this window
201 this.frame.requestFocus();
204 this.getLogger().trace("EXIT!"); //NOI18N
208 * Setups the frame, do not set isInitialized here
210 * @param client Client instance
213 public void setupFrame (final Client client) throws IOException, BadTokenException {
215 this.getLogger().trace(MessageFormat.format("client={0}: CALLED!", client)); //NOI18N
217 // Get and cast manager instance
218 ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getClient().getManager();
220 // Has the user entered own data?
221 if (manager.isOwnContactAdded()) {
223 this.getLogger().debug("Disabling menus: isOwnContactAdded()=false"); //NOI18N
225 // Not entered yet, so disable "add" menu
226 this.addOwnItem.setEnabled(false);
229 this.editOwnItem.setEnabled(false);
232 // Make the frame visible
233 this.frame.setVisible(true);
236 this.updateStatus("done"); //NOI18N
239 this.getLogger().trace("EXIT!"); //NOI18N
243 * Initalizes this frame. Having initComponents() exposed (publicly
244 * accessible) means that any other object can initialize components which
248 * org.mxchange.jcore.exceptions.FrameAlreadyInitializedException If
249 * this method has been called twice
252 public void init () throws FrameAlreadyInitializedException {
254 this.getLogger().trace("CALLED!"); //NOI18N
256 // Has this frame been initialized?
257 if (this.isInitialized()) {
259 throw new FrameAlreadyInitializedException();
263 this.initComponents();
266 this.initialized = true;
269 this.getLogger().trace("EXIT!"); //NOI18N
273 * Returns field isInitialized. This flag indicates whether this frame has
274 * been initialized or not.
276 * @return Field isInitialized
279 public final boolean isInitialized () {
280 return this.initialized;
284 * Shuts down the application.
287 public void shutdownApplication () {
289 this.getLogger().trace("CALLED!"); //NOI18N
291 // To do this, the frame must be initialized
292 if (!this.isInitialized()) {
293 // Not initalized, so bad call
294 this.getLogger().fatal("Bad call of shutdownApplication(). Please report this."); //NOI18N
298 // Call shutdown method
300 this.getClient().getApplication().doShutdown();
301 } catch (final SQLException | IOException ex) {
303 this.abortProgramWithException(ex);
307 this.getLogger().trace("EXIT!"); //NOI18N
311 * Adds a new menu item with given key to menu instance
313 * @param menu Menu instance to add item to
314 * @param key Message key part
315 * @param listener Listener instance
317 private void addMenuItem (final JMenu menu, final String key, final ActionListener listener) {
319 this.getLogger().trace(MessageFormat.format("menu={0},key={1},listener={2} - CALLED!", menu, key, listener)); //NOI18N
322 JMenuItem item = this.initMenuItemWithTooltip(key);
325 item.addActionListener(listener);
331 this.getLogger().trace("EXIT!"); //NOI18N
335 * Adds a JTextField with label and tool tip to given panel
337 * @param panel Panel instance to add text field
338 * @param key Part of message key from resource bundle
339 * @param fieldLength Length of text field
341 private void addTextFieldWithLabelToPanel (final JPanel panel, final String key, final int fieldLength) {
343 this.getLogger().trace(MessageFormat.format("panel={0},key={1},fieldLength={2} - CALLED!", panel, key, fieldLength)); //NOI18N
345 // Init label for given key
346 JLabel label = new JLabel(this.getBundle().getString(String.format("AddressbookFrame.%s.text", key))); //NOI18N
348 // And input box wih tool tip
349 JTextField field = new JTextField(fieldLength);
350 field.setToolTipText(this.getBundle().getString(String.format("AddressbookFrame.%s.toolTipText", key))); //NOI18N
357 this.getLogger().trace("EXIT!"); //NOI18N
361 * Generates a title for borders
363 * @param key Key part to look for
364 * @return Human-readable title
366 private String generateBorderTitle (final String key) {
367 // Call bundle instance
368 return this.getBundle().getString(String.format("AddressbookFrame.border.%s.title.text", key)); //NOI18N
372 * Generates a title for all frames based on given sub title key. If null is
373 * given, the sub title is not generated.
375 * @param subKey Key for sub title resource
376 * @return A full application title
378 private String generateFrameTitle (final String subKey) {
380 String title = AddressbookApplication.printableTitle();
383 if (subKey != null) {
385 title = String.format("%s - %s", title, this.getBundle().getString(String.format("AddressbookFrame.%s.title.text", subKey))); //NOI18N
393 * Initializes "add" and "cancel" buttons
395 private void initAddCancelButtons () {
397 this.getLogger().trace("CALLED!"); //NOI18N
400 JPanel panel = new JPanel();
401 panel.setLayout(new GridLayout(1, 2, 10, 10));
403 // Generate "add" button
404 JButton addButton = new JButton(this.getBundle().getString("AddressbookFrame.button.addAddress.text"));
407 addButton.addActionListener(new AddActionListener(this.addContact, this));
409 // Add button to panel
410 panel.add(addButton);
412 // Generate "cancel" button
413 JButton cancelButton = new JButton(this.getBundle().getString("AddressbookFrame.button.cancel.text"));
416 cancelButton.addActionListener(new CancelActionListener(this.addContact, this));
418 // Add button to panel
419 panel.add(cancelButton);
421 // Add panel to main panel
422 this.addContact.add(panel);
425 this.getLogger().trace("EXIT!"); //NOI18N
429 * Initializes "add contact" dialog
431 private void initAddContactDialog () {
433 this.getLogger().trace("CALLED!"); //NOI18N
435 // Instance dialog and set title
436 this.addContact = new JDialog();
437 this.addContact.setTitle(this.generateFrameTitle("dialog.addContact")); //NOI18N
440 this.addContact.setLayout(new GridLayout(0, 1, 2, 2));
442 // Only hide it on close and make it appear in middle of screen
443 this.addContact.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
444 this.addContact.setLocationRelativeTo(this.frame);
446 // Set always on top and auto-focus
447 this.addContact.setAlwaysOnTop(true);
448 this.addContact.setAutoRequestFocus(true);
451 this.addContact.setSize(500, 500);
453 // And it is not resizeable
454 this.addContact.setResizable(false);
457 * Add listener which asks for confirmation, if data has been entered
458 * but not saved yet. The user may appriciate this ... ;-)
462 this.addContact.addWindowListener(new WindowAdapter() {
464 * Invoked when a window has been closed.
467 public void windowClosed (final WindowEvent e) {
468 // Enable main window again
469 AddressbookFrame.getSelfInstance(null).enableMainWindow();
473 * Invoked when a window is in the process of being closed. The
474 * close operation can be overridden at this point.
477 public void windowClosing (final WindowEvent e) {
478 e.getWindow().dispose();
484 initNameDataPanel(this.addContact);
486 // 2) "address" panel
487 initAddressDataPanel(this.addContact);
490 initOtherDataPanel(this.addContact);
492 // 4) "Add" and "Cancel" buttons, combined they are unique for this dialog
493 initAddCancelButtons();
495 // x)Only for developing:
496 /* DEBUG: */ this.addContact.setVisible(true);
499 this.getLogger().trace("EXIT!"); //NOI18N
503 * Initializes address panel
505 * @param dialog A JDialog instance to this components to
507 private void initAddressDataPanel (final JDialog dialog) {
509 this.getLogger().trace("CALLED!"); //NOI18N
511 // Panel "address" input boxes
512 JPanel addressPanel = new JPanel();
513 addressPanel.setLayout(new GridLayout(0, 4, 3, 3));
515 // Set border to titled version
516 addressPanel.setBorder(new TitledBorder(this.generateBorderTitle("address"))); //NOI18N
518 // Add text field for street
519 this.addTextFieldWithLabelToPanel(addressPanel, "street", 20); //NOI18N
522 JLabel numberLabel = new JLabel(this.getBundle().getString("AddressbookFrame.number.text"));
524 // And text field, but only accept numbers
525 JFormattedTextField number = new JFormattedTextField();
526 number.setToolTipText(this.getBundle().getString("AddressbookFrame.number.toolTipText"));
528 // Add both to street panel
529 addressPanel.add(numberLabel);
530 addressPanel.add(number);
532 // Label for ZIP code, again numbers only
533 JLabel zipLabel = new JLabel(this.getBundle().getString("AddressbookFrame.zip.text"));
535 // Init text field with label
536 JFormattedTextField zip = new JFormattedTextField();
537 zip.setToolTipText(this.getBundle().getString("AddressbookFrame.zip.toolTipText"));
539 // Add both to street panel
540 addressPanel.add(zipLabel);
541 addressPanel.add(zip);
543 // Add text field for city name
544 this.addTextFieldWithLabelToPanel(addressPanel, "city", 20); //NOI18N
546 // Add panel to dialog
547 dialog.add(addressPanel);
550 this.getLogger().trace("EXIT!"); //NOI18N
554 * Initialize components
556 private void initComponents () {
558 this.getLogger().trace("CALLED!"); //NOI18N
560 // Set default close operation
561 this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
563 // Register shutdown listener
564 this.frame.addWindowListener(new WindowAdapter() {
566 * Invoked when a window has been closed.
569 public void windowClosed (final WindowEvent e) {
570 // Shutdown application cleanly
571 self.shutdownApplication();
575 * Invoked when a window is in the process of being closed. The
576 * close operation can be overridden at this point.
579 public void windowClosing (final WindowEvent e) {
580 // Also shutdown cleanly here
581 self.shutdownApplication();
585 // Setup layout manager
586 this.frame.setLayout(new BorderLayout(2, 2));
589 this.frame.setSize(700, 400);
591 // Center window in middle of screen, instead of top-left corner
592 this.frame.setLocationRelativeTo(null);
603 // Init other windows
607 this.getLogger().trace("EXIT!"); //NOI18N
611 * Initializes a menu item instance with tool tip
613 * @param key Message key part
614 * @return A finished JMenuItem instance
616 private JMenuItem initMenuItemWithTooltip (final String key) {
618 this.getLogger().trace(MessageFormat.format("key={0} - CALLED!", key)); //NOI18N
620 JMenuItem item = new JMenuItem(this.getBundle().getString(String.format("AddressbookFrame.menuItem.%s.text", key))); //NOI18N
621 item.setToolTipText(this.getBundle().getString(String.format("AddressbookFrame.menuItem.%s.toolTipText", key))); //NOI18N
624 this.getLogger().trace(MessageFormat.format("item={0} - EXIT!", item)); //NOI18N
631 * Initializes the menu system
633 private void initMenuSystem () {
635 this.getLogger().trace("CALLED!"); //NOI18N
637 // Init menu bar, menu and item instances
638 JMenuBar menuBar = new JMenuBar();
644 menu = new JMenu(this.getBundle().getString("AddressbookFrame.menu.file.text"));
647 // 1.x) Exit program (should be last)
648 this.addMenuItem(menu, "exitProgram", new ActionListener() { //NOI18N
650 * If the user has performed this action
652 * @param e An instance of an ActionEvent class
655 public void actionPerformed (final ActionEvent e) {
656 self.shutdownApplication();
660 // Add menu -> menu bar
664 // 2) Addressbook menu
665 menu = new JMenu(this.getBundle().getString("AddressbookFrame.menu.addressbook.text"));
668 this.addOwnItem = this.initMenuItemWithTooltip("addOwnData"); //NOI18N
670 // Add listener to exit menu
671 this.addOwnItem.addActionListener(new ActionListener() {
673 * If the user has performed this action
675 * @param e An instance of an ActionEvent class
678 public void actionPerformed (final ActionEvent e) {
680 ManageableAddressbookContact manager = (ManageableAddressbookContact) self.getClient().getManager();
681 manager.doEnterOwnData();
682 } catch (final ContactAlreadyAddedException ex) {
683 // Already added, log away
684 // @TODO maybe output message here?
685 self.logException(ex);
686 } catch (final IOException | BadTokenException ex) {
687 // Somethind bad happened here
688 // @TODO Output error message here?
694 menu.add(this.addOwnItem);
696 // 2.2) Edit own data
697 this.editOwnItem = this.initMenuItemWithTooltip("editOwnData"); //NOI18N
699 // Add listener to exit menu
700 this.editOwnItem.addActionListener(new ActionListener() {
702 * If the user has performed this action
704 * @param e An instance of an ActionEvent class
707 public void actionPerformed (final ActionEvent e) {
708 ManageableAddressbookContact manager = (ManageableAddressbookContact) self.getClient().getManager();
710 manager.doChangeOwnData();
711 } catch (final IOException | BadTokenException ex) {
712 self.logException(ex);
718 menu.add(this.editOwnItem);
721 // 1) Add new contact
722 this.addMenuItem(menu, "addNewContact", new ActionListener() { //NOI18N
724 * If the user has performed this action
726 * @param e An instance of an ActionEvent class
729 public void actionPerformed (final ActionEvent e) {
730 ManageableAddressbookContact manager = (ManageableAddressbookContact) self.getClient().getManager();
731 manager.doAddOtherAddress();
735 // Add menu -> menu bar
738 // Add menu bar -> frame
739 this.frame.add(menuBar, BorderLayout.NORTH);
742 this.getLogger().trace("EXIT!"); //NOI18N
746 * Initializes name panel
748 * @param dialog A JDialog instance to this components to
750 private void initNameDataPanel (final JDialog dialog) {
752 this.getLogger().trace(MessageFormat.format("dialog={0} - CALLED!", dialog)); //NOI18N
754 // Panel "name" input boxes
755 JPanel namePanel = new JPanel();
756 namePanel.setLayout(new GridLayout(0, 2, 3, 3));
758 // Set border to titled version
759 namePanel.setBorder(new TitledBorder(this.generateBorderTitle("name"))); //NOI18N
762 JLabel gLabel = new JLabel(this.getBundle().getString("AddressbookFrame.gender.text"));
765 Gender[] genders = Gender.values();
767 // Init gender combo box with tool tip
768 JComboBox<Gender> gender = new JComboBox<>(new DefaultComboBoxModel<>(genders));
769 gender.setToolTipText(this.getBundle().getString("AddressbookFrame.gender.toolTipText"));
771 // Add both to gender panel
772 namePanel.add(gLabel);
773 namePanel.add(gender);
775 // Add text field for surname
776 this.addTextFieldWithLabelToPanel(namePanel, "surname", 20); //NOI18N
778 // Add text field for family name
779 this.addTextFieldWithLabelToPanel(namePanel, "familyName", 20); //NOI18N
781 // Finally add panel to dialog
782 dialog.add(namePanel);
785 this.getLogger().trace("EXIT!"); //NOI18N
789 * Initializes "other" data panel
791 * @param dialog A JDialog instance to this components to
792 * @todo Fill this with life
794 private void initOtherDataPanel (final JDialog dialog) {
796 this.getLogger().trace(MessageFormat.format("dialog={0} - CALLED!", dialog)); //NOI18N
798 // Panel "other" input boxes
799 JPanel otherPanel = new JPanel();
800 otherPanel.setLayout(new GridLayout(0, 2, 3, 3));
801 otherPanel.setBorder(new TitledBorder(this.generateBorderTitle("other"))); //NOI18N
803 // Add text field for email address
804 this.addTextFieldWithLabelToPanel(otherPanel, "emailAddress", 20); //NOI18N
806 // Add text field for phone number
807 this.addTextFieldWithLabelToPanel(otherPanel, "phoneNumber", 20); //NOI18N
809 // Add text field for cellphone number
810 this.addTextFieldWithLabelToPanel(otherPanel, "cellphoneNumber", 20); //NOI18N
812 // Add text field for fax number
813 this.addTextFieldWithLabelToPanel(otherPanel, "faxNumber", 20); //NOI18N
816 JLabel commentLabel = new JLabel(this.getBundle().getString("AddressbookFrame.comment.text"));
818 // Init text area with tool tip
819 JTextArea comment = new JTextArea(5, 20);
820 comment.setToolTipText(this.getBundle().getString("AddressbookFrame.comment.toolTipText"));
823 otherPanel.add(commentLabel);
824 otherPanel.add(comment);
826 // Finally add panel to dialog
827 dialog.add(otherPanel);
830 this.getLogger().trace("EXIT!"); //NOI18N
834 * Initialize other dialogs (e.g. "Add contact")
836 private void initOtherDialogs () {
838 this.getLogger().trace("CALLED!"); //NOI18N
840 // Init other windows:
842 initAddContactDialog();
845 this.getLogger().trace("EXIT!"); //NOI18N
849 * Initializes status panel
851 private void initStatusPanel () {
853 this.getLogger().trace("CALLED!"); //NOI18N
855 // Init status label (which needs to be updated
856 this.statusLabel = new JLabel();
857 this.updateStatus("initializing"); //NOI18N
859 // Init status bar in south
860 JPanel panel = new JPanel();
861 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
862 panel.add(this.statusLabel);
863 panel.setBorder(BorderFactory.createEtchedBorder());
865 // Add panel to frame
866 this.frame.add(panel, BorderLayout.SOUTH);
869 this.getLogger().trace("EXIT!"); //NOI18N
873 * Initializes the table which will show all contacts
875 private void initTable () {
877 this.getLogger().trace("CALLED!"); //NOI18N
879 // Instance table model
880 this.dataModel = new ContactTableModel(this.getClient());
883 this.dataTable = new JTable(this.dataModel);
885 // Add mouse listener
886 this.dataTable.addMouseListener(new MouseAdapter() {
888 * If the user peformed a click on a cell
890 * @param e Mouse event instance
893 public void mouseClicked (final MouseEvent e) {
894 throw new UnsupportedOperationException("Unfinished."); //NOI18N
898 // Instance scroll pane
899 JScrollPane scroller = new JScrollPane();
901 // Add table to scroll pane
902 scroller.setViewportView(this.dataTable);
903 scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
904 scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
907 this.frame.add(scroller, BorderLayout.CENTER);
910 this.getLogger().trace("EXIT!"); //NOI18N
914 * Updates status to given type
916 * @param type Status type
918 private void updateStatus (final String type) {
920 this.getLogger().trace(MessageFormat.format("type={0} - CALLED!", type)); //NOI18N
922 // Set status message
923 this.statusLabel.setText(this.getBundle().getString(String.format("AddressbookFrame.statusLabel.%s.text", type))); //NOI18N
926 this.getLogger().trace("EXIT!"); //NOI18N
930 * Class for "add address" button
932 private static class AddActionListener extends BaseAddressbookSystem implements ActionListener {
936 private final JDialog dialog;
939 * Frame (not JFrame) instance
941 private final ClientFrame frame;
944 * Constructor for action listener
946 * @param dialog Dialog instance to call back
947 * @param frame Frame instance (not JFrame)
949 protected AddActionListener (final JDialog dialog, final ClientFrame frame) {
950 // Set dialog and frame here
951 this.dialog = dialog;
956 * If the action has been performed
958 * @param e The performed action event
961 public void actionPerformed (final ActionEvent e) {
962 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
967 * Class for "cancel address" button
969 private static class CancelActionListener extends BaseAddressbookSystem implements ActionListener {
973 private final JDialog dialog;
976 * Frame (not JFrame) instance
978 private final ClientFrame frame;
981 * Constructor for action listener
983 * @param dialog Dialog instance to call back
984 * @param frame Frame instance (not JFrame)
986 protected CancelActionListener (final JDialog dialog, final ClientFrame frame) {
987 // Set dialog and frame here
988 this.dialog = dialog;
993 * If the action has been performed
995 * @param e The performed action event
998 public void actionPerformed (final ActionEvent e) {
999 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.