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