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