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