001 /** =====================================================================
002 *
003 * File Name : $Id: SearchForm.java,v 1.22 2008/01/15 11:08:15 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: SearchForm.java,v 1.22 2008/01/15 11:08:15 cb Exp $
032 *
033 * @Author : $Author: cb $
034 *
035 * Header : $Header: /opt/INGsrc/src/CVS/softproj/FaultDatabase/src/FaultDatabase/FaultDatabase/src/GWTApplication/client/SearchForm.java,v 1.22 2008/01/15 11:08:15 cb Exp $
036 *
037 * Log : $Log: SearchForm.java,v $
038 * Log : Revision 1.22 2008/01/15 11:08:15 cb
039 * Log : Ran through PMD and sorted out the javadoc so that we could export the
040 * Log : javadoc to the javadoc repository.
041 * Log :
042 * Log : Revision 1.21 2007/12/12 15:26:10 cb
043 * Log : Added new javascript library which allows fancy message boxes to be
044 * Log : displayed.
045 * Log :
046 * Log : Revision 1.20 2007/09/26 08:40:31 cb
047 * Log : Fixed an incorrect error message when the date occured field was not
048 * Log : filled in correct.
049 * Log :
050 * Log : Revision 1.19 2007/09/25 10:22:04 cb
051 * Log : Updated so that the advanced search will not allow the user to enter
052 * Log : an empty search clause
053 * Log :
054 * Log : Revision 1.18 2007/09/25 09:09:42 cb
055 * Log : Fixed the simple search processing to ensure that the user has entered
056 * Log : at least one search term.
057 * Log :
058 * Log : Revision 1.17 2007/09/06 07:59:18 cb
059 * Log : Updated to support the concept of a single FaultUpdateMonitor
060 * Log : throughout the entire application so we do not hammer the database
061 * Log : when looking for updated faults.
062 * Log :
063 * Log : Revision 1.16 2007/09/04 14:10:02 cb
064 * Log : Removed the check on the number date fields which have been
065 * Log : completed. now it is not mandatory that the user completes both date
066 * Log : fields.
067 * Log :
068 * Log : Revision 1.15 2007/08/23 15:41:09 cb
069 * Log : Ordered the fields in the advanced search
070 * Log :
071 * Log : Revision 1.14 2007/08/22 15:58:50 cb
072 * Log : After PMD session
073 * Log :
074 * Log : Revision 1.13 2007/08/22 12:54:10 cb
075 * Log : Added a reset button to the advanced search page
076 * Log :
077 * Log : Revision 1.12 2007/08/21 09:21:27 cb
078 * Log : Modified so that the user can specify either the start or the end date
079 * Log : in the advanced search
080 * Log :
081 * Log : Revision 1.11 2007/08/21 09:05:29 cb
082 * Log : Fixed problem parsing the defect number and the time lost
083 * Log :
084 * Log : Revision 1.10 2007/08/20 11:01:59 cb
085 * Log : Added an option which allow the usr to specify an boolean OR on the
086 * Log : search terms in the keywords
087 * Log :
088 * Log : Revision 1.9 2007/08/17 14:26:41 cb
089 * Log : Updated for lastest prototype incorporating a lot of Nikos comments
090 * Log :
091 * Log : Revision 1.8 2007/08/16 13:29:29 cb
092 * Log : Changed the priority field into a text field into which the user can
093 * Log : put <> characters
094 * Log :
095 * Log : Revision 1.7 2007/08/16 12:43:50 cb
096 * Log : Added start & end date to advanced search. Cleared out results box
097 * Log : before search
098 * Log :
099 * Log : Revision 1.6 2007/08/02 12:22:54 cb
100 * Log : Modified to support the extra tabs in the quick view tab panel to
101 * Log : include the different groups of outstanding faults.
102 * Log :
103 * Log : Revision 1.5 2007/08/01 13:00:04 cb
104 * Log : First prototype after import
105 * Log :
106 * Log : Revision 1.4 2007/07/24 08:30:17 cb
107 * Log : Modified to take into account the changes which have been made to the SearchResultFormatter
108 * Log :
109 * Log : Revision 1.3 2007/07/19 08:20:40 cb
110 * Log : Added a handler so that the user can press the <return> key to start
111 * Log : the search. Factored out the code which checks the input parameters
112 * Log : for the simple search to new method.
113 * Log :
114 * Log : Revision 1.2 2007/07/13 10:54:04 cb
115 * Log : Complete interface prototype
116 * Log :
117 * Log : Revision 1.1.1.1 2007/06/01 08:33:26 cb
118 * Log : Imported using TkCVS
119 * Log :
120 *
121 * =====================================================================*/
122
123 package GWTApplication.client;
124
125 import com.google.gwt.core.client.GWT;
126 import com.google.gwt.user.client.*;
127 import com.google.gwt.user.client.rpc.*;
128 import com.google.gwt.user.client.ui.*;
129 import com.google.gwt.user.client.ui.FlexTable.*;
130
131 import com.gwtext.client.core.EventObject;
132 import com.gwtext.client.util.Format;
133 import com.gwtext.client.widgets.MessageBox;
134 import com.gwtext.client.widgets.MessageBoxConfig;
135
136 import java.util.*;
137
138 /**
139 * This class will be used to build a form which may subsequently be
140 * used to search through the fault management system. There are two
141 * searches associated with this form. The first is a simple search
142 * which allows the user to enter and a start and end date. The second is an
143 * advanced search which allows the user much finer control over the
144 * search parameters. The results of the search will be displayed in
145 * the search view.
146 * @author Craige Bevil
147 * @version $Id: SearchForm.java,v 1.22 2008/01/15 11:08:15 cb Exp $
148 */
149
150 public class SearchForm extends FaultDBForm implements ClickListener, KeyboardListener {
151
152 /**
153 * Used to check the database intermittingly and report back to
154 * listeners which faults they are displaying have changed so that
155 * they may update their view accordingly.
156 */
157
158 private FaultUpdateMonitor faultUpdateMonitor = null;
159
160 /**
161 * Used for indicating the state of chcek boxes which are included
162 * in the interface
163 */
164
165 public final static String CHECKED = "CHECKED";
166
167 /**
168 * Used for indicating the state of chcek boxes which are included
169 * in the interface
170 */
171
172 public final static String NOTCHECKED = "NOTCHECKED";
173
174 /**
175 * A constant which will be used to index the search data
176 * structure and will be used across the client and the server
177 */
178
179 public final static String KEYWORDS = "Keywords";
180
181 /**
182 * A constant which will be used to index the search data
183 * structure and will be used across the client and the server
184 */
185
186 public final static String DATEOCCURED = "TimeOccured";
187
188 /**
189 * A constant which will be used to index the search data
190 * structure and will be used across the client and the server
191 */
192
193 public final static String TIMELOST = "TimeLost";
194
195 /**
196 * A constant which will be used to index the search data
197 * structure and will be used across the client and the server
198 */
199
200 public final static String OBSERVER = "Observer";
201
202 /**
203 * A constant which will be used to index the search data
204 * structure and will be used across the client and the server
205 */
206
207 public final static String DEFECTNUMBER = "DefectNumber";
208
209 /**
210 * A constant which will be used to index the search data
211 * structure and will be used across the client and the server
212 */
213
214 public final static String SEVERITY = "Severity";
215
216 /**
217 * A constant which will be used to index the search data
218 * structure and will be used across the client and the server
219 */
220
221 public final static String INSTRUMENT = "Instrument";
222
223 /**
224 * A constant which will be used to index the search data
225 * structure and will be used across the client and the server
226 */
227
228 public final static String SITE = "Site";
229
230 /**
231 * A constant which will be used to index the search data
232 * structure and will be used across the client and the server
233 */
234
235 public final static String SYSTEM = "System";
236
237 /**
238 * A constant which will be used to index the search data
239 * structure and will be used across the client and the server
240 */
241
242 public final static String ORIGINATOR = "Originator";
243
244 /**
245 * The fault number of the fault
246 */
247
248 public final static String FAULTNUMBER = "FaultNumber";
249
250 /**
251 * A constant which will be used to index the search data
252 * structure and will be used across the client and the server
253 */
254
255 public final static String TO = "TelescopeOperator";
256
257 /**
258 * A constant which will be used to index the search data
259 * structure and will be used across the client and the server
260 */
261
262 public final static String DUTYENGINEER = "DutyEngineer";
263
264 /**
265 * A constant which will be used to index the search data
266 * structure and will be used across the client and the server
267 */
268
269 public final static String SA = "SupportAstronomer";
270
271 /**
272 * A constant which will be used to index the search data
273 * structure and will be used across the client and the server
274 */
275
276 public final static String PRIORITY = "Priority";
277
278 /**
279 * A constant which will be used to index the search data
280 * structure and will be used across the client and the server
281 */
282
283 public final static String ASSIGNEDTO = "AssignedTo";
284
285 /**
286 * A constant which will be used to index the search data
287 * structure and will be used across the client and the server
288 */
289
290 public final static String FAULTTYPE = "FaultType";
291
292 /**
293 * A constant which will be used to index the search data
294 * structure and will be used across the client and the server
295 */
296
297 public final static String STATUSTYPE = "StatusType";
298
299 /**
300 * A constant which will be used to index the search data
301 * structure and will be used across the client and the server
302 */
303
304 public final static String SUBMIT = "Submit";
305
306 /**
307 * A constant which will be used to index the search data
308 * structure and will be used across the client and the server
309 */
310
311 public final static String STARTDATE = "STARTDATE";
312
313 /**
314 * A constant which will be used to index the search data
315 * structure and will be used across the client and the server
316 */
317
318 public final static String ENDDATE = "ENDDATE";
319
320 /**
321 * A constant which will be used to index the search data
322 * structure and will be used across the client and the server
323 */
324
325 public final static String RESET = "RESET";
326
327 /**
328 * This is used by the user to indicate that he wants an boolean
329 * and applied to the terms in the search query for the advanced
330 * search
331 */
332
333 public final static String USEAND = "USEAND";
334
335 /**
336 * Used to indicate that we should use OR as the conjungating
337 * operator in the advanced search query
338 */
339
340 public final static String USEOR = "USEOR";
341
342 /**
343 * Used to indicate that we should use OR as the conjungating
344 * operator in the keywords of the search
345 */
346
347 public final static String USEORKEYWORDS = "USEORKEYWORDS";
348
349 /**
350 * This is the main tab panel for the application
351 */
352
353 final private TabPanel MainTabPanel;
354
355 /**
356 * A constant used to index the SearchFormatters hash map
357 */
358
359 private static final String ADVANCED = "ADVANCED";
360
361 /**
362 * A constant used to index the SearchFormatters hash map
363 */
364
365 private static final String SIMPLE = "SIMPLE";
366
367 /**
368 * This is the object which will be used to allow the user to
369 * modify faults should he be entitled to
370 */
371
372 final private ModifyFormPanel ModifyFormPage;
373
374 /**
375 * This hash map will contain the formatters which will be used
376 * for creating the search result table.
377 */
378
379 final private HashMap SearchFormatters = new HashMap();
380
381 /**
382 * This class will be used for internationalization so that we can
383 * flick between the locales of English and Spanish.
384 */
385
386 InternationalizationConstants internationalizationConstants = (InternationalizationConstants) GWT.create(InternationalizationConstants.class);
387
388 /**
389 * A static which is used to indicate that a widget is a text box
390 */
391
392 final static int TEXTBOX = 0;
393
394 /**
395 * A static which is used to indicate that a widget is a list box
396 */
397
398 final static int LISTBOX = 1;
399
400 /**
401 * A static which is used to indicate that a widget is a button
402 */
403
404 final static int BUTTON = 2;
405
406 /**
407 * A static which is used to indicate that a widget is a checkbox
408 */
409
410 final static int CHECKBOX = 3;
411
412 /**
413 * A static to indicate that the widget should occupy the full
414 * width of the table into which it is positioned.
415 */
416
417 final static int FULLWIDTH = -1;
418
419 /**
420 * This is the tabbed panel which contains two panels. One
421 * represents the advanced search and the other represents the
422 * simple search.
423 */
424
425 final TabPanel SearchTabPanel = new TabPanel();
426
427 /**
428 * This is a hashtable which will be used to index the fields in
429 * the simple search
430 * @gwt.typeArgs <GWTApplication.client.SearchForm.InputField>
431 */
432
433 final HashMap SimpleSearchFieldsHash = new HashMap();
434
435 /**
436 * This is a hashtable which will be used to index the fields in
437 * the advanced search
438 * @gwt.typeArgs <GWTApplication.client.SearchForm.InputField>
439 */
440
441 final HashMap AdvancedSearchFieldsHash = new HashMap();
442
443 /**
444 * This is an inner class which is used to represent a field
445 * within the search form
446 */
447
448 class InputField {
449
450 public String Index;
451 public int Type;
452 public String Title = "Unknown";
453 public int Width = 1;
454 public boolean HasOptionalVisibilityInSearchQuery = true;
455
456 public Widget ControlWidget;
457
458 public CheckBox VisibleInResultCheckBox;
459
460 InputField (final String Index,final int Type, final String Title,final int Width,final boolean HasOptionalVisibilityInSearchQuery) {
461 this.Index = Index;
462 this.Type = Type;
463 this.Title = Title;
464 this.Width = Width;
465 this.HasOptionalVisibilityInSearchQuery = HasOptionalVisibilityInSearchQuery;
466 }
467
468 void setControlWidget (final Widget ControlWidget) {
469 this.ControlWidget = ControlWidget;
470 }
471
472 Widget getControlWidget () {
473 return ControlWidget;
474 }
475
476 }
477
478 /**
479 * The generation of the search form is data-driven and this is
480 * done through the use of the following array
481 */
482
483 final InputField[] AdvancedSearchInputFieldData = new InputField[] {
484 new InputField(KEYWORDS, TEXTBOX,internationalizationConstants.keywords(),FULLWIDTH,false),
485
486 new InputField(STARTDATE,TEXTBOX,internationalizationConstants.startDate(),1,true),
487 new InputField(DATEOCCURED,TEXTBOX,internationalizationConstants.dateOccured(),1,true),
488 new InputField(DEFECTNUMBER,TEXTBOX,internationalizationConstants.defectNumber(),1,true),
489
490 new InputField(ENDDATE,TEXTBOX,internationalizationConstants.endDate(),1,true),
491 new InputField(PRIORITY,TEXTBOX,internationalizationConstants.priority(),1,true),
492 new InputField(TIMELOST,TEXTBOX,internationalizationConstants.timeLost(),1,true),
493
494 new InputField(INSTRUMENT,LISTBOX,internationalizationConstants.instrument(),1,true),
495 new InputField(SEVERITY,LISTBOX,internationalizationConstants.severity(),1,true),
496 new InputField(SITE,LISTBOX,internationalizationConstants.site(),1,true),
497
498 new InputField(FAULTTYPE,LISTBOX,internationalizationConstants.faultType(),1,true),
499 new InputField(STATUSTYPE,LISTBOX,internationalizationConstants.status(),1,true),
500 new InputField(SYSTEM,LISTBOX,internationalizationConstants.system(),1,true),
501
502 new InputField(ASSIGNEDTO,LISTBOX,internationalizationConstants.assignedTo(),1,true),
503 new InputField(DUTYENGINEER,LISTBOX,internationalizationConstants.dutyTechnician(),1,true),
504 new InputField(ORIGINATOR,LISTBOX,internationalizationConstants.enteredBy(),1,true),
505
506 new InputField(SA,LISTBOX,internationalizationConstants.supportAstronomer(),1,true),
507 new InputField(OBSERVER,TEXTBOX,internationalizationConstants.observer(),1,true),
508 new InputField(TO,LISTBOX,internationalizationConstants.telescopeOperator(),1,true),
509
510 new InputField(USEORKEYWORDS,CHECKBOX,internationalizationConstants.useOrKeywords(),1,false),
511 new InputField(USEOR,CHECKBOX,internationalizationConstants.useOr(),FULLWIDTH,false),
512 new InputField(SUBMIT,BUTTON,internationalizationConstants.search(),1,false),
513 new InputField(RESET,BUTTON,internationalizationConstants.resetForm(),1,false)
514 };
515
516
517 // These are the fields which will be used for the simple search
518
519 final InputField[] SimpleSearchInputFieldData = new InputField[] {
520 new InputField(KEYWORDS, TEXTBOX,internationalizationConstants.keywords(),FULLWIDTH,false),
521 new InputField(STARTDATE,TEXTBOX,internationalizationConstants.startDate(),1,false),
522 new InputField(ENDDATE,TEXTBOX,internationalizationConstants.endDate(),1,false),
523 new InputField(FAULTNUMBER,TEXTBOX,internationalizationConstants.defectNumber(),1,false),
524 new InputField(SUBMIT,BUTTON,internationalizationConstants.search(),1,false),
525 new InputField(RESET,BUTTON,internationalizationConstants.resetForm(),1,false),
526 };
527
528 /**
529 * An obligation to the KeyboardListener interface. Not Used.
530 */
531
532 public void onKeyDown(Widget sender, char keyCode, int modifiers) {
533
534 }
535
536 /**
537 * Called when the user presses the return key on the search panel
538 * interface. We check to see if the key that was pressed was
539 * the return key and if so, we call the search depending on which
540 * of the search tabs was selected
541 */
542
543 public void onKeyPress(final Widget sender, final char keyCode, final int modifiers) {
544
545 if (keyCode == KeyboardListener.KEY_ENTER) {
546
547 // Work out which of the search tabs are selected and the
548 // call the search procedure which is associated with that
549 // tab whether it be advanced or simple.
550
551 final int SIMPLESEARCHPANEL = 0;
552
553 if (SearchTabPanel.getTabBar().getSelectedTab() == SIMPLESEARCHPANEL) {
554 processSimpleSearch();
555 } else {
556 processAdvancedSearch();
557 }
558 }
559 }
560
561 /**
562 * An obligation to the KeyboardListener interface. Not Used.
563 */
564
565 public void onKeyUp(final Widget sender, final char keyCode, final int modifiers) {
566
567 }
568
569 /**
570 * This implements part of the ClickListener interface and is
571 * called when the user clicks on the button to activate the
572 * search
573 * @param sender This is the widget which was the source of the
574 * click event.
575 */
576
577 public void onClick (final Widget sender) {
578
579 // Has the user requested the simple search ?
580
581 for (int i=0; i < SimpleSearchInputFieldData.length ;i++) {
582
583 if (SimpleSearchInputFieldData[i] != null) {
584
585 if (SimpleSearchInputFieldData[i].ControlWidget.equals(sender)) {
586
587 // If the user has pressed the submit button
588
589 if (SimpleSearchInputFieldData[i].Index.equals(SUBMIT)) {
590
591 processSimpleSearch();
592 return;
593
594 } else if (SimpleSearchInputFieldData[i].Index.equals(RESET)) {
595
596 // If the user has pressed the reset button then
597 // we should reset the fields in the form
598
599 resetFields(SimpleSearchInputFieldData);
600 return;
601 }
602 }
603 }
604 }
605
606 // Has the user pressed a button on the advanced search window ?
607
608 for (int i=0; i < AdvancedSearchInputFieldData.length ;i++) {
609
610 if (AdvancedSearchInputFieldData[i] != null && AdvancedSearchInputFieldData[i].ControlWidget.equals(sender)) {
611
612 if (AdvancedSearchInputFieldData[i].Index.equals(SUBMIT)) {
613
614 // The user has requested to perform the advanced
615 // search
616
617 processAdvancedSearch();
618
619 return;
620
621 } else if (AdvancedSearchInputFieldData[i].Index.equals(RESET)) {
622
623 // Now we need to reset all of the fields in the
624 // advanced search interface
625
626 resetFields(AdvancedSearchInputFieldData);
627 }
628 }
629 }
630 }
631
632 /**
633 * Perform the basic search. Verify that the user has filled in
634 * the search terms correctly and then perform the search on the
635 * java servlet. The results which come back will be displayed in a
636 * {@link GWTApplication.client.SearchResultFormatter SearchResultFormatter}
637 */
638
639 private void processSimpleSearch () {
640
641 // The user has requested to perform the simple
642 // search
643
644 // If there is something in one of the date fields
645 // then make sure there is something in the other
646 // one as well. Also make sure that the format of
647 // the date which was entered into the boxes is
648 // correct.
649
650 TextBox startDate, endDate, faultNumber;
651
652 InputField inputField;
653
654 // True if the user has entered a search term
655
656 boolean fieldCompleted = false;
657
658 // If the user has specified single characters in the keywords
659 // then complain
660
661 inputField = (InputField)SimpleSearchFieldsHash.get(KEYWORDS);
662
663 final String textToCheck = ((TextBox)inputField.getControlWidget()).getText();
664
665 if (!textToCheck.equalsIgnoreCase("")) {
666 fieldCompleted = true;
667 }
668
669 final String[] searchKeys = textToCheck.split(" ");
670
671 for (int i=0; i < searchKeys.length;i++) {
672
673 if (searchKeys[i].length() == 1) {
674 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.searchKeyToShort());
675 return;
676 }
677 }
678
679 inputField = (InputField)SimpleSearchFieldsHash.get(STARTDATE);
680 startDate = (TextBox)inputField.ControlWidget;
681
682 inputField = (InputField)SimpleSearchFieldsHash.get(ENDDATE);
683 endDate = (TextBox)inputField.ControlWidget;
684
685 inputField = (InputField)SimpleSearchFieldsHash.get(FAULTNUMBER);
686 faultNumber = (TextBox)inputField.ControlWidget;
687
688 // Check that if the user has put something into the fault
689 // number field then it is an integer.
690
691 if (!faultNumber.getText().equalsIgnoreCase("")) {
692
693 fieldCompleted = true;
694
695 try {
696 Integer.parseInt(faultNumber.getText());
697 } catch (NumberFormatException e) {
698 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.defectNumberNotSpecifiedCorrectly());
699 return;
700 }
701 }
702
703 // Check the start date to ensure if filled in, it
704 // has been done so correctly
705
706 if (!startDate.getText().equalsIgnoreCase("")) {
707
708 fieldCompleted = true;
709
710 if (!verifyDateFormat(startDate.getText())) {
711 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.dateFieldNotCompletedCorrectly(internationalizationConstants.startDate()));
712 return;
713 }
714 }
715
716 // Check the end date to ensure if filled in, it
717 // has been done so correctly
718
719 if (!endDate.getText().equalsIgnoreCase("")) {
720
721 fieldCompleted = true;
722
723 if (!verifyDateFormat(endDate.getText())) {
724 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.dateFieldNotCompletedCorrectly(internationalizationConstants.endDate()));
725 return;
726 }
727 }
728
729 // If the user has not entered anything into any of the search
730 // fields then inform him and return
731
732 if (!fieldCompleted) {
733 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.noSearchTermSpecified());
734 return;
735 }
736
737 // If the user did not specify a date then we should check
738 // that he has entered some search terms. It is legal to
739 // simply enter a date window.
740
741 final InputField temp = (InputField)SimpleSearchFieldsHash.get(KEYWORDS);
742
743 final String searchQuery = ((TextBox)temp.ControlWidget).getText();
744
745 // Now we need to call the servlet to perform the
746 // search for us
747
748 busyIndicator.showBusy(true);
749
750 // Clear the results table
751
752 DeferredCommand.add(new Command() {
753
754 public void execute() {
755
756 final SearchResultFormatter searchFormatter = (SearchResultFormatter)SearchFormatters.get(SIMPLE);
757
758 searchFormatter.clearResultTable();
759 }});
760
761 svc.performBasicSearch (0,searchQuery,faultNumber.getText(),startDate.getText(),endDate.getText(),internationalizationConstants.locale(),new AsyncCallback() {
762
763 public void onSuccess (final Object result) {
764
765 // Now get the search formatter for
766 // this search type
767
768 final SearchResultFormatter searchFormatter = (SearchResultFormatter)SearchFormatters.get(SIMPLE);
769
770 // Get the formatter to display the
771 // results of the search underneath
772 // the search terms
773
774 searchFormatter.displaySearchResults((ArrayList)result,MainTabPanel);
775 busyIndicator.showBusy(false);
776 }
777
778 public void onFailure (Throwable ex)
779 {
780 busyIndicator.showBusy(false);
781 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.unableToPerformSearch(ex.getMessage()));
782 }
783 });
784 }
785
786 /**
787 * Method called to invoke the advanced search on the servlet in
788 * tomcat container. It will validate the data which has been
789 * entered by the user in order to make sure it is correct and
790 * then execute the search command
791 */
792
793 private void processAdvancedSearch () {
794
795 String textToCheck;
796
797 InputField inputField;
798
799 // Text boxes into which the user specifies the start and the
800 // end date
801
802 TextBox startDateTextBox, endDateTextBox;
803
804 // This is the start and end date that the user specified
805
806 String startDate = "";
807 String endDate = "";
808
809 // True if the user has completed one of the fields
810
811 boolean fieldCompleted = false;
812
813 inputField = (InputField)AdvancedSearchFieldsHash.get(STARTDATE);
814 startDateTextBox = (TextBox)inputField.ControlWidget;
815
816 // Check the start date to ensure if filled in, it
817 // has been done so correctly
818
819 if (inputField.VisibleInResultCheckBox.isChecked() && !startDateTextBox.getText().equalsIgnoreCase("")) {
820
821 fieldCompleted = true;
822
823 if (!verifyDateFormat(startDateTextBox.getText())) {
824 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.dateFieldNotCompletedCorrectly(internationalizationConstants.startDate()));
825 return;
826 }
827
828 startDate = startDateTextBox.getText();
829 }
830
831 // Check the end date to ensure if filled in, it
832 // has been done so correctly
833
834 inputField = (InputField)AdvancedSearchFieldsHash.get(ENDDATE);
835 endDateTextBox = (TextBox)inputField.ControlWidget;
836
837 if (inputField.VisibleInResultCheckBox.isChecked() && !endDateTextBox.getText().equalsIgnoreCase("")) {
838
839 fieldCompleted = true;
840
841 if (!verifyDateFormat(endDateTextBox.getText())) {
842 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.dateFieldNotCompletedCorrectly(internationalizationConstants.endDate()));
843 return;
844 }
845
846 endDate = endDateTextBox.getText();
847 }
848
849 // Verify that the user has specified the priority field
850 // correctly if it has been specified. It can be [<>]1-5 if
851 // specified
852
853 inputField = (InputField)AdvancedSearchFieldsHash.get(PRIORITY);
854
855 textToCheck = ((TextBox)inputField.getControlWidget()).getText();
856 textToCheck = textToCheck.replaceAll("[> <]","");
857
858 if (inputField.VisibleInResultCheckBox.isChecked() && !textToCheck.matches("^[<>]?[ ]?[1-5]?$")) {
859 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.priorityNotCompletedCorrectly());
860 return;
861 }
862
863 // If the user has entered anything into the date occured
864 // field and ticked the check box make sure that what has been
865 // entered is valid
866
867 inputField = (InputField)AdvancedSearchFieldsHash.get(DATEOCCURED);
868
869 textToCheck = ((TextBox)inputField.getControlWidget()).getText();
870 textToCheck = textToCheck.replaceAll("[> <]","");
871
872 if (inputField.VisibleInResultCheckBox.isChecked() && !verifyDateFormat(textToCheck)) {
873 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.dateFieldNotCompletedCorrectly(internationalizationConstants.dateOccured()));
874 return;
875 }
876
877 // Verify that if the user has specified a defect number it is
878 // an integer
879
880 inputField = (InputField)AdvancedSearchFieldsHash.get(DEFECTNUMBER);
881
882 textToCheck = ((TextBox)inputField.getControlWidget()).getText();
883
884 if (inputField.VisibleInResultCheckBox.isChecked() && !textToCheck.matches("^[<>]?[ ]?[0-9]+$")) {
885 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.defectNumberNotSpecifiedCorrectly());
886 return;
887 }
888
889 // Verify that if the user has entered data into the time lost
890 // field that he has entered it in the correct format
891
892 inputField = (InputField)AdvancedSearchFieldsHash.get(TIMELOST);
893
894 textToCheck = ((TextBox)inputField.getControlWidget()).getText();
895
896 if (inputField.VisibleInResultCheckBox.isChecked() && !textToCheck.matches("^[<>]?[ ]?([0-9]+):[0-5][0-9]$")) {
897 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.timeFieldNotCompletedCorrectly(internationalizationConstants.timeLost()));
898 return;
899 }
900
901 // If the user has specified single characters in the keywords
902 // then complain
903
904 inputField = (InputField)AdvancedSearchFieldsHash.get(KEYWORDS);
905
906 textToCheck = ((TextBox)inputField.getControlWidget()).getText().trim();
907
908 // If the user has entered some keywords flag the fact that he has entered some search terms
909
910 if (!textToCheck.equalsIgnoreCase("")) {
911 fieldCompleted = true;
912 }
913
914 final String[] searchKeys = textToCheck.split(" ");
915
916 for (int i=0; i < searchKeys.length;i++) {
917
918 if (searchKeys[i].length() == 1) {
919 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.searchKeyToShort());
920 return;
921 }
922 }
923
924 // Now that we have parsed all of the free form input fields,
925 // pack the search data into a data structure and send it down
926 // to the servlet to perform the search
927
928 final HashMap searchParameters = new HashMap();
929
930 Iterator iterator = AdvancedSearchFieldsHash.keySet().iterator();
931
932 while (iterator.hasNext()) {
933
934 final InputField field = (InputField)AdvancedSearchFieldsHash.get((String)iterator.next());
935
936 // We only include the search parameters if the user has
937 // clicked the check box or if it does not have a checkbox
938 // (in the case of the keywords).
939
940 if (field != null) {
941
942 if (!field.HasOptionalVisibilityInSearchQuery || (field.HasOptionalVisibilityInSearchQuery && field.VisibleInResultCheckBox.isChecked())) {
943
944 String searchParameter;
945
946 if (field.Type == TEXTBOX) {
947
948 searchParameter = ((TextBox)field.getControlWidget()).getText();
949
950 } else if (field.Type == LISTBOX) {
951
952 ListBox list = (ListBox)field.getControlWidget();
953
954 searchParameter = list.getValue(list.getSelectedIndex());
955
956 } else if (field.Type == CHECKBOX) {
957
958 CheckBox checkBox = (CheckBox)field.getControlWidget();
959
960 searchParameter = checkBox.isChecked()?CHECKED:NOTCHECKED;
961
962 } else {
963
964 // If this is a field that we do not how to
965 // deal with then move onto the next input
966 // field
967
968 continue;
969 }
970
971 if (!searchParameter.equals("")) {
972
973 if (field.Type != CHECKBOX) {
974 fieldCompleted = true;
975 }
976
977 searchParameters.put(field.Index,searchParameter);
978 }
979 }
980 }
981 }
982
983 // Now check to make sure that the user has specified some
984 // search parameters by checking the hash to make sure there
985 // are some search terms in there otherwise there is no point
986 // going on from here (Note that the parameter which will be
987 // used to determine if we are use And/Or to conjugate the
988 // search query counts as one parameter).
989
990 if (searchParameters.size() == 1 || !fieldCompleted) {
991 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.noSearchTermSpecified());
992 return;
993 }
994
995 // Now we execute the operation in the servlet which is going
996 // to perform the search
997
998 busyIndicator.showBusy(true);
999
1000 // Clear out the results table
1001
1002 DeferredCommand.add(new Command() {
1003
1004 public void execute() {
1005
1006 SearchResultFormatter searchFormatter = (SearchResultFormatter)SearchFormatters.get(ADVANCED);
1007
1008 searchFormatter.clearResultTable();
1009 }});
1010
1011 svc.performAdvancedSearch (searchParameters,startDate,endDate,internationalizationConstants.locale(),new AsyncCallback() {
1012
1013 public void onSuccess (final Object result) {
1014
1015 // Now get the search formatter for
1016 // this search type
1017
1018 SearchResultFormatter searchFormatter = (SearchResultFormatter)SearchFormatters.get(ADVANCED);
1019
1020 // Get the formatter to display the results of the
1021 // search underneath the search terms
1022
1023 searchFormatter.displaySearchResults((ArrayList)result,MainTabPanel);
1024 busyIndicator.showBusy(false);
1025 }
1026
1027 public void onFailure (Throwable ex)
1028 {
1029 busyIndicator.showBusy(false);
1030 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.unableToPerformSearch(ex.getMessage()));
1031 }
1032 });
1033
1034 return;
1035
1036 }
1037
1038 /**
1039 * This will be used to reset the fields in the search form which
1040 * is provided.
1041 * @param FormFields This is an array of all of the fields in the
1042 * form which is to be reset
1043 */
1044
1045 private void resetFields(final InputField[] FormFields) {
1046
1047 for (int i=0; i < FormFields.length; i++) {
1048
1049 if (FormFields[i].Type == TEXTBOX) {
1050
1051 // Reset any text boxes in the form
1052
1053 ((TextBox)FormFields[i].ControlWidget).setText("");
1054 }
1055
1056 if (FormFields[i].Type == CHECKBOX) {
1057
1058 // Reset any check boxes
1059
1060 ((CheckBox)FormFields[i].ControlWidget).setChecked(false);
1061 }
1062
1063 // Clear any visibility tickboxes which have been selected
1064 // if they are included in the search page
1065
1066 if (FormFields[i].HasOptionalVisibilityInSearchQuery) {
1067 FormFields[i].VisibleInResultCheckBox.setChecked(false);
1068 }
1069 }
1070 }
1071
1072 /**
1073 * This method will create a search panel within the parent tab
1074 * panel. The operation is data-driven and the method uses the
1075 * information which is located in the SearchTabPanelData input
1076 * parameter in order to determine how the panel should be
1077 * constructed. This method is woefully inflexible but serves the
1078 * required purpose.
1079 * @param SearchType This the type of the search which can be
1080 * {@link #ADVANCED ADVANCED} or {@link #SIMPLE SIMPLE}.
1081 * @param TabText This is the text which should be associated with
1082 * the tab. Should be either simple or advanced
1083 * @param SearchTabPanelData this variable contains the data which
1084 * will be used to generate the form from.
1085 * @param TableWidth This is the expected widths in columns of the
1086 * table into which we will generate the search form
1087 * @param IncludeVisibilityCheckBoxes This indicates whether or
1088 * not we should add checkboxes associated with each of the input
1089 * fields. The semantic of the checkbox is to include the selected
1090 * fields in the search results.
1091 */
1092
1093 void createSearchTabPanel (final String SearchType,
1094 final String TabText,
1095 final InputField[] SearchTabPanelData,
1096 final int TableWidth,
1097 final boolean IncludeVisibilityCheckBoxes) {
1098
1099 // Create a new tab in the search panel with the label which
1100 // was provided
1101
1102 final FlexTable searchTable = new FlexTable();
1103
1104 final FlexCellFormatter formatter = (FlexCellFormatter)searchTable.getCellFormatter();
1105
1106 final VerticalPanel mainPanel = new VerticalPanel();
1107
1108 mainPanel.setWidth("97%");
1109 mainPanel.setStyleName("searchPanel");
1110
1111 searchTable.setWidth("97%");
1112
1113 // Now add the table to the panel
1114
1115 mainPanel.add(searchTable);
1116 mainPanel.setCellWidth(searchTable,"100%");
1117
1118 // Add a new tab to the tab panel
1119
1120 SearchTabPanel.add(mainPanel,TabText);
1121
1122 int currentColumn = 0;
1123 int currentRow = 0;
1124
1125 for (int i=0; i < SearchTabPanelData.length ;i++) {
1126
1127 final InputField currentField = SearchTabPanelData[i];
1128
1129 if (currentField != null) {
1130
1131 if (currentField.Type == TEXTBOX) {
1132
1133 final TextBox searchTermField = new TextBox();
1134 final Label label = new Label(currentField.Title);
1135
1136 currentField.ControlWidget = searchTermField;
1137
1138 // If this field is to be the full width then make
1139 // it the full width of the table
1140
1141 if (currentField.Width == FULLWIDTH) {
1142
1143 searchTermField.setWidth("100%");
1144
1145 // We put the label above the text input box.
1146
1147 searchTable.setWidget(currentRow,currentColumn,label);
1148 formatter.setWidth(currentRow,currentColumn,"10%");
1149
1150 currentRow++;
1151 searchTable.setWidget(currentRow,currentColumn,searchTermField);
1152 formatter.setColSpan(currentRow,currentColumn,TableWidth);
1153
1154 } else {
1155
1156 searchTable.setWidget(currentRow,currentColumn,label);
1157 formatter.setWidth(currentRow,currentColumn,"10%");
1158
1159 if (currentField.HasOptionalVisibilityInSearchQuery) {
1160
1161 currentField.VisibleInResultCheckBox = new CheckBox();
1162
1163 searchTable.setWidget(currentRow,currentColumn+1,currentField.VisibleInResultCheckBox);
1164 searchTable.setWidget(currentRow,currentColumn+2,searchTermField);
1165 formatter.setWidth(currentRow,currentColumn+2,"15%");
1166
1167 } else {
1168
1169 final int columnToInsertInto = IncludeVisibilityCheckBoxes?currentColumn+2:currentColumn+1;
1170
1171 searchTable.setWidget(currentRow,columnToInsertInto,searchTermField);
1172
1173 // If we have been requested to display
1174 // the optional visibility checkboxes but
1175 // there is no check box specified in the
1176 // data model for this search
1177
1178 formatter.setWidth(currentRow,columnToInsertInto,"20%");
1179
1180 formatter.setHorizontalAlignment(currentRow,columnToInsertInto,HasHorizontalAlignment.ALIGN_LEFT);
1181 }
1182
1183 searchTermField.setWidth("5cm");
1184 }
1185
1186 // Make sure that the user can press the return key to activate the search
1187
1188 searchTermField.addKeyboardListener(this);
1189
1190 } else if (currentField.Type == LISTBOX) {
1191
1192 ListBox searchTermField = new ListBox();
1193 Label label = new Label(currentField.Title);
1194
1195 currentField.ControlWidget = searchTermField;
1196
1197 // If this field is to be the full width then make
1198 // it the full width
1199
1200 if (currentField.Width == FULLWIDTH) {
1201
1202 searchTermField.setWidth("100%");
1203
1204 searchTable.setWidget(currentRow,currentColumn,label);
1205 currentRow++;
1206 searchTable.setWidget(currentRow+1,currentColumn,searchTermField);
1207 formatter.setColSpan(currentRow,currentColumn,4);
1208
1209 } else {
1210
1211 searchTable.setWidget(currentRow,currentColumn,label);
1212
1213 if (currentField.HasOptionalVisibilityInSearchQuery) {
1214
1215 CheckBox temp = new CheckBox();
1216
1217 currentField.VisibleInResultCheckBox = temp;
1218
1219 searchTable.setWidget(currentRow,currentColumn+1,temp);
1220 searchTable.setWidget(currentRow,currentColumn+2,searchTermField);
1221 formatter.setWidth(currentRow,currentColumn+2,"20%");
1222
1223 } else {
1224
1225 final int columnToInsertInto = IncludeVisibilityCheckBoxes?currentColumn+2:currentColumn+1;
1226
1227 searchTable.setWidget(currentRow,columnToInsertInto,searchTermField);
1228 formatter.setWidth(currentRow,columnToInsertInto,"20%");
1229 }
1230 }
1231
1232 searchTermField.setWidth("5cm");
1233
1234 // Make sure that the user can press the return key to activate the search
1235
1236 searchTermField.addKeyboardListener(this);
1237
1238 } else if (currentField.Type == BUTTON) {
1239
1240 Button button = new Button(currentField.Title,this);
1241
1242 currentField.ControlWidget = button;
1243
1244 // If this field is to be the full width then make it the full width
1245
1246 if (currentField.Width == FULLWIDTH) {
1247
1248 if (currentColumn != 0) {
1249 currentColumn = 0;
1250 currentRow++;
1251 }
1252
1253 searchTable.setWidget(currentRow,currentColumn,button);
1254 currentRow++;
1255 } else {
1256 searchTable.setWidget(currentRow,currentColumn,button);
1257 }
1258
1259 } else if (currentField.Type == CHECKBOX) {
1260
1261 final CheckBox checkBox = new CheckBox(currentField.Title);
1262
1263 currentField.ControlWidget = checkBox;
1264
1265 // If this field is to be the full width then make
1266 // it the full width
1267
1268 if (currentField.Width == FULLWIDTH) {
1269
1270 searchTable.setWidget(currentRow,currentColumn,checkBox);
1271 currentRow++;
1272
1273 } else {
1274
1275 searchTable.setWidget(currentRow,currentColumn,checkBox);
1276 formatter.setHorizontalAlignment(currentRow,currentColumn,HasHorizontalAlignment.ALIGN_LEFT);
1277 }
1278 }
1279 }
1280
1281 // Now move onto the next column in the table (if this is not a full table width column).
1282 // Note that a "column" consists of 2 columns in the table (label + entry field).
1283
1284 if (IncludeVisibilityCheckBoxes) {
1285 currentColumn += 3;
1286 } else {
1287 currentColumn += 2;
1288 }
1289
1290 if (currentColumn >= TableWidth || currentField.Width == FULLWIDTH) {
1291 currentColumn = 0;
1292 currentRow++;
1293 }
1294 }
1295
1296 // Now we need to create a table at the foot of the panel
1297 // which will be used to display the results of the search
1298
1299 ScrollPanel resultsScrollPanel = new ScrollPanel();
1300
1301 resultsScrollPanel.setWidth("97%");
1302
1303 resultsScrollPanel.setStyleName("searchResultsPanel");
1304
1305 mainPanel.add(resultsScrollPanel);
1306 mainPanel.setCellWidth(resultsScrollPanel,"100%");
1307 mainPanel.setSpacing(3);
1308
1309 // Now we need to add the results table to the panel
1310
1311 final FlexTable resultsTable = new FlexTable();
1312
1313 resultsTable.setStyleName("searchResultsTable");
1314 resultsTable.setWidth("100%");
1315
1316 resultsScrollPanel.add(resultsTable);
1317
1318 // Now drop the search formatter for this search into the hash
1319 // for later use
1320
1321 final SearchResultFormatter searchFormatter = new SearchResultFormatter(resultsTable,
1322 ModifyFormPage,
1323 UserAuthentication,
1324 svc,
1325 internationalizationConstants,
1326 faultUpdateMonitor);
1327
1328 SearchFormatters.put(SearchType,searchFormatter);
1329
1330 searchFormatter.setResultsTable(resultsTable);
1331 }
1332
1333 /**
1334 * This is used to create the form which will be used to enter the
1335 * details of a search.
1336 * @param MainTabPanel This is the tabbed panel into which we
1337 * should build the search panels.
1338 * @param svc This is used to communicate with the servlet in the
1339 * Tomcat container.
1340 * @param UserAuthentication Contains the details of the users
1341 * authentication.
1342 * @param ModifyFormPage The tab which is used for updating the
1343 * faults in the database. This is so that we can link from the
1344 * search page to the update form panel.
1345 * @param faultUpdateMonitor This will be used to track updates of
1346 * faults in the system.
1347 */
1348
1349 SearchForm (final TabPanel MainTabPanel,
1350 final FaultServiceAsync svc,
1351 final AuthenticationDetails UserAuthentication,
1352 final ModifyFormPanel ModifyFormPage,
1353 final FaultUpdateMonitor faultUpdateMonitor) {
1354
1355 this.UserAuthentication = UserAuthentication;
1356 this.svc = svc;
1357 this.ModifyFormPage = ModifyFormPage;
1358 this.MainTabPanel = MainTabPanel;
1359 this.faultUpdateMonitor = faultUpdateMonitor;
1360
1361 // Now add the main panel to the tab
1362
1363 MainTabPanel.add(SearchTabPanel,internationalizationConstants.search());
1364
1365 // Create the simple & advanced search tabs in the search panel.
1366
1367 createSearchTabPanel(SIMPLE,internationalizationConstants.simple(),SimpleSearchInputFieldData,6,false);
1368 createSearchTabPanel(ADVANCED,internationalizationConstants.advanced(),AdvancedSearchInputFieldData,9,true);
1369
1370 // Select the simple search by default
1371
1372 SearchTabPanel.selectTab(0);
1373
1374 // Now create the hashtables now which will be used for
1375 // accessing the fields in the form
1376
1377 for (int i=0; i < AdvancedSearchInputFieldData.length ;i++) {
1378
1379 if (AdvancedSearchInputFieldData[i] != null) {
1380 AdvancedSearchFieldsHash.put(AdvancedSearchInputFieldData[i].Index,AdvancedSearchInputFieldData[i]);
1381 }
1382 }
1383
1384 for (int i=0; i < SimpleSearchInputFieldData.length ;i++) {
1385
1386 if (SimpleSearchInputFieldData[i] != null) {
1387 SimpleSearchFieldsHash.put(SimpleSearchInputFieldData[i].Index,SimpleSearchInputFieldData[i]);
1388 }
1389 }
1390
1391 // Now we need to fill in the drop down menus in the advanced
1392 // search engine with the fields from which the user can
1393 // select from.
1394
1395 fillListBoxWithInstruments((ListBox)((InputField)AdvancedSearchFieldsHash.get(INSTRUMENT)).getControlWidget(),internationalizationConstants.locale());
1396 fillListBoxWithSystems((ListBox)((InputField)AdvancedSearchFieldsHash.get(SYSTEM)).getControlWidget(),internationalizationConstants.locale());
1397 fillListBoxWithTelescopeOperators((ListBox)((InputField)AdvancedSearchFieldsHash.get(TO)).getControlWidget(),null,true);
1398 fillListBoxWithSupportAstronomers((ListBox)((InputField)AdvancedSearchFieldsHash.get(SA)).getControlWidget(),null,true);
1399 fillListBoxWithStaffMembers((ListBox)((InputField)AdvancedSearchFieldsHash.get(ASSIGNEDTO)).getControlWidget(),null,true);
1400 fillListBoxWithStates((ListBox)((InputField)AdvancedSearchFieldsHash.get(STATUSTYPE)).getControlWidget(),internationalizationConstants.locale());
1401 fillListBoxWithSeverity((ListBox)((InputField)AdvancedSearchFieldsHash.get(SEVERITY)).getControlWidget(),internationalizationConstants.locale());
1402 fillListBoxWithSites((ListBox)((InputField)AdvancedSearchFieldsHash.get(SITE)).getControlWidget(),internationalizationConstants.locale());
1403 fillListBoxWithStaffMembers((ListBox)((InputField)AdvancedSearchFieldsHash.get(ORIGINATOR)).getControlWidget(),null,true);
1404 fillListBoxWithFaultType((ListBox)((InputField)AdvancedSearchFieldsHash.get(FAULTTYPE)).getControlWidget(),internationalizationConstants.locale());
1405 fillListBoxWithDutyTechnicians((ListBox)((InputField)AdvancedSearchFieldsHash.get(DUTYENGINEER)).getControlWidget(),null,true);
1406 }
1407 }
1408
1409
1410