]> git.mxchange.org Git - jaddressbook-lib.git/blob - Addressbook/src/org/mxchange/addressbook/client/gui/AddressbookFrame.java
92e8dfe375646bba016972fa4d2fc863ae1ce076
[jaddressbook-lib.git] / Addressbook / src / org / mxchange / addressbook / client / gui / AddressbookFrame.java
1 /*
2  * Copyright (C) 2015 Roland Haeder
3  *
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.
8  *
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.
13  *
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/>.
16  */
17 package org.mxchange.addressbook.client.gui;
18
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.text.MessageFormat;
28 import javax.swing.BorderFactory;
29 import javax.swing.BoxLayout;
30 import javax.swing.DefaultComboBoxModel;
31 import javax.swing.InputVerifier;
32 import javax.swing.JComboBox;
33 import javax.swing.JComponent;
34 import javax.swing.JDialog;
35 import javax.swing.JFrame;
36 import javax.swing.JLabel;
37 import javax.swing.JMenu;
38 import javax.swing.JMenuBar;
39 import javax.swing.JMenuItem;
40 import javax.swing.JPanel;
41 import javax.swing.JScrollPane;
42 import javax.swing.JTable;
43 import javax.swing.JTextField;
44 import javax.swing.border.TitledBorder;
45 import javax.swing.table.TableModel;
46 import org.mxchange.addressbook.BaseFrameworkSystem;
47 import org.mxchange.addressbook.application.AddressbookApplication;
48 import org.mxchange.addressbook.client.Client;
49 import org.mxchange.addressbook.contact.Gender;
50 import org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException;
51 import org.mxchange.addressbook.model.contact.ContactTableModel;
52
53 /**
54  *
55  * @author Roland Haeder
56  */
57 public class AddressbookFrame extends BaseFrameworkSystem implements ClientFrame {
58
59         /**
60          * Own instance
61          */
62         private static ClientFrame self;
63
64         /**
65          * Singelton getter for this frame instance.
66          *
67          * @param client Client instance
68          * @return Returns a singelton instance of this frame
69          */
70         public static final ClientFrame getSelfInstance (final Client client) {
71                 // Is it set?
72                 if (!(self instanceof ClientFrame)) {
73                         // Create new instance
74                         self = new AddressbookFrame(client);
75                 }
76
77                 // Return instance
78                 return self;
79         }
80
81         /**
82          * Dialog box "add contact"
83          */
84         private JDialog addContact;
85
86         /**
87          * Frame instance for "add own data"
88          */
89         private JMenuItem addOwnItem;
90
91         /**
92          * Instance to table model
93          */
94         private TableModel dataModel;
95
96         /**
97          * Table instance
98          */
99         private JTable dataTable;
100
101         /**
102          * Frame instance for "edit own data"
103          */
104         private JMenuItem editOwnItem;
105
106         /**
107          * Frame instance
108          */
109         private final JFrame frame;
110
111         /**
112          * Whether this frame has been initialized
113          */
114         private boolean isInitialized;
115
116         /**
117          * Layout instance
118          */
119         private GridLayout layout;
120
121         /**
122          * Status label needs to be updated
123          */
124         private JLabel statusLabel;
125
126         /**
127          * Creates an instance of this frame with a client instance
128          *
129          * @param client
130          */
131         private AddressbookFrame (final Client client) {
132                 // Debug line
133                 this.getLogger().trace(MessageFormat.format("client={0}: CALLED!", client)); //NOI18N
134
135                 // Set frame instance
136                 this.frame = new JFrame();
137                 this.frame.setTitle(this.generateFrameTitle("main")); //NOI18N
138
139                 // Set client here
140                 this.setClient(client);
141         }
142
143         /**
144          * Shutdown this frame
145          */
146         @Override
147         public void doShutdown () {
148                 // First only show shutdown status
149                 this.updateStatus("shutdown"); //NOI18N
150         }
151
152         /**
153          * Setups the frame, do not set isInitialized here
154          *
155          * @param client Client instance
156          */
157         @Override
158         public void setupFrame (final Client client) {
159                 // Debug line
160                 this.getLogger().trace(MessageFormat.format("client={0}: CALLED!", client)); //NOI18N
161
162                 // Has the user entered own data?
163                 if (this.getClient().getContactManager().isOwnContactAdded()) {
164                         // Debug message
165                         this.getLogger().debug("Disabling menus: isOwnContactAdded()=false"); //NOI18N
166
167                         // Not entered yet, so disable "add" menu
168                         this.addOwnItem.setEnabled(false);
169                 } else {
170                         // Disable "edit"
171                         this.editOwnItem.setEnabled(false);
172                 }
173
174                 // Make the frame visible
175                 this.frame.setVisible(true);
176
177                 // All done here
178                 this.updateStatus("done"); //NOI18N
179         }
180
181         /**
182          * Initalizes this frame. Having initComponents() exposed (publicly
183          * accessible) means that any other object can initialize components which
184          * you may not want.
185          *
186          * @throws
187          * org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException If
188          * this method has been called twice
189          */
190         @Override
191         public void init () throws FrameAlreadyInitializedException {
192                 // Debug line
193                 this.getLogger().trace("CALLED!"); //NOI18N
194
195                 // Has this frame been initialized?
196                 if (this.isInitialized()) {
197                         // Throw exception
198                         throw new FrameAlreadyInitializedException();
199                 }
200
201                 // Init components
202                 this.initComponents();
203
204                 // Set flag
205                 this.isInitialized = true;
206         }
207
208         /**
209          * Returns field isInitialized. This flag indicates whether this frame has
210          * been initialized or not.
211          *
212          * @return Field isInitialized
213          */
214         @Override
215         public final boolean isInitialized () {
216                 return this.isInitialized;
217         }
218
219         /**
220          * Shuts down the application.
221          */
222         @Override
223         public void shutdownApplication () {
224                 // To do this, the frame must be initialized
225                 if (!this.isInitialized()) {
226                         // Not initalized, so bad call
227                         this.getLogger().fatal("Bad call of shutdownApplication(). Please report this."); //NOI18N
228                         return;
229                 }
230                 this.getClient().getApplication().doShutdown();
231         }
232
233         /**
234          * Generates a title for borders
235          *
236          * @param key Key part to look for
237          * @return Human-readable title
238          */
239         private String generateBorderTitle (final String key) {
240                 // Call bundle instance
241                 return this.getBundle().getString(String.format("AddressbookFrame.border.%s.title.text", key)); //NOI18N
242         }
243
244         /**
245          * Generates a title for all frames based on given sub title key. If null is
246          * given, the sub title is not generated.
247          *
248          * @param subKey Key for sub title resource
249          * @return A full application title
250          */
251         private String generateFrameTitle (final String subKey) {
252                 // Base title
253                 String title = AddressbookApplication.printableTitle();
254
255                 // Is key given?
256                 if (subKey != null) {
257                         // Add sub title
258                         title = String.format("%s - %s", title, this.getBundle().getString(String.format("AddressbookFrame.%s.title.text", subKey))); //NOI18N
259                 }
260
261                 // Return it
262                 return title;
263         }
264
265         /**
266          * Initializes "add contact" dialog
267          */
268         private void initAddContactDialog () {
269                 // Instance dialog and set title
270                 this.addContact = new JDialog();
271                 this.addContact.setTitle(this.generateFrameTitle("dialog.addContact")); //NOI18N
272
273                 // Set layout
274                 this.addContact.setLayout(new GridLayout(0, 1, 2, 2));
275
276                 // Only hide it on close and make it appear in middle of screen
277                 this.addContact.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
278                 this.addContact.setLocationRelativeTo(null);
279
280                 // Set always on top and auto-focus
281                 this.addContact.setAlwaysOnTop(true);
282                 this.addContact.setAutoRequestFocus(true);
283
284                 // Initial dimension
285                 this.addContact.setSize(500, 500);
286
287                 /*
288                  * Add listener which asks for confirmation, if data has been entered
289                  * but not saved yet. The user may appriciate this ... ;-)
290                  *
291                  * @TODO Unfinished
292                  */
293                 // Init 3 panels:
294                 // 1) "name" panel
295                 initNameDataPanel();
296
297                 // 2) "address" panel
298                 initAddressDataPanel();
299
300                 // 3) "other" panel
301                 initOtherDataPanel();
302
303                 // x)Only for developing:
304                 /*
305                  * DEBUG:
306                  */ this.addContact.setVisible(true);
307         }
308
309         /**
310          * Initializes address panel
311          */
312         private void initAddressDataPanel () {
313                 // Panel "address" input boxes
314                 JPanel addressPanel = new JPanel();
315                 addressPanel.setLayout(new BoxLayout(addressPanel, BoxLayout.Y_AXIS));
316
317                 // Set border to titled version
318                 addressPanel.setBorder(new TitledBorder(this.generateBorderTitle("address"))); //NOI18N
319
320                 // Init all elements:
321                 // 1) Street and number together
322                 JPanel streetNumberPanel = new JPanel();
323                 streetNumberPanel.setLayout(new GridLayout(1, 4, 5, 5));
324
325                 // Label for street
326                 JLabel streetLabel = new JLabel(this.getBundle().getString("AddressbookFrame.street.text"));
327
328                 // Init text field with label
329                 JTextField street = new JTextField(20);
330                 street.setToolTipText(this.getBundle().getString("AddressbookFrame.street.tooltipText"));
331
332                 // Add both to street panel
333                 streetNumberPanel.add(streetLabel);
334                 streetNumberPanel.add(street);
335
336                 // Number label
337                 JLabel numberLabel = new JLabel(this.getBundle().getString("AddressbookFrame.number.text"));
338
339                 // And text field, but only accept numbers
340                 JTextField number = new JTextField(4);
341                 number.setToolTipText(this.getBundle().getString("AddressbookFrame.number.tooltipText"));
342
343                 // Add number verifier
344                 number.setInputVerifier(new InputVerifier() {
345
346                         /**
347                          * Method to verify that the entered data is a number.
348                          *
349                          * @param input Input to verify
350                          * @return Whether the data is a number
351                          */
352                         @Override
353                         public boolean verify (final JComponent input) {
354                                 // Cast on text field
355                                 JTextField text = (JTextField) input;
356
357                                 // Default is passed
358                                 boolean isValid = true;
359
360                                 // Try to convert input text to a number
361                                 try {
362                                         int num = Integer.valueOf(text.getText());
363                                 } catch (final NumberFormatException ex) {
364                                         // Didn't work
365                                         isValid = false;
366                                 }
367
368                                 // Return status
369                                 return isValid;
370                         }
371                 });
372
373                 // Add both to street panel
374                 streetNumberPanel.add(numberLabel);
375                 streetNumberPanel.add(number);
376
377                 // Add panel to address panel
378                 addressPanel.add(streetNumberPanel);
379
380                 // 2) ZIP code and ccity name
381                 JPanel zipCityPanel = new JPanel();
382                 zipCityPanel.setLayout(new GridLayout(1, 4, 5, 5));
383
384                 // Label for ZIP code, again numbers only
385                 JLabel zipLabel = new JLabel(this.getBundle().getString("AddressbookFrame.zip.text"));
386
387                 // Init text field with label
388                 JTextField zip = new JTextField(20);
389                 zip.setToolTipText(this.getBundle().getString("AddressbookFrame.zip.tooltipText"));
390
391                 // Add number verifier
392                 zip.setInputVerifier(new InputVerifier() {
393
394                         /**
395                          * Method to verify that the entered data is a number.
396                          *
397                          * @param input Input to verify
398                          * @return Whether the data is a number
399                          */
400                         @Override
401                         public boolean verify (final JComponent input) {
402                                 // Cast on text field
403                                 JTextField text = (JTextField) input;
404
405                                 // Default is passed
406                                 boolean isValid = true;
407
408                                 // Try to convert input text to a number
409                                 try {
410                                         int num = Integer.valueOf(text.getText());
411                                 } catch (final NumberFormatException ex) {
412                                         // Didn't work
413                                         isValid = false;
414                                 }
415
416                                 // Return status
417                                 return isValid;
418                         }
419                 });
420
421                 // Add both to street panel
422                 zipCityPanel.add(zipLabel);
423                 zipCityPanel.add(zip);
424
425                 // Label for street
426                 JLabel cityLabel = new JLabel(this.getBundle().getString("AddressbookFrame.city.text"));
427
428                 // Init text field with label
429                 JTextField city = new JTextField(20);
430                 city.setToolTipText(this.getBundle().getString("AddressbookFrame.city.tooltipText"));
431
432                 // Add both to street panel
433                 zipCityPanel.add(cityLabel);
434                 zipCityPanel.add(city);
435
436                 // Add panel to address panel
437                 addressPanel.add(zipCityPanel);
438
439                 // Add panel to dialog
440                 this.addContact.add(addressPanel);
441         }
442
443         /**
444          * Initialize components
445          */
446         private void initComponents () {
447                 // Debug line
448                 this.getLogger().trace("CALLED!"); //NOI18N
449
450                 // Set default close operation
451                 this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
452
453                 // Register shutdown listener
454                 this.frame.addWindowListener(new WindowAdapter() {
455                         /**
456                          * Invoked when a window has been closed.
457                          */
458                         @Override
459                         public void windowClosed (final WindowEvent e) {
460                                 // Shutdown application cleanly
461                                 self.shutdownApplication();
462                         }
463
464                         /**
465                          * Invoked when a window is in the process of being closed. The
466                          * close operation can be overridden at this point.
467                          */
468                         @Override
469                         public void windowClosing (final WindowEvent e) {
470                                 // Also shutdown cleanly here
471                                 self.shutdownApplication();
472                         }
473                 });
474
475                 // Setup layout manager
476                 this.frame.setLayout(new BorderLayout(2, 2));
477
478                 // Set window size
479                 this.frame.setSize(700, 400);
480
481                 // Center window in middle of screen, instead of top-left corner
482                 this.frame.setLocationRelativeTo(null);
483
484                 // Init menu system
485                 initMenuSystem();
486
487                 // Init table
488                 initTable();
489
490                 // Init status panel
491                 initStatusPanel();
492
493                 // Init other windows
494                 initOtherDialogs();
495         }
496
497         /**
498          * Initializes the menu system
499          */
500         private void initMenuSystem () {
501                 // Init menu bar, menu and item instances
502                 JMenuBar menuBar = new JMenuBar();
503                 JMenu menu;
504                 JMenuItem item;
505
506                 // Init some menus:
507                 // 1) File menu
508                 menu = new JMenu(this.getBundle().getString("AddressbookFrame.menu.file.text"));
509
510                 // Add menu items:
511                 // 1.x) Exit program (should be last)
512                 item = new JMenuItem(this.getBundle().getString("AddressbookFrame.menuItem.exitProgram.text"));
513                 item.setToolTipText(this.getBundle().getString("AddressbookFrame.menuItem.exitProgram.toolTipText"));
514
515                 // Add listener to exit menu
516                 item.addActionListener(new ActionListener() {
517                         /**
518                          * If the user has performed this action
519                          *
520                          * @param e An instance of an ActionEvent class
521                          */
522                         @Override
523                         public void actionPerformed (final ActionEvent e) {
524                                 self.shutdownApplication();
525                         }
526                 });
527
528                 // Add item -> menu
529                 menu.add(item);
530
531                 // Add menu -> menu bar
532                 menuBar.add(menu);
533
534                 // Init some menus:
535                 // 2) Addressbook menu
536                 menu = new JMenu(this.getBundle().getString("AddressbookFrame.menu.addressbook.text"));
537
538                 // 2.1) Add own data
539                 this.addOwnItem = new JMenuItem(this.getBundle().getString("AddressbookFrame.menuItem.addOwnData.text"));
540                 this.addOwnItem.setToolTipText(this.getBundle().getString("AddressbookFrame.menuItem.addOwnData.toolTipText"));
541
542                 // Add listener to exit menu
543                 this.addOwnItem.addActionListener(new ActionListener() {
544                         /**
545                          * If the user has performed this action
546                          *
547                          * @param e An instance of an ActionEvent class
548                          */
549                         @Override
550                         public void actionPerformed (final ActionEvent e) {
551                                 self.getClient().getContactManager().doEnterOwnData();
552                         }
553                 });
554
555                 // Add item -> menu
556                 menu.add(this.addOwnItem);
557
558                 // 2.2) Edit own data
559                 this.editOwnItem = new JMenuItem(this.getBundle().getString("AddressbookFrame.menuItem.editOwnData.text"));
560                 this.editOwnItem.setToolTipText(this.getBundle().getString("AddressbookFrame.menuItem.editOwnData.toolTipText"));
561
562                 // Add listener to exit menu
563                 this.editOwnItem.addActionListener(new ActionListener() {
564                         /**
565                          * If the user has performed this action
566                          *
567                          * @param e An instance of an ActionEvent class
568                          */
569                         @Override
570                         public void actionPerformed (final ActionEvent e) {
571                                 self.getClient().getContactManager().doChangeOwnData();
572                         }
573                 });
574
575                 // Add item -> menu
576                 menu.add(this.editOwnItem);
577
578                 // Add menu -> menu bar
579                 menuBar.add(menu);
580
581                 // Add menu bar -> frame
582                 this.frame.add(menuBar, BorderLayout.NORTH);
583         }
584
585         /**
586          * Initializes name panel
587          */
588         private void initNameDataPanel () {
589                 // Panel "name" input boxes
590                 JPanel namePanel = new JPanel();
591                 namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.Y_AXIS));
592
593                 // Set border to titled version
594                 namePanel.setBorder(new TitledBorder(this.generateBorderTitle("name"))); //NOI18N
595
596                 // Panel for gender
597                 JPanel gPanel = new JPanel();
598                 gPanel.setLayout(new GridLayout(1, 2, 5, 5));
599
600                 // Gender text field
601                 JLabel gLabel = new JLabel(this.getBundle().getString("AddressbookFrame.gender.text"));
602
603                 // Get all genders
604                 Gender[] genders = Gender.values();
605
606                 // Init gender combo box with tool tip
607                 JComboBox<Gender> gender = new JComboBox<>(new DefaultComboBoxModel<>(genders));
608                 gender.setToolTipText(this.getBundle().getString("AddressbookFrame.gender.tooltipText"));
609
610                 // Add both to gender panel
611                 gPanel.add(gLabel);
612                 gPanel.add(gender);
613
614                 // Add gender panel to "name" panel
615                 namePanel.add(gPanel);
616
617                 // Panel for surname
618                 JPanel sPanel = new JPanel();
619                 sPanel.setLayout(new GridLayout(1, 2, 5, 5));
620
621                 // New label for surname is not needed
622                 JLabel sLabel = new JLabel(this.getBundle().getString("AddressbookFrame.surname.text"));
623
624                 // And input box wih tool tip
625                 JTextField surname = new JTextField(20);
626                 surname.setToolTipText(this.getBundle().getString("AddressbookFrame.surname.tooltipText"));
627
628                 // Add both to surname panel
629                 sPanel.add(sLabel);
630                 sPanel.add(surname);
631
632                 // Add surname panel to "name" panel
633                 namePanel.add(sPanel);
634
635                 // Panel for surname
636                 JPanel fPanel = new JPanel();
637                 fPanel.setLayout(new GridLayout(1, 2));
638
639                 // New label for surname is not needed
640                 JLabel fLabel = new JLabel(this.getBundle().getString("AddressbookFrame.familyName.text"));
641
642                 // And input box wih tool tip
643                 JTextField familyName = new JTextField(20);
644                 familyName.setToolTipText(this.getBundle().getString("AddressbookFrame.familyName.tooltipText"));
645
646                 // Add both to surname panel
647                 fPanel.add(fLabel);
648                 fPanel.add(familyName);
649
650                 // Add family namepanel to "name" panel
651                 namePanel.add(fPanel);
652
653                 // Finally add panel to dialog
654                 this.addContact.add(namePanel);
655         }
656
657         /**
658          * Initializes "other" data panel
659          */
660         private void initOtherDataPanel () {
661         }
662
663         /**
664          * Initialize other dialogs (e.g. "Add contact")
665          */
666         private void initOtherDialogs () {
667                 // Init other windows:
668                 // 1) Add contact
669                 initAddContactDialog();
670         }
671
672         /**
673          * Initializes status panel
674          */
675         private void initStatusPanel () {
676                 // Init status label (which needs to be updated
677                 this.statusLabel = new JLabel();
678                 this.updateStatus("initializing"); //NOI18N
679
680                 // Init status bar in south
681                 JPanel panel = new JPanel();
682                 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
683                 panel.add(this.statusLabel);
684                 panel.setBorder(BorderFactory.createEtchedBorder());
685
686                 // Add panel to frame
687                 this.frame.add(panel, BorderLayout.SOUTH);
688         }
689
690         /**
691          * Initializes the table which will show all contacts
692          */
693         private void initTable () {
694                 // Instance table model
695                 this.dataModel = new ContactTableModel(this.getClient());
696
697                 // Instance table
698                 this.dataTable = new JTable(this.dataModel);
699
700                 // Add mouse listener
701                 this.dataTable.addMouseListener(new MouseAdapter() {
702                         /**
703                          * If the user peformed a click on a cell
704                          *
705                          * @param e Mouse event instance
706                          */
707                         @Override
708                         public void mouseClicked (final MouseEvent e) {
709                                 throw new UnsupportedOperationException("Unfinished."); //NOI18N
710                         }
711                 });
712
713                 // Instance scroll pane
714                 JScrollPane scroller = new JScrollPane();
715
716                 // Add table to scroll pane
717                 scroller.setViewportView(this.dataTable);
718                 scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
719                 scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
720
721                 // Add pane to frame
722                 this.frame.add(scroller, BorderLayout.CENTER);
723         }
724
725         /**
726          * Updates status to given type
727          *
728          * @param type Status type
729          */
730         private void updateStatus (final String type) {
731                 // Set status message
732                 this.statusLabel.setText(this.getBundle().getString(String.format("AddressbookFrame.statusLabel.%s.text", type))); //NOI18N
733         }
734 }