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 }