001    /** =====================================================================       
002    *
003    *  File Name : $Id: Main.java,v 1.10 2008/01/14 17:00:47 cb Exp $
004    *
005    *  Description
006    *  -----------
007    *
008    *  See javadoc comment 
009    * 
010    *  =====================================================================
011    *
012    *   @Author : Craige Bevil 
013    *             Control Software Group
014    *             Isaac Newton Group of Telescopes
015    *
016    *  =====================================================================
017    *
018    *     Modification Log
019    *
020    *     Vers         Date        Author       Reason
021    *     ----         ----        ------       ------
022    *      1                       C.Bevil      First Release
023    *
024    *     Commissioning Notes
025    *     -------------------
026    *
027    *     None
028    *     
029    *  =====================================================================
030    *
031    *     @Version   : $Id: Main.java,v 1.10 2008/01/14 17:00:47 cb Exp $
032    *
033    *     @Author    : $Author: cb $
034    *
035    *     Header     : $Header: /opt/INGsrc/src/CVS/softproj/FaultDatabase/src/FaultDatabase/FaultDatabase/src/GWTApplication/client/Main.java,v 1.10 2008/01/14 17:00:47 cb Exp $
036    *
037    *     Log        : $Log: Main.java,v $
038    *     Log        : Revision 1.10  2008/01/14 17:00:47  cb
039    *     Log        : Resize the root panel on window resize
040    *     Log        :
041    *     Log        : Revision 1.9  2007/12/12 15:24:50  cb
042    *     Log        : Added the quick help
043    *     Log        :
044    *     Log        : Revision 1.8  2007/10/22 11:40:11  cb
045    *     Log        : Used GWTEXT dialogs
046    *     Log        :
047    *     Log        : Revision 1.7  2007/10/08 09:32:50  cb
048    *     Log        : Modified to allow and review the user to change the faults which he is
049    *     Log        : subscribed to.
050    *     Log        :
051    *     Log        : Revision 1.6  2007/09/06 07:59:18  cb
052    *     Log        : Updated to support the concept of a single FaultUpdateMonitor
053    *     Log        : throughout the entire application so we do not hammer the database
054    *     Log        : when looking for updated faults.
055    *     Log        :
056    *     Log        : Revision 1.5  2007/08/17 14:26:42  cb
057    *     Log        : Updated for lastest prototype incorporating a lot of Nikos comments
058    *     Log        :
059    *     Log        : Revision 1.4  2007/08/01 13:00:05  cb
060    *     Log        : First prototype after import
061    *     Log        :
062    *     Log        : Revision 1.3  2007/07/25 16:10:34  cb
063    *     Log        : Added support for a URL parameter EditFault which will allow the user
064    *     Log        : to modify a fault straight away from an HTML page.
065    *     Log        :
066    *     Log        : Revision 1.2  2007/07/13 10:54:06  cb
067    *     Log        : Complete interface prototype
068    *     Log        :
069    *     Log        : Revision 1.1.1.1  2007/06/01 08:33:26  cb
070    *     Log        : Imported using TkCVS
071    *     Log        :
072    *
073    * =====================================================================*/
074    
075    
076    package GWTApplication.client;
077    
078    import com.google.gwt.core.client.EntryPoint;
079    import com.google.gwt.core.client.GWT;
080    import com.google.gwt.user.client.*;
081    import com.google.gwt.user.client.rpc.*;
082    import com.google.gwt.user.client.ui.*;
083    import com.google.gwt.i18n.client.*;
084    import com.google.gwt.user.client.ui.FlexTable.*;
085    import com.google.gwt.user.client.ui.HTMLTable.*;
086    
087    import org.gwtwidgets.client.util.*;
088    
089    import com.gwtext.client.core.EventObject;
090    import com.gwtext.client.util.Format;
091    import com.gwtext.client.widgets.MessageBox;
092    import com.gwtext.client.widgets.MessageBoxConfig;
093    
094    import java.util.*;
095    
096    /**
097     * This is the main entry point for the fault database application
098     * client. The code generates the user interface which will be
099     * translated to AJAX/java script which will be subsequently deployed
100     * into the web browsers.
101     *
102     * @author cb
103     * @version $Id: Main.java,v 1.10 2008/01/14 17:00:47 cb Exp $
104     */
105    
106    public class Main implements EntryPoint, FDBLoginListener, TabListener, WindowCloseListener, WindowResizeListener {
107    
108        /**
109         * Used to check the database intermittingly and report back to
110         * listeners which faults they are displaying have changed so that
111         * they may update their view accordingly. 
112         */
113        
114        private FaultUpdateMonitor faultUpdateMonitor = null;
115        
116        /**
117         * Indicator which will be used to show that we are busy 
118         */
119        
120        private BusyIndicator busyIndicator = new BusyIndicator();
121    
122        /**
123         * This class will be used for internationalization so that we can
124         * flick between the locales of English and Spanish.
125         */
126    
127        protected InternationalizationConstants internationalizationConstants = (InternationalizationConstants) GWT.create(InternationalizationConstants.class);
128    
129        /** 
130         * This is the service which will be used to access the servlet
131         * which is running in the tomcat container
132         */
133    
134        protected FaultServiceAsync svc;
135    
136        /**
137         * This is the main tab bar which will contain for each form in
138         * the Fault management system a tab which can be used to access
139         * that form
140         */
141        
142        private TabPanel MainTabBar;
143        
144        /**
145         * This is an instance of the quick view report object which will form one tab
146         */
147        
148        private QuickViewReport quickViewPanel;
149    
150        /**
151         * This is an instance of the managed system object which will
152         * allow the Privileged user to be able to administer the system.
153         */
154        
155        private ManageSystem manageSystemPanel;
156    
157        /**
158         * This is an instance of the new fault form object which will
159         * allow the user to enter a new fault into the system
160         */
161        
162        private NewFaultForm createNewFaultPanel;
163    
164        /**
165         * This is an instance of the search form object which will allow
166         * the user to perform a search across the data contained within
167         * the fault management system
168         */
169        
170        private SearchForm searchPanel;
171    
172        /**
173         * This is an instance of the Modify fault object which will allow
174         * the user to Update and append to an existing fault in the
175         * system.
176         */
177        
178        private ModifyFormPanel modifyFormPanel;
179    
180        /**
181         * This is the login panel which the user will be greeted with he
182         * first logs onto the system
183         */
184        
185        private LoginPanel loginPanel;
186        
187        /**
188         * Contains the details of the authentication which was performed
189         * by the user. 
190         */
191        
192        private AuthenticationDetails UserAuthentication;
193        
194        /**
195         * This class is a listener class which is called when the user
196         * clicks upon the help link in the main panel and is used to
197         * display quick help associated with the application
198         * @author Craige Bevil 
199         */
200        
201        class QuickHelpListener implements ClickListener {
202                        
203            /**
204             * This is called when the user clicks on the hyperlink
205             * associated with the help link on the main page and results
206             * in the quick help dialog window being displayed.
207             * @param sender This is the widget that raised this event. 
208             */
209        
210            public void onClick (final Widget sender) {
211                
212                QuickHelpDialog quickHelpDialog = new QuickHelpDialog("quickHelp_" + internationalizationConstants.locale() + ".html");
213                            
214                quickHelpDialog.showHelpDialog();
215            }
216        }
217    
218        /**
219         * Called before a tab is selected. We prevent the user selecting
220         * the update tab when there are no faults being edited. 
221         * @param sender The tab panel which sent the event 
222         * @param tabIndex This is the index of the panel which was
223         * selected. 
224         * @return boolean false if the user is to be blocked from
225         * selecting the tab selected. 
226         */
227        
228        public boolean onBeforeTabSelected(final SourcesTabEvents sender, final int tabIndex) {
229            
230            // If the user is using the system as user guest then we do
231            // not mind if he selects tab 0 as the update fault tab does
232            // not exist. 
233            
234            if (UserAuthentication.UserId.equalsIgnoreCase(FaultDatabaseConstants.GUEST)) {
235                return true;
236            }
237    
238            if (tabIndex == 0 && modifyFormPanel.getNumberOfFaultsBeingEdited() == 0) {
239                MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.noFaultsBeingEdited());
240                return false;
241            }
242            
243            return true;
244        }
245    
246        /**
247         * Called when the user is about to close down the window, we need
248         * to make sure that he really does want to leave the page. This
249         * is to save the user unwillingly losing unsaved changes.
250         */
251        
252        public String onWindowClosing() {
253            return internationalizationConstants.youMayLoseUnsavedChanges();
254        }
255    
256        /**
257         * Called when the user closes down the window. We don't do
258         * anything here. This method does nothing and is simply to
259         * satisfy the interface requirements. 
260         */
261        
262        public void onWindowClosed() {
263        }
264        
265        /**
266         * Called when the tab has been selected but we do nothing 
267         * @param sender The tab panel which sent the event 
268         * @param tabIndex This is the index of the panel which was
269         * selected. 
270         */
271        
272        public void onTabSelected (final SourcesTabEvents sender, final int tabIndex) {
273        }
274    
275        /**
276         * This implements the expected interface of the login listener
277         * which will be called when the user logs onto the system for the
278         * first time. The main interface of the application will be built
279         * through this method.
280         *
281         * @param UserAuthentication Contains the details of the user that
282         * has logged onto the system and his levels of priviledge
283         */
284        
285        public void userLoggedIn (final AuthenticationDetails UserAuthentication) {
286    
287            Hyperlink changePasswordLink = null;
288    
289            Hyperlink updateFaultSubscriptionLink = null;
290    
291            Hyperlink quickHelpLink = null;
292    
293            busyIndicator.showBusy(true);
294    
295            this.UserAuthentication = UserAuthentication;
296            
297            // Now add a listener in case the user tries to navigate away
298            // from the page without saving his changes 
299    
300            Window.addWindowCloseListener(this);
301            
302            // Now we need to remove the panel which contains the login
303            // panel and replace it with the tab bar which the user will
304            // use to interact with the system. Which panels will be
305            // displayed depends on the level of priviledge that he has
306            
307            RootPanel.get().remove(loginPanel);
308    
309            // Now create the main interface that the user is going to use
310            // to interact with the system
311            
312            MainTabBar = new TabPanel();
313    
314            // We add a listener to make sure that the user does not
315            // select tabs when he should not (i.e. in the case of
316            // selecting the update tab when there are not faults to be
317            // edited. 
318            
319            MainTabBar.addTabListener(this);        
320    
321            // Now create the various tabs which will be used by the
322            // system
323            
324            // If the user has ING user priviledge then he will able to
325            // modify faults in the system
326    
327            for (int i=0; i < UserAuthentication.PriviledgeLevels.size();i++) { 
328                
329                // Only if the user has logged onto the system using his
330                // user name can he modify faults
331    
332                if (((String)UserAuthentication.PriviledgeLevels.get(i)).equalsIgnoreCase(FaultDatabaseConstants.INGUSERPRIVILEDGE)) {
333    
334                    // Allow the user to change faults 
335    
336                    modifyFormPanel = new ModifyFormPanel(MainTabBar,svc,UserAuthentication);
337    
338                    // Allow the user to change his password 
339                    
340                    changePasswordLink = new Hyperlink(internationalizationConstants.changePassword(),"ChangePassword");
341    
342                    ChangePasswordListener changePasswordListener = new ChangePasswordListener(UserAuthentication);
343                
344                    changePasswordLink.addClickListener(changePasswordListener);
345                    
346                    // Allow the user to edit his list of subscribed faults 
347    
348                    updateFaultSubscriptionLink = new Hyperlink(internationalizationConstants.updateFaultSubscription(),"UpdateSubscriptionList");
349                    
350                    UpdateFaultSubscriptionListener updateFaultSubscriptionListener = new UpdateFaultSubscriptionListener(UserAuthentication);
351                    
352                    updateFaultSubscriptionLink.addClickListener(updateFaultSubscriptionListener);
353                    
354                }
355            }
356    
357            // Register a monitor on the faults which will be used for
358            // checking the database to see if it has been updated with
359            // new or modified faults.
360            
361            faultUpdateMonitor = new FaultUpdateMonitor(svc);
362            
363            // Schedule the updater to check for new faults every 10
364            // seconds as this query can be done really quickly by the
365            // server
366            
367            faultUpdateMonitor.scheduleRepeating(7500);
368    
369            // Create the quick view search panel 
370    
371            quickViewPanel = new QuickViewReport(MainTabBar,svc,modifyFormPanel,UserAuthentication,faultUpdateMonitor);     
372    
373            // If the user has admin priviledges then let him modify the
374            // administration data
375            
376            for (int i=0; i < UserAuthentication.PriviledgeLevels.size();i++) { 
377             
378                if (((String)UserAuthentication.PriviledgeLevels.get(i)).equalsIgnoreCase(FaultDatabaseConstants.ADMINPRIVILEDGE)) {
379                    manageSystemPanel = new ManageSystem(MainTabBar,svc,UserAuthentication);
380                }
381            }
382            
383            // Now create the form in which the use will enter the details of the new fault 
384            
385            createNewFaultPanel = new NewFaultForm(MainTabBar,svc,UserAuthentication);
386    
387            // Create the form in which the user will enter the details of the search 
388            
389            searchPanel = new SearchForm(MainTabBar,svc,UserAuthentication,modifyFormPanel,faultUpdateMonitor);
390            
391            MainTabBar.selectTab(1);
392    
393            // Now add the name of the user which has logged onto the
394            // system at the top of the window and if applicable, add a
395            // link which will allow the user to change his password
396            
397            final FlexTable headerTable = new FlexTable();
398            final RowFormatter tableRowFormatter = (RowFormatter)headerTable.getRowFormatter();      
399    
400            if (UserAuthentication.Surname.equals(FaultDatabaseConstants.GUEST)) {
401                headerTable.setText(0,0,internationalizationConstants.user() + " : " + internationalizationConstants.guest() + " | ");
402            } else {
403                headerTable.setText(0,0,internationalizationConstants.user() + " : " + UserAuthentication.Name + " " + UserAuthentication.Surname + " | ");
404            }
405            
406            // Now add the link which will allow the user to log out of the system
407            
408            headerTable.setHTML(0,1,"<a href=\"Main.html\">" + internationalizationConstants.signOut() + "</a> | ");
409    
410            // Now add a link which will allow the user to get quick help
411            // on the system
412            
413            quickHelpLink = new Hyperlink(internationalizationConstants.help(),"Help");
414            
415            QuickHelpListener quickHelpLinkListener = new QuickHelpListener();
416            
417            quickHelpLink.addClickListener(quickHelpLinkListener);
418    
419            headerTable.setWidget(0,3,quickHelpLink);                   
420            headerTable.setHTML(0,4,"|");
421                    
422            // If the user is logged in as anybody other than guest then
423            // we allow him to change his password
424    
425            if (changePasswordLink != null) {
426                headerTable.setWidget(0,5,changePasswordLink);
427            }
428            
429            // If the user has logged in as himself then we give him the
430            // chance to update to update the list of faults which he is subscribed to 
431            
432            if (updateFaultSubscriptionLink != null) {
433                headerTable.setHTML(0,6,"|");                   
434                        
435                headerTable.setWidget(0,7,updateFaultSubscriptionLink);                 
436            }
437    
438            headerTable.setStyleName("HeaderStyle");
439    
440    
441            tableRowFormatter.setStyleName(0,"headerBox");
442    
443            // Now add the main tab bar to the root panel of the browser window
444    
445            RootPanel.get().add(headerTable);
446            RootPanel.get().add(MainTabBar);
447            
448            MainTabBar.setWidth("98%");
449            MainTabBar.setHeight("100%");           
450            
451            // Find out if in the URL for the page include a URL parameter
452            // FaultID which indicates a fault to be updated. If so we
453            // initialise the update form panel with a tab which contains
454            // the fault to be edited if the user has the adequate
455            // priviledge to update the fault.
456            
457            final String temp = WindowUtils.getLocation().getParameter("EditFault");
458            
459            if (temp != null) {
460    
461                // Ensure that the fault id is actually an integer
462                
463                int faultId = -1;
464    
465                boolean validFaultIdFound = false;
466    
467                try {
468                    faultId = Integer.parseInt(temp);
469                    validFaultIdFound = true;
470                } catch (NumberFormatException e) {
471                    MessageBox.alert(internationalizationConstants.information(),"Unable to edit fault as fault number specified " + temp + " is invalid");
472                }
473                
474                boolean userAuthorised = false;
475    
476                // We have to do this as we can only use variables
477                // declared as final in the innner class
478    
479                final int faultNumber = faultId;
480                
481                if (validFaultIdFound) {
482    
483                    for (int i=0; i < UserAuthentication.PriviledgeLevels.size();i++) { 
484                        
485                        // Only if the user has logged onto the system
486                        // using his user name can he modify faults
487                        
488                        if (((String)UserAuthentication.PriviledgeLevels.get(i)).equalsIgnoreCase(FaultDatabaseConstants.INGUSERPRIVILEDGE)) {
489    
490                            userAuthorised = true;
491    
492                            // Now we need to establish if the fault that
493                            // has been specified exists and if it does
494                            // then we can build the tab which will be
495                            // used to hold the fault 
496    
497                            svc.faultExists(faultNumber,true,new AsyncCallback() {
498                                    
499                                    // If the fault does exist in the
500                                    // database then we can allow the user
501                                    // to edit it 
502    
503                                    public void onSuccess (final Object result) {
504                                        
505                                        if (((Boolean)result).booleanValue()) {
506                                            modifyFormPanel.addNewFaultTab(faultNumber);
507    
508                                            // Select the update tab panel so that the user
509                                            // can edit it straight away
510                                            
511                                            MainTabBar.selectTab(0);
512    
513                                        } else {
514                                            MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.unableToFindFaultInDatabase(faultNumber));
515                                        }
516                                    }
517                                    
518                                    public void onFailure (Throwable ex)
519                                    {
520                                        MessageBox.alert(internationalizationConstants.information(),"Unable to edit fault " + faultNumber);
521                                    }
522                                });
523                            
524                            break;
525                        }                               
526                    }
527                    
528                    if (!userAuthorised) {
529                        MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.userDoesNotSufficientPriviledge());
530                    }
531                }
532            }
533            
534            busyIndicator.showBusy(false);
535                    
536        }
537    
538        /**
539         * Called when the main window is resized 
540         */
541        
542        public void onWindowResized (int width, int height) {
543    
544            final RootPanel rootPanel = RootPanel.get();
545            
546            rootPanel.setSize(Math.max(width - rootPanel.getAbsoluteLeft(), 0) + "px",Math.max(height - rootPanel.getAbsoluteTop(), 0) + "px");             
547        }
548         
549        /**
550         *  This is the entry point of the client side of the system. This
551         *  is the method which is called by the web browser when it is
552         *  loaded for the first and boots the system.
553         */
554    
555        public void onModuleLoad() {
556    
557            // Now test out the object which will be used to communicate
558            // with the servlet on the tomcat server
559            
560            final FaultServiceAsync svc = (FaultServiceAsync) GWT.create(FaultService.class);
561            final ServiceDefTarget endPoint = (ServiceDefTarget) svc;
562    
563            endPoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "/faultService");
564    
565            // Now create a login screen which will be used by the user to
566            // enter the his login credentials for the system. After he
567            // has entered his user credentials, the user will then be
568            // exposed to the rest of the system 
569            
570            this.svc = svc;
571            
572            loginPanel = new LoginPanel(svc,this);
573            
574            final RootPanel rootPanel = RootPanel.get();
575            
576            rootPanel.add(loginPanel);
577            rootPanel.setWidth("100%");
578    
579            Window.setTitle("ING Fault Management System"); 
580            Window.setMargin("2px");
581    
582            Window.addWindowResizeListener(this);
583    
584        }
585    }
586