001 /** ===================================================================== 002 * 003 * File Name : $Id: SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 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 1 Jun 2007 C.Bevil First Release 023 * 024 * Commissioning Notes 025 * ------------------- 026 * 027 * None 028 * 029 * ===================================================================== 030 * 031 * @Version : $Id: SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 cb Exp $ 032 * 033 * @Author : $Author: cb $ 034 * 035 * Header : $Header: /opt/INGsrc/src/CVS/softproj/FaultDatabase/src/FaultDatabase/FaultDatabase/src/GWTApplication/client/SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 cb Exp $ 036 * 037 * Log : $Log: SearchResultFormatter.java,v $ 038 * Log : Revision 1.26 2007/12/17 12:26:40 cb 039 * Log : Moved a section of code into a try structure as it was suspected that 040 * Log : it was giving problems. 041 * Log : 042 * Log : Revision 1.25 2007/12/14 15:00:28 cb 043 * Log : Modified the fault number which is inserted into the table such that 044 * Log : it is a link which the user can cut & paste. 045 * Log : 046 * Log : Revision 1.24 2007/12/10 17:11:41 cb 047 * Log : Corrected a bug when we were using the fault array to fill in the 048 * Log : table when there was nothing in it. Modified to use the nice new JS 049 * Log : toolkit. 050 * Log : 051 * Log : Revision 1.23 2007/10/18 14:17:16 cb 052 * Log : Put a error trap into the deferred incremental command which fills in 053 * Log : the details of the search results in the case of the search page where 054 * Log : the user types in a second search query before the results of the 055 * Log : first query has been completely displayed i.e. the incremental command 056 * Log : has not completed. This was breaking on IE. 057 * Log : 058 * Log : Revision 1.22 2007/09/06 07:59:17 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.21 2007/09/06 06:53:41 cb 064 * Log : Before overhaul to fix update problems 065 * Log : 066 * Log : Revision 1.20 2007/09/04 14:10:54 cb 067 * Log : Check for updates to the faults every 2.5 seconds now. 068 * Log : 069 * Log : Revision 1.19 2007/08/22 15:56:46 cb 070 * Log : Comment update 071 * Log : 072 * Log : Revision 1.18 2007/08/22 15:55:17 cb 073 * Log : Update the view using a full SQL search if the search formatter is 074 * Log : empty when a fault update is received. 075 * Log : 076 * Log : Revision 1.17 2007/08/20 14:48:14 cb 077 * Log : Added extra fields in the fault description table to include the time 078 * Log : occured and the date occured. 079 * Log : 080 * Log : Revision 1.16 2007/08/17 14:19:40 cb 081 * Log : Ensure that the keywords in the search keywords have more than a 082 * Log : single character 083 * Log : 084 * Log : Revision 1.15 2007/08/14 10:47:54 cb 085 * Log : Modified so that the disclosure panel will update dynamically when a 086 * Log : fault or it's history is changed. 087 * Log : 088 * Log : Revision 1.14 2007/08/14 09:39:08 cb 089 * Log : Modified after PMD session 090 * Log : 091 * Log : Revision 1.13 2007/08/08 16:16:16 cb 092 * Log : Optimised for speed a little 093 * Log : 094 * Log : Revision 1.12 2007/08/07 14:44:40 cb 095 * Log : Modified to display busy when opening the disclosure boxes 096 * Log : 097 * Log : Revision 1.11 2007/08/02 10:57:05 cb 098 * Log : Moved workaround above comments 099 * Log : 100 * Log : Revision 1.10 2007/08/01 13:00:04 cb 101 * Log : First prototype after import 102 * Log : 103 * Log : Revision 1.9 2007/07/30 14:25:24 cb 104 * Log : Before optimizing for speed 105 * Log : 106 * Log : Revision 1.8 2007/07/24 08:28:13 cb 107 * Log : Modified to use the print dialogue 108 * Log : 109 * Log : Revision 1.7 2007/07/23 15:42:07 cb 110 * Log : Modified to include a fault monitor which will check the database 111 * Log : intermittingly and update the view if the faults which are being 112 * Log : displayed are changed behind the scenes. 113 * Log : 114 * Log : Revision 1.6 2007/07/19 12:44:38 cb 115 * Log : Added facility to close a fault down. 116 * Log : 117 * Log : Revision 1.5 2007/07/13 10:54:04 cb 118 * Log : Complete interface prototype 119 * Log : 120 * Log : Revision 1.4 2007/07/03 16:47:15 cb 121 * Log : Modified to include the email links in the fault specifics. 122 * Log : 123 * Log : Revision 1.3 2007/07/03 12:48:08 cb 124 * Log : Before augmenting the fault information with the full details of the 125 * Log : fault 126 * Log : 127 * Log : Revision 1.2 2007/06/01 14:23:41 cb 128 * Log : First version that I am happy with 129 * Log : 130 * Log : Revision 1.1.1.1 2007/06/01 08:33:26 cb 131 * Log : Imported using TkCVS 132 * Log : 133 * 134 * =====================================================================*/ 135 136 package GWTApplication.client; 137 138 import com.google.gwt.user.client.*; 139 import com.google.gwt.user.client.rpc.*; 140 import com.google.gwt.user.client.ui.*; 141 import com.google.gwt.user.client.ui.FlexTable.*; 142 import com.google.gwt.user.client.ui.HTMLTable.*; 143 import com.google.gwt.user.client.ui.Hyperlink.*; 144 145 import com.gwtext.client.core.EventObject; 146 import com.gwtext.client.util.Format; 147 import com.gwtext.client.widgets.MessageBox; 148 import com.gwtext.client.widgets.MessageBoxConfig; 149 150 import java.util.*; 151 152 /** 153 * This class will be used to format the results of a search query and 154 * display them in a HTML table. Each of the faults will be displayed 155 * as a row in the table and associated with each row will be a panel which 156 * expands out to provide the full details of the fault to the user 157 * which includes all of the comments, the solution and the workaround 158 * which is associated with the fault. 159 * <P> 160 * This class is central to the displaying of the results of search 161 * queries throughout the system. It is used by the {@link 162 * QuickViewReport QuickViewReport} class and the {@link SearchForm 163 * SearchForm} class in order to display the results of the SQL 164 * queries which extract from the database faults pertinent to them 165 * specific views on the fault information. 166 * @author Craige Bevil 167 * @version $Id: SearchResultFormatter.java,v 1.17 2007/08/20 14:48:14 168 * cb Exp $ 169 * @see QuickViewReport 170 * @see SearchForm 171 */ 172 173 class SearchResultFormatter extends FaultDBForm implements FaultListener { 174 175 /** 176 * Used to check the database intermittingly and report back to 177 * listeners which faults they are displaying have changed so that 178 * they may update their view accordingly. 179 */ 180 181 private FaultUpdateMonitor faultUpdateMonitor = null; 182 183 /** 184 * This is an object which can be used to refresh the details of 185 * this search view. The search formatter only displays the 186 * details of a search query, it does not know about how the 187 * results were deduced in the first instance. This object will 188 * allow the search result formatter to request that it's contents 189 * be refreshed. 190 */ 191 192 public RefreshSearchResultsListener searchResultUpdater = null; 193 194 /** 195 * A constant which is used to indicate something is UNKNOWN. 196 */ 197 198 private final static int UNKNOWN = -1; 199 200 /** 201 * This is the fault id with the highest defect number which is 202 * displayed in the table 203 */ 204 205 private int HighestDefectNoInTable = UNKNOWN; 206 207 /** 208 * Indicates the first row in the search result table 209 */ 210 211 final static int HEADOFTABLE = 1; 212 213 /** 214 * Whether to add new faults which are entered into the database 215 * after this search result displayer has been initialised 216 */ 217 218 private boolean displayNewFaults = false; 219 220 /** 221 * Whether the user has the privilege to perform admin type functions 222 */ 223 224 final private boolean hasAdminPriviledge; 225 226 /** 227 * This is a has of all of the fault displayers which are 228 * associated with the disclosure panels 229 */ 230 231 final private HashMap faultDisplayers = new HashMap(); 232 233 /** 234 * Whether this user can modify the details of a fault if his 235 * priviledge level is high enough. 236 */ 237 238 private boolean userCanModifyFaults = false; 239 240 /** 241 * This is used to format the main results table 242 */ 243 244 private FlexCellFormatter resultsTableCellFormatter; 245 246 /** 247 * This is used to format the main results table 248 */ 249 250 private RowFormatter resultsTableRowFormatter; 251 252 /** 253 * This is a hashmap which contains for each faults, which row in 254 * the table that they reside in. This is used when updating the 255 * details of a fault should the fault be updated in the 256 * background by another user 257 */ 258 259 private HashMap faultTableRowMapping = new HashMap(); 260 261 /** 262 * This is the service which will be used to access the servlet 263 * which is running in the tomcat container 264 */ 265 266 final private FaultServiceAsync svc; 267 268 /** 269 * Contains the authentication data which is associated with the 270 * current user 271 */ 272 273 private AuthenticationDetails UserAuthentication; 274 275 /** 276 * This is the main tab panel for the application. We need this so 277 * that if the user clicks on the modify fault link we can select 278 * the entry in the tab panel which corresponds to the update 279 * fault page. 280 */ 281 282 private TabPanel MainTabPanel; 283 284 /** 285 * This panel will be used to allow the user to modify the details 286 * of a fault 287 */ 288 289 final private ModifyFormPanel ModifyFormPage; 290 291 /** 292 * This is the widget into which the search results will be 293 * displayed. 294 */ 295 296 private FlexTable ResultsTable; 297 298 /** 299 * This class will be used for internationalization so that we can 300 * flick between the locales of English and Spanish. 301 */ 302 303 InternationalizationConstants internationalizationConstants; 304 305 /** 306 * This is an incremental command which is used to display the 307 * search results so that the browser does not simply lock up 308 * whilst the results are being displayed. Although it is not 309 * possible to thread GWT applications, this works like a timer 310 * and breaks the work up such that the browser will respond to 311 * the user whilst it is building the search panel. This is 312 * important as to build the FlexTable which contains the details 313 * of the search results takes a lot of time and I'm sure that the 314 * user will not appreciate having to wait for 30 seconds until 315 * his search results are displayed. 316 * @author Craige Bevil 317 * @version $Id: SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 cb Exp $ 318 */ 319 320 private class DisplaySearchResultsIncrementalCommand implements IncrementalCommand { 321 322 /** 323 * This is the number of search results that we need to add to the search panel 324 */ 325 326 private int numberOfResultsToAdd = 0; 327 328 /** 329 * This is the number of search results which have been added to the search panel 330 */ 331 332 private int numberOfRowsAdded = 0; 333 334 /** 335 * This is the list of search results which are to be 336 * displayed in the search result panel 337 */ 338 339 private ArrayList searchResults; 340 341 /** 342 * This is the current row in the search result table into which we put the next search result 343 */ 344 345 private int currentRow; 346 347 /** 348 * This is the constructor 349 */ 350 351 DisplaySearchResultsIncrementalCommand (final ArrayList searchResults) { 352 353 this.searchResults = searchResults; 354 355 numberOfResultsToAdd = searchResults.size(); 356 357 HighestDefectNoInTable = UNKNOWN; 358 359 // First clear out the current results of the table if there 360 // is anything in it. 361 362 ResultsTable.clear(); 363 ResultsTable.setStyleName("QuickViewResultsTable"); 364 365 for (int i= ResultsTable.getRowCount()-1; i >= 0; i--) { 366 ResultsTable.removeRow(i); 367 } 368 369 // If there were no results to be displayed then we report to 370 // that effect 371 372 if (searchResults.size() == 0) { 373 ResultsTable.setHTML(0,0,internationalizationConstants.noSearchResultsFound()); 374 resultsTableRowFormatter.setStyleName(0,"quickViewFaultDetailRow"); 375 return; 376 } 377 378 // Now create the header row which for the results 379 380 ResultsTable.insertRow(0); 381 382 ResultsTable.setHTML(0,0,"ID"); 383 ResultsTable.setHTML(0,1,internationalizationConstants.type()); 384 ResultsTable.setHTML(0,2,internationalizationConstants.severity()); 385 ResultsTable.setHTML(0,3,internationalizationConstants.timeReported()); 386 ResultsTable.setHTML(0,4,internationalizationConstants.originator()); 387 ResultsTable.setHTML(0,5,internationalizationConstants.site()); 388 ResultsTable.setHTML(0,6,internationalizationConstants.instrument()); 389 ResultsTable.setHTML(0,7,internationalizationConstants.timeLost()); 390 ResultsTable.setHTML(0,8,internationalizationConstants.status()); 391 ResultsTable.setHTML(0,9,internationalizationConstants.timeSpent()); 392 ResultsTable.setHTML(0,10,internationalizationConstants.action()); 393 394 resultsTableRowFormatter.setStyleName(0,"quickViewFaultDetailRow"); 395 396 // Now go through each of the faults in the array and add the 397 // details of the search to the table. 398 399 currentRow = HEADOFTABLE; 400 401 faultTableRowMapping = new HashMap(); 402 403 } 404 405 public boolean execute () { 406 407 final Fault fault; 408 409 if (searchResults.size() == 0) { 410 return false; 411 } 412 413 fault = (Fault)searchResults.get(numberOfRowsAdded); 414 415 try { 416 417 // Store which row in the table that the fault belongs 418 // in 419 420 faultTableRowMapping.put(new Integer(fault.id),new Integer(currentRow)); 421 422 putFaultIntoResultsTable(fault,currentRow,false,false); 423 424 // Move the current row in the table down two 425 426 currentRow += 2; 427 428 // If we have added all of the rows that we want to add 429 // then we have finished this incremental command now 430 431 if (++numberOfRowsAdded == numberOfResultsToAdd) { 432 433 // Now format the row generically 434 435 resultsTableRowFormatter.setStyleName(0,"quickViewFaultTable"); 436 437 return false; 438 } 439 440 } catch (Exception e) { 441 442 // If there is something wrong here then do nothing else. 443 444 return false; 445 } 446 447 // We have not added all of the rows to the search results 448 // yet 449 450 return true; 451 } 452 } 453 454 /** 455 * Inner class which will be used to display the full fault 456 * history as the user clicks on a disclosure widget header and 457 * opens it for the first time. 458 * @author Craige Bevil 459 * @version $Id: SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 cb Exp $ 460 */ 461 462 private class DisplayFullFault implements DisclosureHandler { 463 464 /** 465 * This will be used to display whether or not we are busy or 466 * not 467 */ 468 469 private BusyIndicator busyIndicator = null; 470 471 /** 472 * Contains the full history of the fault 473 */ 474 475 private FaultEntryDetails faultHistory = null; 476 477 /** 478 * Whether or not we have the fault information for this fault 479 */ 480 481 int noOfSubTasksCompleted = 0; 482 483 /** 484 * This is the defect number which is associated with 485 * the fault 486 */ 487 488 private int FaultNumber; 489 490 /** 491 * This is the panel into which we are to put the result once 492 * they arrive from the servlet 493 */ 494 495 private DisclosurePanel panel; 496 497 /** 498 * If the panel has been initialised 499 */ 500 501 private boolean panelInitialised = false; 502 503 /** 504 * Called when the user opens the disclosure box and results 505 * in the data being extracted from the database and displayed 506 * within the disclosure box. 507 */ 508 509 public void onOpen(DisclosureEvent event) { 510 511 // If the panel is already set up then return 512 513 if (panelInitialised) return; 514 515 // Now update the display with the details of the fault 516 517 getFaultDetails(); 518 519 if (busyIndicator == null) { 520 busyIndicator = new BusyIndicator(); 521 } 522 523 panel = (DisclosurePanel)event.getSource(); 524 525 busyIndicator.showBusy(true); 526 527 // Now wait until the fault data has been retrieved from 528 // the servlet using a deferred command. This is basically 529 // a mechanism for syncronisation when a command is built 530 // into subtasks and we need to syncronise when all of the 531 // subtasks are completed. The javascript GWT engine will 532 // call this class intermittingly until all of the 533 // subtasks have been completed or it times out and 534 // complains to the user the script is taking too long 535 536 DeferredCommand.addCommand(new IncrementalCommand() { 537 538 public boolean execute() { 539 540 // If the information relating to the fault has 541 // arrived then display it now otherwise we wait 542 // for the next time that we are called and try 543 // again 544 545 final int NOOFSUBTASKSINVOLVEDINGETTINGFAULTDETAILS = 1; 546 547 if (noOfSubTasksCompleted == NOOFSUBTASKSINVOLVEDINGETTINGFAULTDETAILS) { 548 549 createFaultDisclosurePanelContent(); 550 551 busyIndicator.showBusy(false); 552 553 // false indicates that we are not waiting 554 // for anything more to be done and that 555 // all of the subtasks have been completed 556 557 return false; 558 } 559 560 // We are still waiting for things to be completed. 561 562 return true; 563 } 564 }); 565 566 // The panel is initialised 567 568 panelInitialised = true; 569 } 570 571 /** 572 * Sets the state of the disclosure panel and whether it is 573 * initialied or not 574 * @param State The state of the panel 575 */ 576 577 public void setPanelInitialised (boolean State) { 578 panelInitialised = State; 579 } 580 581 /** 582 * This method will be called to generate the disclosure 583 * content panel which contains the <b>full details</b> of the 584 * fault which is displayed when the user clicks upon the 585 * arrow icon in the disclosure panel in the display. 586 */ 587 588 void createFaultDisclosurePanelContent () { 589 590 final FlexTable faultDescriptionTable = new FlexTable(); 591 final FlexCellFormatter formatter = (FlexCellFormatter)faultDescriptionTable.getCellFormatter(); 592 final RowFormatter tableRowFormatter = (RowFormatter)faultDescriptionTable.getRowFormatter(); 593 final FlexTable faultSpecificsTable = new FlexTable(); 594 595 final Fault faultDetails = faultHistory.fault; 596 597 int timeSpentOnFault = 0; 598 599 // Now take the data and build a nice information panel 600 // which contains all of the details of the fault. 601 602 faultDescriptionTable.setText(0,0,internationalizationConstants.description()); 603 formatter.setStyleName(0,0,"SearchResultsTableBanner"); 604 605 faultDescriptionTable.setHTML(1,0,faultDetails.description); 606 faultDescriptionTable.setStyleName("SearchResultsDetails"); 607 608 // Now for the full specific details of the fault which 609 // are displayed within a table underneath the 610 // description. 611 612 faultDescriptionTable.setWidget(2,0,faultSpecificsTable); 613 formatter.setStyleName(2,0,"SearchResultsDetails"); 614 615 // The first row of the table which contains all of the 616 // details of the fault 617 618 faultSpecificsTable.setStyleName("SearchResultsFaultSpecificsTable"); 619 620 faultSpecificsTable.setHTML(0,0,internationalizationConstants.assignedTo()); 621 faultSpecificsTable.setHTML(0,1,FaultDBForm.createEmailLink(faultDetails.assignedToEmail,faultDetails.id,faultDetails.title, 622 faultDetails.assignedToName + " " + faultDetails.assignedToSurname)); 623 624 faultSpecificsTable.setHTML(0,2,internationalizationConstants.dutyTechnician()); 625 faultSpecificsTable.setHTML(0,3,FaultDBForm.createEmailLink(faultDetails.dutyTechnicianEmail,faultDetails.id,faultDetails.title, 626 faultDetails.dutyTechnicianName + " " + faultDetails.dutyTechnicianSurname)); 627 628 faultSpecificsTable.setHTML(0,4,internationalizationConstants.supportAstronomer()); 629 faultSpecificsTable.setHTML(0,5,FaultDBForm.createEmailLink(faultDetails.supportAstronomerEmail,faultDetails.id,faultDetails.title, 630 faultDetails.supportAstronomerName + " " + faultDetails.supportAstronomerSurname)); 631 632 faultSpecificsTable.setHTML(0,6,internationalizationConstants.telescopeOperator()); 633 faultSpecificsTable.setHTML(0,7,FaultDBForm.createEmailLink(faultDetails.telescopeOperatorEmail,faultDetails.id,faultDetails.title, 634 faultDetails.telescopeOperatorName + " " + faultDetails.telescopeOperatorSurname)); 635 636 // The second row of the fault which contains all of the 637 // details of the fault 638 639 faultSpecificsTable.setHTML(1,0,internationalizationConstants.priority()); 640 faultSpecificsTable.setHTML(1,1,Integer.toString(faultDetails.priority)); 641 642 faultSpecificsTable.setHTML(1,2,internationalizationConstants.observer()); 643 644 if (faultDetails.observer == null || faultDetails.observer.equals("")) { 645 faultSpecificsTable.setHTML(1,3,internationalizationConstants.unknown()); 646 } else { 647 faultSpecificsTable.setHTML(1,3,faultDetails.observer); 648 } 649 650 faultSpecificsTable.setHTML(1,4,internationalizationConstants.system()); 651 faultSpecificsTable.setHTML(1,5,faultDetails.system); 652 653 faultSpecificsTable.setHTML(1,6,internationalizationConstants.instrument()); 654 faultSpecificsTable.setHTML(1,7,faultDetails.instrument); 655 656 faultSpecificsTable.setWidth("100%"); 657 658 // Third row of the fault contains the time and date that 659 // the fault occured. 660 661 faultSpecificsTable.setHTML(2,0,internationalizationConstants.timeOccured()); 662 faultSpecificsTable.setHTML(2,1,faultDetails.timeOccured); 663 664 faultSpecificsTable.setHTML(2,2,internationalizationConstants.dateOccured()); 665 faultSpecificsTable.setHTML(2,3,faultDetails.dateOccured); 666 667 faultSpecificsTable.setHTML(2,4,internationalizationConstants.assignedDate()); 668 669 if (faultDetails.assignedDate == null) { 670 faultSpecificsTable.setHTML(2,5,internationalizationConstants.unknown()); 671 } else { 672 faultSpecificsTable.setHTML(2,5,faultDetails.assignedDate); 673 } 674 675 faultSpecificsTable.setWidth("100%"); 676 677 // Now for the comments which have been added to the fault 678 679 int currentRow = 3; 680 681 // Now add the details of the workaround to the fault if 682 // there is one 683 684 final Workaround faultWorkAround = faultHistory.workAround; 685 686 if (faultWorkAround != null) { 687 688 faultDescriptionTable.setText(currentRow,0,internationalizationConstants.workAround() + " " + internationalizationConstants.by() + " " + faultWorkAround.enteredByName + " " + 689 faultWorkAround.enteredBySurname + " " + internationalizationConstants.onThe() + " " + faultWorkAround.dateEntered 690 + " " + internationalizationConstants.spent() + " " + faultWorkAround.timeSpent + " (HH:MM)"); 691 692 faultDescriptionTable.setHTML(currentRow+1,0,faultWorkAround.description); 693 694 formatter.setStyleName(currentRow,0,"SearchResultsTitle"); 695 formatter.setStyleName(currentRow+1,0,"SearchResultsDetails"); 696 697 // Calculate the amount of time spent on the fault 698 699 timeSpentOnFault += convertTimeToMinutes(faultWorkAround.timeSpent); 700 701 currentRow += 2; 702 } 703 704 final ArrayList faultComments = faultHistory.comments; 705 706 for (int i=0; i < faultComments.size(); i++) { 707 708 final Comment comment = (Comment)faultComments.get(i); 709 710 faultDescriptionTable.setText(currentRow,0,internationalizationConstants.comment() + " " + internationalizationConstants.by() + " " + comment.enteredByName + " " + 711 comment.enteredBySurname + " " + internationalizationConstants.onThe() + " " + comment.dateEntered + " " + 712 internationalizationConstants.spent() + " " + comment.timeSpent + " (HH:MM)"); 713 714 faultDescriptionTable.setHTML(currentRow+1,0,comment.description); 715 716 // Calculate the amount of time spent on the fault 717 718 timeSpentOnFault += convertTimeToMinutes(comment.timeSpent); 719 720 formatter.setStyleName(currentRow,0,"SearchResultsTitle"); 721 formatter.setStyleName(currentRow+1,0,"SearchResultsDetails"); 722 723 currentRow +=2; 724 } 725 726 // Now add the details of the soluton to the fault if 727 // there is one 728 729 final Solution faultSolution = faultHistory.solution; 730 731 if (faultSolution != null) { 732 faultDescriptionTable.setText(currentRow,0,internationalizationConstants.solution() + " " + internationalizationConstants.by() + " " + faultSolution.enteredByName + " " + 733 faultSolution.enteredBySurname + " " + internationalizationConstants.onThe() + " " + faultSolution.dateEntered + " " + 734 internationalizationConstants.spent() + " " + faultSolution.timeSpent + " (HH:MM)"); 735 736 faultDescriptionTable.setHTML(currentRow+1,0,faultSolution.description); 737 738 formatter.setStyleName(currentRow,0,"SearchResultsTitle"); 739 formatter.setStyleName(currentRow+1,0,"SearchResultsDetails"); 740 741 timeSpentOnFault += convertTimeToMinutes(faultSolution.timeSpent); 742 743 currentRow += 2; 744 } 745 746 // Now we add the details of the linked faults if there 747 // are any to be displayed 748 749 final ArrayList linkedFaults = faultHistory.links; 750 751 if (linkedFaults != null) { 752 753 for (int i=0; i < linkedFaults.size(); i++) { 754 755 final Fault fault = (Fault)linkedFaults.get(i); 756 757 // If we have not already added a banner which 758 // declares the linked faults then do so now 759 760 faultDescriptionTable.setText(currentRow,0,internationalizationConstants.linkToFault() + " " + Integer.toString(fault.id) + 761 " " + internationalizationConstants.enteredByPhrase() + " " + getFullUserNameFromEmailAddress(fault.enteredByEmail) + 762 " " + internationalizationConstants.onThe() + " " + fault.dateEntered); 763 764 formatter.setStyleName(currentRow,0,"SearchResultsTitle"); 765 766 // Now add the details of the fault which is linked to this fault 767 768 faultDescriptionTable.setHTML(currentRow+1,0,fault.description); 769 770 tableRowFormatter.setStyleName(currentRow+1,"SearchResultsDetails"); 771 772 currentRow += 2; 773 774 } 775 } 776 777 // Now embed the table into the panel 778 779 panel.setContent(faultDescriptionTable); 780 781 faultDescriptionTable.setWidth("100%"); 782 } 783 784 /** 785 * Used to convert the HH:MM field into minutes expressed as 786 * an integer. 787 * @param TimeAmount Time expressed in HH:MM 788 * @return int The amount expressed in minutes 789 */ 790 791 int convertTimeToMinutes(final String TimeAmount) { 792 return Integer.parseInt(TimeAmount.substring(0,1)) * 60 + Integer.parseInt(TimeAmount.substring(3,4)); 793 } 794 795 /** 796 * Don't do anything when the disclosure panel is closed by 797 * the user. Obligation of the interface that we have to 798 * implement. 799 * @param DisclosureEvent The type of event. 800 */ 801 802 public void onClose (final DisclosureEvent event) { 803 } 804 805 /** 806 * This is the constructor for the class. 807 */ 808 809 DisplayFullFault (final int FaultNumber) { 810 this.FaultNumber = FaultNumber; 811 } 812 813 /** 814 * This method will be used to get the full details of this 815 * fault back from the database and then display them in the 816 * content panel of the disclosure panel which is associated 817 * with this fault. 818 */ 819 820 private void getFaultDetails() { 821 822 noOfSubTasksCompleted = 0 ; 823 824 // Now get the full details of this fault from the 825 // servlet 826 827 svc.getFullFaultHistory (FaultNumber, internationalizationConstants.locale(),new AsyncCallback() { 828 829 public void onSuccess (Object result) { 830 faultHistory = (FaultEntryDetails)result; 831 noOfSubTasksCompleted++; 832 } 833 834 public void onFailure (Throwable ex){ 835 MessageBox.alert(internationalizationConstants.information(),internationalizationConstants.unableToFindFaultInDatabase(FaultNumber)); 836 } 837 }); 838 } 839 840 /** 841 * This will be called with the details of the updated fault 842 * history and will result in the details in the disclosure 843 * panel being updated. 844 * @param faultHistory Containsthe details of the fault 845 */ 846 847 public void updateDisclosurePanel(final FaultEntryDetails faultHistory) { 848 849 this.faultHistory = faultHistory; 850 851 // Now update the disclosure panel to contain the details 852 // of the new fault history 853 854 createFaultDisclosurePanelContent(); 855 panelInitialised = true; 856 } 857 858 } // End of class DisplayFullFault 859 860 /** 861 * Inner class which is used to allow the user to print out a 862 * fault should he wish to 863 */ 864 865 class PrintFaultClickListener implements ClickListener { 866 867 /** 868 * This is the instance of the print dialogue which will be 869 * used by this user to select the printer that he wants to be 870 * used to print the fault. 871 */ 872 873 private PrintFaultDialog printFaultDialog; 874 875 /** 876 * This is the fault number which will be printed by this 877 * instance of the dialog. 878 */ 879 880 final private int FaultNumber; 881 882 /** 883 * Constructor 884 */ 885 886 PrintFaultClickListener(final int FaultNumber) { 887 this.FaultNumber = FaultNumber; 888 } 889 890 /** 891 * Callback method which is called when the user clicks on a 892 * print fault link 893 * @param sender The widget which resulted in this callback 894 * being called. 895 */ 896 897 public void onClick (final Widget sender) { 898 899 // Create the dialog which the user will use to select the 900 // printer 901 902 try { 903 printFaultDialog = new PrintFaultDialog(svc); 904 } catch (Exception e) { 905 return; 906 } 907 908 printFaultDialog.showPrintDialog(FaultNumber); 909 } 910 } 911 912 /** 913 * An inner class which is called when the user presses the 914 * modification link and will result in the modification panel 915 * being called and being set up with the details of the fault 916 * which has been selected being available to be modified. 917 */ 918 919 class ModifyFaultClickListener implements ClickListener { 920 921 /** 922 * The tab panel which contains the faults which are currently 923 * being updated 924 */ 925 926 final private ModifyFormPanel ModifyFormPage; 927 928 /** 929 * This is the fault number of the fault which this object is associated with 930 */ 931 932 final private int FaultNumber; 933 934 /** 935 * This is the main tab panel of the application 936 */ 937 938 final private TabPanel MainTabPanel; 939 940 ModifyFaultClickListener(final int FaultNumber, final ModifyFormPanel ModifyFormPage,final TabPanel MainTabPanel) { 941 this.ModifyFormPage = ModifyFormPage; 942 this.FaultNumber = FaultNumber; 943 this.MainTabPanel = MainTabPanel; 944 } 945 946 /** 947 * Callback method which is called when the user clicks on a 948 * print fault link 949 * @param sender This is the widget that caused this event to be raised. 950 */ 951 952 public void onClick (final Widget sender) { 953 954 // Now add a panel to the update fault panel which will 955 // allow the user to update the fault. 956 957 ModifyFormPage.addNewFaultTab(FaultNumber); 958 959 // Now select the update fault tab so that the user is 960 // selected with the fault that he wishes to edit 961 962 MainTabPanel.selectTab(0); 963 } 964 } 965 966 /** 967 * An inner class which will allow the user to close down a 968 * fault. This is a listener class which is called when the user 969 * clicks upon the close fault link in the search results. 970 * @author Craige Bevil 971 * @version $Id: SearchResultFormatter.java,v 1.26 2007/12/17 12:26:40 cb Exp $ 972 */ 973 974 class CloseFaultClickListener implements ClickListener { 975 976 /** 977 * This is the fault number which is associated with the fault 978 * to be closed 979 */ 980 981 final private int faultNumber; 982 983 /** 984 * This is the panel which is being used to update 985 * faults. Before we allow the user to close down a fault we need 986 * to make sure that he is not editing it. 987 */ 988 989 final private ModifyFormPanel modifyFormPage; 990 991 /** 992 * This is the update link which is associated with a fault. 993 */ 994 995 Hyperlink updateLink; 996 997 /** 998 * Constructor 999 */ 1000 1001 public CloseFaultClickListener (final int faultNumber,final ModifyFormPanel ModifyFormPage, final Hyperlink UpdateLink) { 1002 this.faultNumber = faultNumber; 1003 this.modifyFormPage = ModifyFormPage; 1004 this.updateLink = UpdateLink; 1005 } 1006 1007 /** 1008 * Called when the user clicks upon the close fault link and 1009 * results in the fault being closed down in the database. We 1010 * only allow the user to close down a fault if he is not 1011 * editing it. 1012 * @param sender This is the widget which resulted in this 1013 * event being fired. 1014 */ 1015 1016 public void onClick (final Widget sender) { 1017 1018 // Check to make sure that the user is not editing the 1019 // fault at the moment and if so warn him to stop editing 1020 // it otherwise the user can edit a fault after it has 1021 // been closed down. Not good. 1022 1023 if (modifyFormPage.isFaultBeingEdited(faultNumber)) { 1024 MessageBox.alert(internationalizationConstants.information(),"Fault " + faultNumber + " is currently being edited, you cannot close it down at present"); 1025 return; 1026 } 1027 1028 MessageBox.confirm(internationalizationConstants.confirm(),"Are you sure you want to close fault " + faultNumber + "?", new MessageBox.ConfirmCallback() { 1029 1030 public void execute(final String btnID) { 1031 1032 if ("yes".equals(btnID)) { 1033 1034 svc.closeFault (faultNumber,new AsyncCallback() { 1035 1036 public void onSuccess (Object result) { 1037 1038 // If are succesful then remove 1039 // the update link and the close 1040 // link which was associated with 1041 // the fault. Unfortunately this 1042 // does not affect all of the 1043 // other the search views across 1044 // the system. 1045 1046 sender.removeFromParent(); 1047 1048 if (updateLink != null) { 1049 updateLink.removeFromParent(); 1050 } 1051 } 1052 1053 public void onFailure (Throwable ex){ 1054 MessageBox.alert(internationalizationConstants.information(),"Unable to close down fault " + faultNumber + " " + ex.getMessage()); 1055 } 1056 }); 1057 } 1058 } 1059 }); 1060 } 1061 } 1062 1063 /** 1064 * An inner class which is called when the user presses the link 1065 * fault link which will result in a dialog being displayed within 1066 * which the user can enter the id of a fault to link this fault 1067 * to. 1068 * @author Craige Bevil 1069 */ 1070 1071 class FaultLinkClickListener implements ClickListener { 1072 1073 private LinkFaultDialog linkfaultDialog; 1074 1075 private DisplayFullFault faultDisplayer; 1076 1077 private int faultNumber; 1078 1079 public FaultLinkClickListener(int faultNumber,DisplayFullFault faultDisplayer) { 1080 this.faultNumber = faultNumber; 1081 this.faultDisplayer = faultDisplayer; 1082 } 1083 1084 public void onClick (Widget sender) { 1085 faultDisplayer.setPanelInitialised(false); 1086 linkfaultDialog = new LinkFaultDialog(svc); 1087 linkfaultDialog.showLinkDialog(faultNumber); 1088 } 1089 } 1090 1091 /** 1092 * An inner class which is called when the user presses the link 1093 * which allows him to receive updates when the fault is updated 1094 * in the database 1095 * @author Craige Bevil 1096 */ 1097 1098 class GetEmailUpdateClickListener implements ClickListener { 1099 1100 private int faultNumber; 1101 1102 public GetEmailUpdateClickListener(int faultNumber) { 1103 this.faultNumber = faultNumber; 1104 } 1105 1106 public void onClick (Widget sender) { 1107 1108 // Get verification from the user that he wants to add his 1109 // name to the list of people that will get email updates. 1110 1111 MessageBox.confirm(internationalizationConstants.confirm(),internationalizationConstants.confirmationGetEmailUpdate(Integer.toString(faultNumber)), new MessageBox.ConfirmCallback() { 1112 1113 public void execute(String btnID) { 1114 1115 if ("yes".equals(btnID)) { 1116 1117 // If the user does want to add his email address to 1118 // the list of people getting email updates for this 1119 // fault then we add it to the database 1120 1121 1122 svc.registerForFaultUpdates (UserAuthentication.UserEmailAddress,faultNumber,new AsyncCallback() { 1123 1124 public void onSuccess (Object result) { 1125 } 1126 1127 public void onFailure (Throwable ex){ 1128 MessageBox.alert(internationalizationConstants.information(),"Unable to register email address " + UserAuthentication.UserEmailAddress + " for updates on fault " + faultNumber); 1129 } 1130 }); 1131 }}}); 1132 } 1133 } 1134 1135 /** 1136 * Formats the results of the search query and displays them in 1137 * the table which was passed into the method. 1138 * @param searchResults This is a collection of the type Fault 1139 * which will contain all of the data from the search query. 1140 * @param MainTabPanel This is the main tab panel 1141 */ 1142 1143 public void displaySearchResults(final ArrayList searchResults,final TabPanel MainTabPanel) { 1144 1145 this.MainTabPanel = MainTabPanel; 1146 1147 // We add the entries into the search result table as a 1148 // deferred command so that the user can see something 1149 // happening on the display 1150 1151 DeferredCommand.addCommand(new DisplaySearchResultsIncrementalCommand(searchResults)); 1152 } 1153 1154 /** 1155 * Used to insert the details of a fault into results table at the 1156 * row specified. 1157 * @param fault The fault to insert into the table. 1158 * @param rowToModify The row number in the ttable which are to 1159 * modify should updateExistingRow be set to true. 1160 * @param updateExistingRow True if we are to update an existing 1161 * row in the table. 1162 * @param insertAtHeadOfResults True if to insert the fault at the 1163 * head of the table. Used for inserting new faults which are 1164 * added after the initial search page is created. 1165 */ 1166 1167 private void putFaultIntoResultsTable (final Fault fault, 1168 int rowToModify, 1169 final boolean updateExistingRow, 1170 final boolean insertAtHeadOfResults) { 1171 1172 final DisplayFullFault faultDisplayer = new DisplayFullFault(fault.id); 1173 1174 // Remember the highest fault id which is displayed in the 1175 // table as we only add faults with id higher than this when 1176 // we do real-time updates to the table otherwise we could add 1177 // old faults which have been modified by the user to the head 1178 // of the table. 1179 1180 if (fault.id > HighestDefectNoInTable) { 1181 HighestDefectNoInTable = fault.id; 1182 } 1183 1184 // If we are inserting a new row then we add it at the head of 1185 // the display 1186 1187 if (insertAtHeadOfResults) { 1188 1189 rowToModify = HEADOFTABLE; 1190 1191 ResultsTable.insertRow(HEADOFTABLE); 1192 1193 // Now we need to update the fault-row mapping hash which 1194 // has been thrown out of kilter by adding a new fault at 1195 // the head of the table. We increment all of the table 1196 // rows which are associated with the faults by one as we 1197 // have pushed them down the table by adding the new 1198 // fault at the head of the table 1199 1200 final Iterator mappingIndex = faultTableRowMapping.keySet().iterator(); 1201 1202 HashMap tempHashMap = new HashMap(); 1203 1204 while (mappingIndex.hasNext()) { 1205 1206 Integer mappingKey = (Integer)mappingIndex.next(); 1207 1208 tempHashMap.put(mappingKey,new Integer(((Integer)faultTableRowMapping.get(mappingKey)).intValue() + 2)); 1209 } 1210 1211 faultTableRowMapping = tempHashMap; 1212 1213 // Add the new fault to the mapping in row 1 1214 1215 faultTableRowMapping.put(new Integer(fault.id),new Integer(1)); 1216 1217 } else if (!updateExistingRow) { 1218 1219 // If we are not updating an existing row then we have to 1220 // create a new one 1221 1222 ResultsTable.insertRow(rowToModify); 1223 } 1224 1225 // Add the fault identifier as a link so it can be cut and 1226 // pasted by the user. 1227 1228 ResultsTable.setWidget(rowToModify,0,new HTML("<a href=\"DisplayFaultDetails.fmsc?FaultId=" + Integer.toString(fault.id) + "\" TARGET=\"_blank\">" + Integer.toString(fault.id) + "</a>")); 1229 1230 if (fault.faultType.equals("T&I")) { 1231 fault.faultType = "T&I"; 1232 } 1233 1234 ResultsTable.setHTML(rowToModify,1,fault.faultType); 1235 ResultsTable.setHTML(rowToModify,2,fault.severity); 1236 ResultsTable.setHTML(rowToModify,3,fault.timeEntered + " " + fault.dateEntered); 1237 1238 ResultsTable.setHTML(rowToModify,4,FaultDBForm.createEmailLink(fault.enteredByEmail,fault.id,fault.title, fault.enteredByName + " " + fault.enteredBySurname)); 1239 ResultsTable.setHTML(rowToModify,5,fault.site); 1240 ResultsTable.setHTML(rowToModify,6,fault.instrument); 1241 ResultsTable.setHTML(rowToModify,7,fault.timeLost); 1242 ResultsTable.setHTML(rowToModify,8,fault.state); 1243 ResultsTable.setHTML(rowToModify,9,fault.totalTimeSpentOnFault); 1244 1245 // Set the style of the row 1246 1247 resultsTableRowFormatter.setStyleName(rowToModify,"quickViewFaultDetailRow"); 1248 1249 // Now add in the actions which the user can perform on a 1250 // fault. He can only perform some of the actions if he 1251 // has the appropriate priviledge level 1252 1253 // Give the user the option of being able to print out the 1254 // fault 1255 1256 final HorizontalPanel actionPanel = new HorizontalPanel(); 1257 1258 actionPanel.setStyleName("quickViewRowLinkCell"); 1259 1260 Hyperlink printFaultLink; 1261 1262 printFaultLink = new Hyperlink(internationalizationConstants.print(),true,Integer.toString(fault.id)); 1263 printFaultLink.setStyleName("quickViewRowLinkCell"); 1264 1265 PrintFaultClickListener printFaultClickListener = new PrintFaultClickListener(fault.id); 1266 1267 printFaultLink.addClickListener(printFaultClickListener); 1268 1269 actionPanel.add(printFaultLink); 1270 1271 // Various actions can only be performed by the user if he has adequate priviledge. 1272 1273 if (userCanModifyFaults) { 1274 1275 Hyperlink updateFaultLink,linkFaultLink,getUpdatesLink,closeFaultLink; 1276 1277 // Create a hyper link which the user will use to modify 1278 // the fault with if the fault is currently open 1279 1280 updateFaultLink = null; 1281 1282 if (fault.faultOpen) { 1283 updateFaultLink = new Hyperlink(internationalizationConstants.update(),true,Integer.toString(fault.id)); 1284 updateFaultLink.setStyleName("quickViewRowLinkCell"); 1285 1286 final ModifyFaultClickListener modifyFaultClickListener = new ModifyFaultClickListener(fault.id,ModifyFormPage,MainTabPanel); 1287 1288 updateFaultLink.addClickListener(modifyFaultClickListener); 1289 } 1290 1291 // If the fault is open then the user can close it down if 1292 // he has admin priviledges. 1293 1294 closeFaultLink = null; 1295 1296 if (hasAdminPriviledge && fault.faultOpen) { 1297 1298 closeFaultLink = new Hyperlink(internationalizationConstants.close(),true,Integer.toString(fault.id)); 1299 closeFaultLink.setStyleName("quickViewRowLinkCell"); 1300 1301 final CloseFaultClickListener closeFaultClickListener = new CloseFaultClickListener(fault.id,ModifyFormPage,updateFaultLink); 1302 1303 closeFaultLink.addClickListener(closeFaultClickListener); 1304 } 1305 1306 // Now add a link which will allow the user to link a fault to another fault 1307 1308 linkFaultLink = new Hyperlink(internationalizationConstants.link(),true,Integer.toString(fault.id)); 1309 1310 FaultLinkClickListener faultLinkClickListener = new FaultLinkClickListener(fault.id,faultDisplayer); 1311 1312 linkFaultLink.addClickListener(faultLinkClickListener); 1313 linkFaultLink.setStyleName("quickViewRowLinkCell"); 1314 1315 // Now add a link which will allow the user to get 1316 // email updates from the system 1317 1318 getUpdatesLink = new Hyperlink(internationalizationConstants.monitor(),true,Integer.toString(fault.id)); 1319 1320 GetEmailUpdateClickListener getEmailClickListener = new GetEmailUpdateClickListener(fault.id); 1321 1322 getUpdatesLink.addClickListener(getEmailClickListener); 1323 getUpdatesLink.setStyleName("quickViewRowLinkCell"); 1324 1325 actionPanel.add(linkFaultLink); 1326 actionPanel.add(getUpdatesLink); 1327 1328 // If there is a link which will allow the user to 1329 // update the fault then add it in 1330 1331 if (updateFaultLink != null) { 1332 actionPanel.add(updateFaultLink); 1333 } 1334 1335 // If there is a link which will allow the user to 1336 // close the fault then add it in 1337 1338 if (closeFaultLink != null) { 1339 actionPanel.add(closeFaultLink); 1340 } 1341 1342 } 1343 1344 // Now add the actions panel into the table 1345 1346 ResultsTable.setWidget(rowToModify,10,actionPanel); 1347 1348 // Now create a row which includes the details of the 1349 // title which is a disclosure box which can be then used 1350 // to access the full details of the fault 1351 1352 if (!updateExistingRow) { 1353 1354 DisclosurePanel faultDisclosurePanel = new DisclosurePanel(fault.title); 1355 1356 // Add an event handler which will be called when the user 1357 // opens the disclosure panel and will result in the full 1358 // text of the fault being displayed. 1359 1360 faultDisclosurePanel.addEventHandler(faultDisplayer); 1361 faultDisclosurePanel.setWidth("100%"); 1362 1363 // Store the fault displayer against the fault number 1364 // which it is associated 1365 1366 faultDisplayers.put(new Integer(fault.id),faultDisplayer); 1367 1368 ResultsTable.insertRow(rowToModify+1); 1369 1370 ResultsTable.setWidget(rowToModify+1,0,faultDisclosurePanel); 1371 1372 resultsTableCellFormatter.setColSpan(rowToModify+1,0,11); 1373 1374 } else { 1375 1376 // Update the disclosure panel which is already in that 1377 // cell. 1378 1379 final DisclosurePanel faultDisclosurePanel = (DisclosurePanel)ResultsTable.getWidget(rowToModify+1,0); 1380 1381 faultDisclosurePanel.getHeaderTextAccessor().setText(fault.title); 1382 } 1383 } 1384 1385 /** 1386 * This will be used to set the table into which the results 1387 * will be displayed 1388 * @param ResultsTable The flex table into which to pack the results 1389 */ 1390 1391 public void setResultsTable (final FlexTable ResultsTable) { 1392 1393 if (ResultsTable == null) { 1394 return; 1395 } 1396 1397 this.ResultsTable = ResultsTable; 1398 this.resultsTableCellFormatter = (FlexCellFormatter)ResultsTable.getCellFormatter(); 1399 this.resultsTableRowFormatter = (RowFormatter)ResultsTable.getRowFormatter(); 1400 } 1401 1402 /** 1403 * Will be used to set the state of the all of the disclosure 1404 * panel states in the table to either open or closed. 1405 * @param openAll Whether all of the faults should be 1406 * opened 1407 */ 1408 1409 public void setDisclosurePanelState (final boolean openAll) { 1410 1411 for (int i= 0; i < ResultsTable.getRowCount(); i++) { 1412 1413 // Now go through each of the rows in the result table and 1414 // if the widget is a disclosure panel then we close it 1415 1416 final DisclosurePanel tmp; 1417 1418 try { 1419 tmp = (DisclosurePanel)ResultsTable.getWidget(i,0); 1420 tmp.setOpen(openAll); 1421 } catch (Exception e) { 1422 ; 1423 } 1424 } 1425 } 1426 1427 /** 1428 * Constructor for the class 1429 * @param resultsTable This is a FlexTable widget into which the 1430 * results of the search will be displayed. 1431 * @param modifyFormPage This is the page which can be used to 1432 * modify the details of a fault. 1433 * @param UserAuthentication Login credentials of the person that 1434 * is using the system. 1435 * @param svc This is object which will be used to execute 1436 * operations on the tomcat servlet. 1437 */ 1438 1439 SearchResultFormatter (final FlexTable resultsTable, 1440 final ModifyFormPanel modifyFormPage, 1441 final AuthenticationDetails UserAuthentication, 1442 final FaultServiceAsync svc, 1443 final InternationalizationConstants internationalizationConstants, 1444 final FaultUpdateMonitor faultUpdateMonitor) { 1445 1446 setResultsTable(resultsTable); 1447 1448 this.ModifyFormPage = modifyFormPage; 1449 this.UserAuthentication = UserAuthentication; 1450 this.svc = svc; 1451 this.internationalizationConstants = internationalizationConstants; 1452 this.faultUpdateMonitor = faultUpdateMonitor; 1453 1454 // Determine if the user has the authorisation to modify 1455 // faults and if he hasn't then we do not provide the option 1456 // to modify faults 1457 1458 userCanModifyFaults = false; 1459 1460 for (int i=0; i < UserAuthentication.PriviledgeLevels.size();i++) { 1461 if (((String)UserAuthentication.PriviledgeLevels.get(i)).equalsIgnoreCase(FaultDatabaseConstants.INGUSERPRIVILEDGE)) { 1462 userCanModifyFaults = true; 1463 break; 1464 } 1465 } 1466 1467 // Establish if the user has admin privileges 1468 1469 hasAdminPriviledge = UserAuthentication.hasPriviledgeLevel(FaultDatabaseConstants.ADMINPRIVILEDGE); 1470 1471 // Now register ourself for updates when the faults in the 1472 // database are updated. 1473 1474 faultUpdateMonitor.addListener(this); 1475 } 1476 1477 /** 1478 * This is an obligation of the {@link FaultListener 1479 * FaultListener} interface and is 1480 * called whenever one of the faults in the table that we are 1481 * displaying is changed in the database and then we update the 1482 * fault in the result displayer. 1483 * @param faultsChanged This is an array of type {@link Fault 1484 * Fault} which 1485 * contains the details of the faults which have changed in the 1486 * database. 1487 * @see FaultListener 1488 * @see FaultUpdateMonitor 1489 */ 1490 1491 public void faultsChanged (final ArrayList faultsChanged) { 1492 1493 // If there are *no* fault which are currently being displayed 1494 // by the search result formatter, we should request that we 1495 // perform a FULL update of the results from the parent of the 1496 // search result formatter if specified. We do that because if 1497 // the list is empty, we don't know if the fault which has 1498 // changed (it could have simply been updated) is actually 1499 // within the time window of the view which is being 1500 // displayed. NOTE 1501 1502 if (HighestDefectNoInTable == UNKNOWN && displayNewFaults) { 1503 searchResultUpdater.refreshResults(); 1504 return; 1505 } 1506 1507 for (int i=0; i < faultsChanged.size() ;i++) { 1508 1509 final FaultEntryDetails faultHistory = (FaultEntryDetails)faultsChanged.get(i); 1510 1511 // If this fault is not in the search results and we have 1512 // been instructed not to display new faults, then we 1513 // should skip to the next updated faults which has been 1514 // returned otherwise we have to insert the new 1515 1516 if (!faultTableRowMapping.containsKey(new Integer(faultHistory.fault.id))) { 1517 1518 if (displayNewFaults) { 1519 1520 // Insert the new fault into the table at the head 1521 // of the table. However, we have to make sure 1522 // that the fault number of this fault is great 1523 // than the one which is currently displayed at 1524 // the head of the table as otherwise, should a 1525 // user update an historic fault, we will add the 1526 // details of a fault which should not be 1527 // displayed in this table. We only add NEW faults 1528 // not old faults which have been updated. 1529 1530 if (faultHistory.fault.id > HighestDefectNoInTable || HighestDefectNoInTable == UNKNOWN) { 1531 putFaultIntoResultsTable(faultHistory.fault,0,false,true); 1532 } 1533 1534 } else { 1535 1536 // If we are not displaying new faults then we 1537 // should skip to the next fault to be displayed. 1538 1539 continue; 1540 } 1541 1542 } else { 1543 1544 // Find the row in the table which this fault maps onto 1545 1546 final Integer rowWithFaultIn = (Integer)faultTableRowMapping.get(new Integer(faultHistory.fault.id)); 1547 1548 // Now update the row in the table to show the updated 1549 // values of the fault 1550 1551 putFaultIntoResultsTable(faultHistory.fault,rowWithFaultIn.intValue(),true,false); 1552 1553 // Now get the panel which is used for displaying the full 1554 // details of the fault in the disclosure panel and tell 1555 // it that it should refresh the next time that it is 1556 // opened 1557 1558 final DisplayFullFault faultDisplayer = (DisplayFullFault)faultDisplayers.get(new Integer(faultHistory.fault.id)); 1559 1560 // Now update the disclosure panel which is associated 1561 // with this row in the search results. 1562 1563 faultDisplayer.updateDisclosurePanel(faultHistory); 1564 } 1565 } 1566 } 1567 1568 /** 1569 * Allows the caller to specify if whether to update search results 1570 * when new faults are created. We don't do this in the case of 1571 * the more selective search results (such as the outstanding 1572 * faults) as that needs specialist SQL. 1573 * @param displayNewFaults True if to add new faults to 1574 * the table. 1575 */ 1576 1577 public void setdisplayNewFaults (final boolean displayNewFaults) { 1578 this.displayNewFaults = displayNewFaults; 1579 } 1580 1581 /** 1582 * This method will be used to clear out any existing results from 1583 * the search result table 1584 */ 1585 1586 public void clearResultTable() { 1587 1588 ResultsTable.clear(); 1589 1590 for (int i= ResultsTable.getRowCount()-1; i >= 0; i--) { 1591 ResultsTable.removeRow(i); 1592 } 1593 } 1594 }