Warning: Can't use blame annotator:
svn blame failed on trunk/src/tmcsim/client/CADClient.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator/trunk/src/tmcsim/client/CADClient.java @ 525

Revision 525, 21.6 KB checked in by jdalbey, 6 years ago (diff)

CADClient.java implement #199 - add a splash screen.

RevLine 
1package tmcsim.client;
2
3import java.awt.BorderLayout;
4import java.awt.Color;
5import java.awt.Dialog;
6import java.awt.Font;
7import java.awt.GraphicsEnvironment;
8import java.awt.Point;
9import java.awt.event.WindowEvent;
10import java.awt.event.WindowListener;
11import java.io.FileInputStream;
12import java.io.FileOutputStream;
13import java.io.IOException;
14import java.rmi.Naming;
15import java.rmi.RemoteException;
16import java.rmi.server.UnicastRemoteObject;
17import java.util.Properties;
18import java.util.Vector;
19import java.util.logging.Level;
20import java.util.logging.Logger;
21import javax.swing.JDialog;
22
23import javax.swing.JFrame;
24import javax.swing.JLabel;
25import javax.swing.JOptionPane;
26import javax.swing.JWindow;
27import javax.swing.SwingConstants;
28import javax.swing.UIManager;
29
30import tmcsim.client.cadclientgui.CADClientGUI;
31import tmcsim.client.cadclientgui.CardfileReader;
32import tmcsim.client.cadclientgui.GUIScriptReader;
33import tmcsim.client.cadclientgui.data.CADData;
34import tmcsim.client.cadclientgui.screens.Login;
35import tmcsim.client.cadclientgui.screens.ScreenManager;
36import tmcsim.common.CADEnums;
37import tmcsim.common.SimulationException;
38import tmcsim.common.RevisionNumber;
39import tmcsim.interfaces.CADClientInterface;
40import tmcsim.interfaces.CoordinatorInterface;
41
42/**
43 * CADClient is the main class for the CAD Client application. The main method
44 * instantiates an instance of the CADClient object with the default properties
45 * file "..\config\CADClient.properties" or the first argument fom the command
46 * line invocation. Properties data values are used to bind socket communication
47 * between the CAD Client and the CAD Simulator. The CADClientModel object is
48 * instantiated and the CAD Client registers itself with the CAD Simulator.
49 * Finally, the CADClientView is initialized, the model-view and observer
50 * relationships are established, and the view is shown.<br>
51 * <br>
52 * The properties file contains the following data: <br>
53 * <code>
54 * -----------------------------------------------------------------------------<br>
55 * Host Name     The host name where the CAD Simulator is located.<br>
56 * Port Number   The port number that the CAD Simulator is bound on.<br>
57 * CAD Position  The integer (>= 0) position for this CAD Client.<br>
58 * CAD User ID   The unique user id for this CAD Client.<br>
59 * Error File    Filename of error logging file.<br>
60 * -----------------------------------------------------------------------------<br>
61 * Example File: <br>
62 * CADSimulatorHost       = localhost<br>
63 * CADSimulatorSocketPort = 4444<br>
64 * CADPosition = 1 <br>
65 * CADUserID   = A12345<br>
66 * ErrorFile   = cad_client_err.txt<br>
67 * </code>
68 *
69 * @author Matthew Cechini (mcechini@calpoly.edu)
70 * @version $Date: 2009/04/17 16:27:47 $ $Revision: 1.8 $
71 */
72
73public class CADClient extends UnicastRemoteObject implements
74        CADClientInterface {
75
76    /** Error logger. */
77    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
78
79    /**
80     * Enumeration containing properties name values. See CADClient class
81     * description for more information.
82     *
83     * @author Matthew Cechini
84     * @see CADClient
85     */
86    private static enum PROPERTIES {
87        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
88                "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
89                "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
90                "DisplayType");
91
92        public String name;
93
94        private PROPERTIES(String n) {
95            name = n;
96        }
97    }
98
99    /**
100     * CADClientSocket Object to handle socket communication between the Client
101     * and CAD Simulator.
102     */
103    private CADClientSocket theClientSocket;
104
105    /** Instance of the CADClientModel. */
106    private CADClientModel theClientScreenModel;
107
108    /** Instance of the CADClientView. */
109    private CADClientView theClientScreenView;
110
111    /**
112     * Instance of the CADCLientGUI Replaces CADClientView
113     */
114    private CADClientGUI theClientGUI;
115
116    /** Properties object for the CADClient class. */
117    private Properties cadClientProp;
118
119    /** RMI interface for communication with the remote Coordinator. */
120    private static CoordinatorInterface theCoorInt;
121
122    /** reference to itself to be used for disconnecting from CADSimulator */
123    private CADClientInterface client = this;
124
125    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
126   
127    /**
128     * Constructor. Initialize data from parsed properties file. Create a socket
129     * connection to the CADSimulator. The ClientScreenModel is initialized with
130     * the input and output I/O streams for socket communication. The
131     * ClientScreenModel registers with the CAD Simulator, using CAD position
132     * and userID read in from the properties file. The ClientScreenView is then
133     * created and initialized and set as an observer of the model.
134     *
135     * A thread is created with the runnable ClientScreenModel and is started.
136     * When this thread is no longer alive, or the ClientScrenView and
137     * CADClientSocket are closed. The program then exits.
138     *
139     * @param propertiesFile
140     *            File path (absolute or relative) to the properties file
141     *            containing configuration data.
142     */
143    public CADClient(String propertiesFile) throws SimulationException,
144            RemoteException {
145        if (!verifyProperties(propertiesFile))
146            System.exit(0);
147        // Display a splash screen. Ticket #199.
148        JDialog dlg = createSplashScreen();
149        dlg.setVisible(true);
150       
151        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
152                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());
153
154        // Instantiate the Socket and Model Objects.
155        theClientSocket = new CADClientSocket(cadClientProp.getProperty(
156                PROPERTIES.CAD_SIM_HOST.name).trim(),
157                Integer.parseInt(cadClientProp.getProperty(
158                        PROPERTIES.CAD_SIM_PORT.name).trim()));
159        theClientScreenModel = new CADClientModel();
160        theClientScreenModel.initializeScreen(theClientSocket.getInputStream(),
161                theClientSocket.getOutputStream());
162
163        // Register this CAD Client with the Simulation Manager
164        theClientScreenModel.register(Integer.parseInt(cadClientProp
165                .getProperty(PROPERTIES.CLIENT_CAD_POS.name)), cadClientProp
166                .getProperty(PROPERTIES.CLIENT_USER_ID.name));
167
168        // Instantiate the CADScreenView and set up the model-view observer
169        // relationship.
170        theClientScreenView = new CADClientView(theClientScreenModel);
171        theClientScreenView.setVisible(false);
172
173        // TODO: set up model-view relationship similar to ClientView and
174        // ScreenView
175        // Can repurpose the old model, but may be better to copy over and
176        // modify in parallel
177        // This is required to perform powerline commands on the data
178        theClientGUI = new CADClientGUI();
179
180        // Each screen of the UI should have a reference to either it's parent
181        // object or the main client
182        // This ensures they all have access to each other and the data model
183        theClientGUI.screen = new ScreenManager(theCoorInt);
184        theClientGUI.login = new Login();
185        theClientGUI.client = this;
186
187        // setup keyboard settings for CAD Client
188        if (cadClientProp.getProperty(PROPERTIES.KEYBOARD_TYPE.name).trim()
189                .equals("CAD")) {
190            CADEnums.CAD_KEYS.setupCADKeyboard();
191        }
192        // STD
193        else {
194            CADEnums.CAD_KEYS.setupStandardKeyboard();
195        }
196
197        theClientScreenModel.addObserver(theClientScreenView);
198
199        // Initialize the display
200        if (cadClientProp.getProperty(PROPERTIES.DISPLAY_TYPE.name).equals(
201                "FULL_SCREEN")) {
202
203            theClientScreenView.addWindowListener(new WindowListener() {
204                public void windowClosed(WindowEvent e) {
205                }
206
207                public void windowOpened(WindowEvent e) {
208                }
209
210                public void windowIconified(WindowEvent e) {
211                }
212
213                public void windowDeiconified(WindowEvent e) {
214                }
215
216                public void windowActivated(WindowEvent e) {
217                }
218
219                public void windowDeactivated(WindowEvent e) {
220                }
221
222                public void windowClosing(WindowEvent e) {
223
224                    try {
225                        theClientSocket.closeSocket();
226                    } catch (SimulationException se) {
227                    }
228
229                    System.exit(0);
230                }
231            });
232            // Remove the splash screen.
233            dlg.dispose();
234           
235            theClientScreenView.initWindow();
236            theClientScreenView.setVisible(false);
237        } else {
238            JFrame cadFrame = new JFrame("CAD Client");
239            cadFrame.add(theClientScreenView.initBox());
240            cadFrame.setSize(800, 600);
241
242            cadFrame.addWindowListener(new WindowListener() {
243                public void windowClosed(WindowEvent e) {
244                }
245
246                public void windowOpened(WindowEvent e) {
247                }
248
249                public void windowIconified(WindowEvent e) {
250                }
251
252                public void windowDeiconified(WindowEvent e) {
253                }
254
255                public void windowActivated(WindowEvent e) {
256                }
257
258                public void windowDeactivated(WindowEvent e) {
259                }
260
261                public void windowClosing(WindowEvent e) {
262
263                    try {
264                        theClientSocket.closeSocket();
265                    } catch (SimulationException se) {
266                    }
267
268                    System.exit(0);
269                }
270            });
271            cadFrame.setVisible(true);
272        }
273
274        // Create the CAD Client thread to run the CADClientModel Object.
275        Thread clientThread = new Thread(theClientScreenModel);
276       
277        // Log that everything started okay
278        clientThread.start();
279            cadClientLogger.logp(Level.INFO, "CAD Client",
280                    "Constructor",
281                    "Initialization complete.");
282
283        ensureProperShutdown();
284    }
285
286    /**
287     * Connect to the Coordinator's RMI object, and register this object for
288     * callback with the Coordinator.
289     *
290     * @param hostname
291     *            Host name of the CAD Simulator.
292     * @param portNumber
293     *            Port number of the CAD Simulator RMI communication.
294     * @throws SimulationException
295     *             if there is an error creating the RMI connection.
296     */
297    protected void connect(String hostname, String portNumber)
298            throws SimulationException {
299
300        String coorIntURL = "";
301
302        try {
303            coorIntURL = "rmi://" + hostname + ":" + portNumber
304                    + "/coordinator";
305            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
306            theCoorInt.registerForCallback(this);
307        } catch (Exception e) {
308            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,hostname,
309                    e);
310        }
311    }
312
313    /**
314     * This method verifies that the CAD Simulator Host and Port values are not
315     * null. Also, if a CAD Position or User ID do not exist in the properties
316     * file, the user is prompted to enter values. These values are written to
317     * the properties file. If the user cancels the process of entering these
318     * values, the verification fails.
319     *
320     * @param propertiesFile
321     *            File path (absolute or relative) to the properties file
322     *            containing configuration data.
323     * @return True if the properties file is valid, false if not.
324     * @throws SimulationException
325     *             if there is an exception in verifying the properties file, or
326     *             if the user cancels input.
327     */
328    private boolean verifyProperties(String propertiesFile)
329            throws SimulationException {
330
331        // Load the properties file.
332        try {
333            cadClientProp = new Properties();
334            cadClientProp.load(new FileInputStream(propertiesFile));
335        } catch (Exception e) {
336            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
337                    "Constructor", "Exception in reading properties file.", e);
338
339            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
340                    e);
341        }
342       
343
344        // Ensure that the properties file does not have null values for the
345        // CAD Simulator's connection information.
346        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
347                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null) {
348            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
349                    "Constructor", "Null value in properties file.");
350            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
351        }
352
353        try {
354            // If the properties file does not specify a CAD position, prompt
355            // the
356            // user to select one. If the user selects a position, write the
357            // new properties values to the file. If the user cancels, else
358            // throw an exception.
359            if (cadClientProp.getProperty(PROPERTIES.CLIENT_CAD_POS.name) == null) {
360                if (getCADPosition())
361                    cadClientProp.store(new FileOutputStream(propertiesFile),
362                            "");
363                else
364                    throw new SimulationException(
365                            SimulationException.INITIALIZE_ERROR);
366            }
367
368            // If the properties file does not specifiy a CAD User ID, prompt
369            // the
370            // user to enter a value. If the user enters a valid ID, write the
371            // new properties values to the file. If the user cancels, else
372            // throw an exception.
373            if (cadClientProp.getProperty(PROPERTIES.CLIENT_USER_ID.name) == null) {
374                if (getUserID())
375                    cadClientProp.store(new FileOutputStream(propertiesFile),
376                            "");
377                else
378                    throw new SimulationException(
379                            SimulationException.INITIALIZE_ERROR);
380            }
381        } catch (IOException ioe) {
382            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
383                    "Constructor",
384                    "Exception in writing to the properties file.");
385            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
386        }
387
388        // Ensure that the properties file has a valid display type
389        if (cadClientProp.getProperty(PROPERTIES.DISPLAY_TYPE.name) == null
390                || (!cadClientProp.getProperty(PROPERTIES.DISPLAY_TYPE.name)
391                        .equals("FULL_SCREEN") && !cadClientProp.getProperty(
392                        PROPERTIES.DISPLAY_TYPE.name).equals("FRAME"))) {
393            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
394                    "Constructor", "Invalid display type.");
395            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
396        }
397
398        return true;
399    }
400
401    /**
402     * This method prompts the user to select a value for the CAD position. If
403     * the user cancels the method returns false, else the Properties object is
404     * updated and true is returned.
405     *
406     * @return True if the user successfully selected a CAD position, false if
407     *         not.
408     */
409    private boolean getCADPosition() {
410
411        Vector<Integer> positions = new Vector<Integer>();
412        for (int i = 0; i < 10; i++)
413            positions.add(i);
414
415        Object cadPos = null;
416
417        while (true) {
418            cadPos = JOptionPane.showInputDialog(null,
419                    "Please assign this workstation a CAD position number.",
420                    "CAD Position Asignment", JOptionPane.QUESTION_MESSAGE,
421                    null, positions.toArray(), positions.get(0));
422
423            // If the user pressed cancel, confirm the exit and return false.
424            if (cadPos == null) {
425                if (JOptionPane
426                        .showConfirmDialog(
427                                null,
428                                "CAD Client cannot load until a valid CAD "
429                                        + "position has been selected.  Do you wish to "
430                                        + "cancel loading the CAD Client?",
431                                "Confirm Exit", JOptionPane.YES_NO_OPTION,
432                                JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
433                    return false;
434            }
435            // Else the user selected a CAD position, exit the loop.
436            else {
437                break;
438            }
439        }
440
441        cadClientProp.setProperty(PROPERTIES.CLIENT_CAD_POS.name,
442                cadPos.toString());
443        return true;
444    }
445
446    /**
447     * This method prompts the user to enter a 5-character User ID. If the user
448     * cancels the method returns false, else the Properties object is updated
449     * and true is returned.
450     *
451     * @return True if the user successfully selected a CAD position, false if
452     *         not.
453     */
454    private boolean getUserID() {
455        String cadUID = null;
456
457        while (true) {
458            cadUID = JOptionPane.showInputDialog(null,
459                    "Please assign this workstation a 6-character CAD "
460                            + "User ID.", "CAD User ID Asignment",
461                    JOptionPane.QUESTION_MESSAGE);
462
463            // /If the user pressed cancel, confirm the exit and return false.
464            if (cadUID == null) {
465                if (JOptionPane.showConfirmDialog(null,
466                        "CAD Client cannot load until a valid User ID "
467                                + "has been entered.  Do you wish to "
468                                + "cancel loading the CAD Client?",
469                        "Confirm Exit", JOptionPane.YES_NO_OPTION,
470                        JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
471                    return false;
472            }
473            // If the user does not enter a valid User ID, notify and reprompt.
474            else if (cadUID.length() != 6) {
475                JOptionPane.showMessageDialog(null,
476                        "The User ID must be 6 characters.", "Invalid User ID",
477                        JOptionPane.WARNING_MESSAGE);
478            }
479            // Else the user entered a valid value, exit the loop.
480            else {
481                break;
482            }
483        }
484
485        cadClientProp.setProperty(PROPERTIES.CLIENT_USER_ID.name, cadUID);
486        return true;
487    }
488
489    /**
490     * Construct the CADClient with the properties file path, either from the
491     * command line arguments or default.
492     *
493     * @param args
494     *            Command line arguments.
495     */
496    public static void main(String[] args) {
497        System.out.println("CAD Client " + RevisionNumber.getAppVersion());
498        if(System.getProperty("CONFIG_DIR") == null){
499                System.setProperty("CONFIG_DIR", "config");
500        }
501
502        try {
503            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
504            new CADClient(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
505         
506        } catch (Exception e) {
507            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
508                    "Error initializing application.");
509
510            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
511                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
512
513            System.exit(-1);
514        }
515
516    }
517   
518    /** Create a Splash Screen that displays a "loading" message.
519     *  Implements ticket #199
520     * @return a JDialog with a "loading" message.
521     */
522    private JDialog createSplashScreen()
523    {
524        final int dialogSize = 300;  // desired width and height of dialog
525        // create the dialog
526        JDialog dlg = new JDialog(null,"VisiCAD loading",Dialog.ModalityType.MODELESS);
527        // make the dialog background a color similar to the login screen background
528        dlg.getContentPane().setBackground(new Color(78, 162, 210));
529        // create the text message to be displayed
530        JLabel dlgMsg = new JLabel("Just a moment ...", SwingConstants.CENTER); 
531        // configure the font and color of the text message
532        dlgMsg.setFont(new Font("Arial", Font.PLAIN, 22));
533        dlgMsg.setForeground(Color.white);
534        // Add the msg to the center of the dialog
535        dlg.add(dlgMsg,BorderLayout.CENTER); 
536        // Set how big we want the dialog to be
537        dlg.setSize(dialogSize, dialogSize);
538        // Calculate where to place the dialog on the screen
539        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
540        Point centerPoint = ge.getCenterPoint();
541        int dx = centerPoint.x - dialogSize/2;
542        int dy = centerPoint.y - dialogSize/2;
543        dlg.setLocation(dx, dy);
544        // return the completely built dialog
545        return dlg;
546    }
547   
548    public void refresh() {
549        theClientGUI.screen.refreshScreens();
550    }
551
552    public void ensureProperShutdown() {
553        Runtime.getRuntime().addShutdownHook(new Thread() {
554            public void run() {
555                try {
556                    theCoorInt.unregisterForCallback(client);
557                } catch (RemoteException e) {
558                    cadClientLogger.logp(Level.WARNING, "CADClient.java", "Main",
559                    "Error unregistering in ensureProperShutdown().");
560                }
561            }
562        });
563    }
564
565}
Note: See TracBrowser for help on using the repository browser.