1 /*
2 J-Bird net/sourceforge/jbird/Ticker.java
3
4 Copyright 2001, 2002, 2003 Dick Repasky
5 */
6 package net.sourceforge.jbird;
7
8 import java.awt.Button;
9 import java.awt.Color;
10 import java.awt.Frame;
11 import java.awt.GridBagConstraints;
12 import java.awt.GridBagLayout;
13 import java.awt.Insets;
14 import java.awt.Panel;
15 import java.awt.event.ActionListener;
16 import java.awt.event.ActionEvent;
17 import java.io.IOException;
18 import java.lang.ref.WeakReference;
19 import java.sql.Date;
20 import java.sql.ResultSet;
21 import java.sql.SQLException;
22 import java.text.Collator;
23 import java.text.CollationKey;
24 import java.text.MessageFormat;
25 import java.util.ResourceBundle;
26
27 import net.sourceforge.jbird.JTextEditor;
28 import net.sourceforge.jbird.SpeciesNameIface;
29 import net.sourceforge.jbird.awt.AVQueue;
30 import net.sourceforge.jbird.iface.IntarrayListener;
31 import net.sourceforge.jbird.iface.IntegerListener;
32 import net.sourceforge.jbird.iface.IntegerListenerList;
33 import net.sourceforge.jbird.iface.LogListener;
34
35 /**
36 * Panel that performs ticking for AddEditTicks.
37 * @author Dick Repasky
38 *
39 */
40
41 public class Ticker extends Panel {
42
43 protected Button tickbutton;
44 protected Button annotatebutton;
45 protected Button untickbutton;
46 /** @since J-Bird 0.1.1 */
47 protected Button displaybutton;
48
49 private Insets inset = new Insets(5,5,5,5);
50
51 protected int currentregion = -1;
52 protected int currenttrip = -1;
53 protected Date currentripdate = null;
54 protected int[] currentobservers = null;
55 protected String[] currentobsnames = null;
56 protected int currentspecies = -1;
57
58 // listeners for passively receiving events
59 protected TickRegionListener regionlistener = new TickRegionListener();
60 protected TickTripListener triplistener = new TickTripListener();
61 protected TickObserverListener observerlistener = new TickObserverListener();
62 protected TickSpeciesListener specieslistener = new TickSpeciesListener();
63
64 protected IntegerListenerList specieslisteners = new IntegerListenerList();
65
66 // interface for actively obtaining species names
67 protected SpeciesNameIface speciessource = null;
68
69 protected AVQueue gratifyqueue;
70 protected String[] gratifyitem = new String[3];
71
72 // result messages
73 private String lifemessage;
74 private String regmessage;
75 private String tripmessage;
76 private String alreadymessage;
77 private String failmessage;
78 private String untickmessage;
79 private String nottickdmessage;
80
81 private JbirdDB dbase;
82 private JBirdOptions jbirdoptions;
83 /** @since J-Bird 0.1.1 */
84 private ResourceBundle progres;
85 private Frame owningframe;
86 private ObserverChooser observerchooser;
87 private LogListener log;
88
89 protected JTextEditor texteditor;
90
91 // variables used to
92 // keep track of notes
93 // values initialized to -1
94 // -1 always indicates nothing stored
95 // -2 indicates that species is ticked
96 // but no note exists for it
97
98 // Array of note indices for observers
99 // Contains note corresponding
100 // to same index of currentobservers
101 private int[] currentnotes;
102 // Array of note indices that
103 // corresponds to rows in
104 // the matrix that follows it
105 private int[] noteidx;
106 // Matrix that describes observers
107 // that are associated with notes
108 // rows - note (corresponds to noteidx
109 // columns - contain vector of user
110 // indices
111 private int[][] noteobservers;
112
113 private WeakReference reportref;
114
115 /** Used to record time of calls to popupImage.
116 Set to current time to prevent odd things
117 from happening when differences are
118 recast to int.
119 @since J-Bird 0.1.1 */
120 private long lastcall = System.currentTimeMillis();
121
122
123 /**
124 * Big cheat. Pass the observerchooser so that I can get
125 * the names. IndexedListChooser should have a mechanism
126 * for providing both to listeners.
127 *
128 */
129
130 public Ticker(JbirdDB db, ResourceBundle rb,
131 JBirdOptions jo, LogListener logger, Frame owner,
132 ObserverChooser oc) {
133
134 dbase = db;
135 jbirdoptions = jo;
136 progres = rb;
137 owningframe = owner;
138 log = logger;
139 observerchooser = oc;
140
141 lifemessage = rb.getString("Life_tick_for");
142 regmessage = rb.getString("Region_tick_for");
143 tripmessage = rb.getString("Trip_tick_for");
144 alreadymessage = rb.getString("Already_ticked_for");
145 failmessage = rb.getString("Tick_failed");
146 untickmessage = rb.getString("Untick_for");
147 nottickdmessage = rb.getString("Not_ticked");
148 tickbutton = new Button(rb.getString("Tick"));
149 untickbutton = new Button(rb.getString("Untick"));
150 annotatebutton = new Button(rb.getString("TickAnnotate"));
151 displaybutton = new Button(rb.getString("DisplayTicks"));
152
153 GridBagLayout gridbag = new GridBagLayout();
154 GridBagConstraints c = new GridBagConstraints();
155 c.insets = inset;
156 setLayout(gridbag);
157
158 c.gridwidth = 1;
159 c.gridheight = 1;
160 c.gridx = 0;
161 c.gridy = 0;
162
163 add(tickbutton, c);
164
165 c.gridx = 2;
166 add(annotatebutton, c);
167
168 c.gridx = 3;
169 add(untickbutton, c);
170
171 c.gridx = 4;
172 add(displaybutton, c);
173
174 checkStatus();
175
176 TickButtonListener tickbuttonlistener = new TickButtonListener();
177 tickbutton.addActionListener(tickbuttonlistener);
178
179 UnTickButtonListener untickbuttonlistener = new UnTickButtonListener();
180 untickbutton.addActionListener(untickbuttonlistener);
181
182 annotatebutton.addActionListener(new AnnotateButtonListener());
183 displaybutton.addActionListener(new DisplayButtonListener());
184
185 gratifyqueue = new AVQueue(3000, owner);
186 }
187
188 /**
189 * Return currently selected species, which should be -1
190 * no species is selected.
191 * @since J-Bird 0.1.4
192 *
193 */
194
195 public final int getSelectedSpecies() {
196 return currentspecies;
197 }
198
199 private final void checkStatus() {
200 if (currentregion == -1 || currenttrip == -1 ||
201 currentobservers == null || currentobservers.length == 0 ||
202 currentspecies == -1) {
203 tickbutton.setEnabled(false);
204 untickbutton.setEnabled(false);
205 annotatebutton.setEnabled(false);
206 } else {
207 tickbutton.setEnabled(true);
208 untickbutton.setEnabled(true);
209 annotatebutton.setEnabled(true);
210 }
211 }
212
213 class TickRegionListener implements IntarrayListener {
214 public void receiveIntarray(int[] intarray) {
215 if (intarray == null || intarray.length == 0) {
216 currentregion = -1;
217 } else {
218 currentregion = intarray[0];
219 }
220 checkStatus();
221 }
222 }
223
224 public final IntarrayListener passRegionListener() {
225 return regionlistener;
226 }
227
228 class TickTripListener implements IntarrayListener {
229 public void receiveIntarray(int[] intarray) {
230 if (intarray == null || intarray.length == 0) {
231 currenttrip = -1;
232 currentripdate = null;
233 } else {
234 currenttrip = intarray[0];
235 currentripdate =
236 dbase.getTripDate(currenttrip);
237 }
238 checkStatus();
239 }
240 }
241
242 public final IntarrayListener passTripListener() {
243 return triplistener;
244 }
245
246 class TickObserverListener implements IntarrayListener {
247 public void receiveIntarray(int[] intarray) {
248 currentobservers = (int[])intarray.clone();
249 currentobsnames =
250 observerchooser.picklist.getSelectedItems();
251 checkStatus();
252 }
253 }
254
255 public IntarrayListener passObserverListener() {
256 return observerlistener;
257 }
258
259 class TickSpeciesListener implements IntegerListener {
260 public void receiveInteger (int intvalue) {
261 currentspecies = intvalue;
262 checkStatus();
263 }
264 }
265
266 public final IntegerListener passSpeciesListener() {
267 return specieslistener;
268 }
269
270
271 /**
272 * Tick current species for current observers.
273 *
274 * Logs attempts to retick species
275 *
276 */
277
278 private final void tickSpecies () {
279 tickSpecies(currentobservers, currentobsnames, true);
280 }
281
282 /**
283 * Tick current species for current observers.
284 *
285 * Logs attempts to tick again as indicated.
286 *
287 */
288
289 private final void tickSpecies (boolean logalready) {
290 tickSpecies(currentobservers, currentobsnames, logalready);
291 }
292
293
294 /**
295 * Tick identified observers.
296 * <p>
297 * Called from updateNotes.
298 *
299 */
300
301 private final void tickSpecies (int[] obsnos, String[] obsnames,
302 boolean logalready) {
303 int i;
304 for (i = 0; i < obsnos.length; i++ ) {
305 tickObserver(obsnos[i], obsnames[i], logalready);
306 }
307 if (! hasFocus()) requestFocus();
308 }
309
310 private final void tickObserver(int observer, String obsname,
311 boolean logalready) {
312 int ticktype = dbase.tickType(currentregion, currenttrip,
313 currentripdate, observer, currentspecies);
314 Object[] oba = new Object[1];
315 oba[0] = obsname;
316 String logmessage = null;
317 switch (ticktype) {
318 case 0:
319 // already ticked
320 if (logalready) {
321 logmessage = MessageFormat.format(alreadymessage,
322 oba);
323 log.trace(logmessage);
324 alreadyTicked();
325 }
326 return;
327 case 1:
328 // trip tick
329 logmessage = MessageFormat.format(tripmessage,
330 oba);
331 newTripTick();
332 break;
333 case 2:
334 // region tick
335 logmessage = MessageFormat.format(regmessage, oba);
336 newRegionTick(logmessage);
337 break;
338 case 3:
339 // life tick
340 logmessage = MessageFormat.format(lifemessage,
341 oba);
342 newLifeTick(logmessage);
343 break;
344 default:
345 // internal error
346 log.popupError(MessageFormat.format(failmessage,
347 oba), false);
348 return;
349 }
350 int rc = dbase.tickSpecies(currenttrip, observer, currentspecies);
351 if (rc == 1) {
352 log.trace(logmessage);
353 } else {
354 log.popupError(MessageFormat.format(failmessage, oba), false);
355 }
356 }
357
358 private final void untickSpecies() {
359 int i;
360 Object[] oba = new Object[1];
361 for (i = 0; i < currentobservers.length; i++ ) {
362 String oname = currentobsnames[i];
363 oba[0] = oname;
364 int rc = dbase.untickSpecies(currenttrip,
365 currentobservers[i], currentspecies);
366 if (rc >= 1) {
367 log.trace(MessageFormat.format(untickmessage, oba));
368 } else if (rc == 0) {
369 log.trace(MessageFormat.format(nottickdmessage, oba));
370 } else {
371 log.trace(MessageFormat.format(failmessage, oba));
372 }
373 }
374 if (! hasFocus()) requestFocus();
375 }
376
377 class TickButtonListener implements ActionListener {
378 public void actionPerformed(ActionEvent a) {
379 Color fg = tickbutton.getForeground();
380 Color bg = tickbutton.getBackground();
381 tickbutton.setForeground(bg);
382 tickbutton.setBackground(fg);
383 tickSpecies();
384 tickbutton.setForeground(fg);
385 tickbutton.setBackground(bg);
386 }
387 }
388
389 class UnTickButtonListener implements ActionListener {
390 public void actionPerformed(ActionEvent a) {
391 Color fg = untickbutton.getForeground();
392 Color bg = untickbutton.getBackground();
393 untickbutton.setForeground(bg);
394 untickbutton.setBackground(fg);
395 untickSpecies();
396 untickbutton.setForeground(fg);
397 untickbutton.setBackground(bg);
398 }
399 }
400
401 class AnnotateButtonListener implements ActionListener {
402 public void actionPerformed(ActionEvent a) {
403 Color fg = annotatebutton.getForeground();
404 Color bg = annotatebutton.getBackground();
405 annotatebutton.setForeground(bg);
406 annotatebutton.setBackground(fg);
407 tickAndAnnotateSpecies();
408 annotatebutton.setForeground(fg);
409 annotatebutton.setBackground(bg);
410 }
411 }
412
413 class DisplayButtonListener implements ActionListener {
414 public void actionPerformed(ActionEvent a) {
415 Color fg = displaybutton.getForeground();
416 Color bg = displaybutton.getBackground();
417 displaybutton.setForeground(bg);
418 displaybutton.setBackground(fg);
419 displayTicks();
420 displaybutton.setForeground(fg);
421 displaybutton.setBackground(bg);
422 }
423 }
424
425 private final void newLifeTick(String message) {
426 boolean gratify = false;
427 gratifyitem[0] = null;
428 gratifyitem[1] = null;
429 gratifyitem[2] = null;
430 if (jbirdoptions.lifepopup) {
431 String file = jbirdoptions.lifeimage;
432 if (file != null) {
433 gratifyitem[0] = message;
434 gratifyitem[1] = file;
435 gratify = true;
436 }
437 }
438 if (jbirdoptions.lifesound) {
439 String file = jbirdoptions.lifesoundbite;
440 if (file != null) {
441 gratifyitem[2] = file;
442 gratify = true;
443 }
444 } else { // play trip tick if trip ticks are played
445 if (jbirdoptions.ticksound) {
446 String file = jbirdoptions.ticksoundbite;
447 if (file != null) {
448 gratifyitem[2] = file;
449 gratify = true;
450 }
451 }
452 }
453 if (gratify) {
454 gratifyqueue.add(gratifyitem);
455 }
456 }
457
458 private final void newRegionTick(String message) {
459 boolean gratify = false;
460 gratifyitem[0] = null;
461 gratifyitem[1] = null;
462 gratifyitem[2] = null;
463 if (jbirdoptions.regionpopup) {
464 String file = jbirdoptions.regionimage;
465 if (file != null) {
466 gratifyitem[0] = message;
467 gratifyitem[1] = file;
468 gratify = true;
469 }
470 }
471 if (jbirdoptions.regionsound) {
472 String file = jbirdoptions.regionsoundbite;
473 System.out.println("trip region should play sound");
474 if (file != null) {
475 gratifyitem[2] = file;
476 gratify = true;
477 }
478 } else { // play trip tick if trip ticks are played
479 if (jbirdoptions.ticksound) {
480 String file = jbirdoptions.ticksoundbite;
481 if (file != null) {
482 gratifyitem[2] = file;
483 gratify = true;
484 }
485 }
486 }
487 if (gratify) {
488 gratifyqueue.add(gratifyitem);
489 }
490 }
491
492 private final void newTripTick() {
493 if (jbirdoptions.ticksound) {
494 String file = jbirdoptions.ticksoundbite;
495 if (file != null) {
496 gratifyitem[0] = null;
497 gratifyitem[1] = null;
498 gratifyitem[2] = file;
499 gratifyqueue.add(gratifyitem);
500 }
501 }
502 }
503
504 /**
505 * Play error sound if options allow it.
506 * @since J-Bird 0.1.2
507 *
508 */
509
510 private final void alreadyTicked() {
511 if (jbirdoptions.errorsound) {
512 String file = jbirdoptions.errorsoundbite;
513 if (file != null) {
514 gratifyitem[0] = null;
515 gratifyitem[1] = null;
516 gratifyitem[2] = file;
517 gratifyqueue.add(gratifyitem);
518 }
519 }
520 }
521
522 private final void tickAndAnnotateSpecies() {
523 System.out.println("pressed Tick / Annotate");
524 // tick those puppies
525 tickSpecies(false); // false to not report repeat ticks in log
526 getNoteIndices();
527 checkMissingNotes();
528 //printNoteIndices();
529 updateNotes();
530 if (! hasFocus()) requestFocus();
531 }
532
533 /**
534 * -1's in currentnotes array indicate that no note was
535 * present for a species and that the species was not ticked.
536 * File entries for these observers in the matrix noteobservers.
537 *
538 */
539
540 private final void checkMissingNotes() {
541 int maxi = currentnotes.length;
542 int i;
543 for (i = 0; i < maxi; i++) {
544 if (currentnotes[i] == -1) {
545 if (jbirdoptions.individualnotes == false) {
546 System.out.println("checkMissingNotes: calling fileObserver");
547 fileObserver(-2, currentobservers[i]);
548 } else {
549 System.out.println("checkMissingNotes: calling fileObserverForceNew");
550 fileObserverForceNew(-2, currentobservers[i]);
551 }
552 }
553 }
554 }
555
556 private final void printNoteIndices() {
557 System.out.println("printNoteIndices");
558 if (currentnotes == null) {
559 System.out.println("currentnotes == null");
560 return;
561 }
562 int i;
563 for (i = 0; i < currentnotes.length; i++) {
564 System.out.println("number " + i +
565 "\tcurrentnotes= " + currentnotes[i]);
566 }
567 for (i = 0; i < noteidx.length; i++) {
568 System.out.println("number " +
569 i +
570 "\tnoteidx = " +
571 noteidx[i]);
572 int j = 0;
573 // following commented out for debugging.
574 // while (j < currentnotes.length && noteobservers[i][j] >= 0) {
575 while (j < currentnotes.length) {
576 System.out.println("\t\tobserver = " +
577 noteobservers[i][j]);
578 j++;
579 }
580 }
581 }
582
583 /* When this routine exits the following should exist
584 currentnotes[] - for each observer contains the
585 note index
586 -1 if note the species is not already ticked
587 for the observer and if no note is present
588 -2 if the species is already ticked but no note
589 exists
590 */
591
592 private final void getNoteIndices() {
593 currentnotes = null;
594 noteidx = null;
595 noteobservers = null;
596
597 currentnotes = new int[currentobservers.length];
598 noteidx = new int[currentobservers.length];
599 noteobservers = new int[currentobservers.length]
600 [currentobservers.length];
601 initializeNoteInfo(); // everything to -1
602 ResultSet noters = dbase.getNoteInfo(currenttrip,
603 currentobservers, currentspecies);
604 if (noters == null) {
605 return;
606 }
607 try {
608 noters.beforeFirst();
609 int idxobs = 0;
610 int idxnote = 0;
611 while (noters.next()) {
612 int obsnum = noters.getInt("Observer");
613 int notenum = noters.getInt("NoteNo");
614 if (noters.wasNull() || notenum == 0) {
615 notenum = -2; // tick but no note
616 }
617 fileNote(notenum, obsnum);
618 if (notenum != -2 ||
619 jbirdoptions.individualnotes == false) {
620 System.out.println("calling fileObserver");
621 fileObserver(notenum, obsnum);
622 } else {
623 System.out.println("calling fileObserverForceNew");
624 fileObserverForceNew(notenum, obsnum);
625 }
626 }
627 System.out.println("getNoteIndices: finished extracting");
628 }
629 catch (SQLException e) {
630 dbase.unanticipatedError("Ticker.getNoteIndices: " +
631 e.getMessage());
632 currentnotes = null;
633 noteidx = null;
634 noteobservers = null;
635 return;
636 }
637 finally {
638 dbase.closeSqlQuery(noters);
639 }
640 System.out.println("getNoteIndices: normal return");
641 return;
642 }
643
644 /**
645 * Set all values to -1
646 *
647 */
648
649 private final void initializeNoteInfo() {
650 int len = currentobservers.length;
651 int i,j;
652 for (i = 0; i < len; i++) {
653 currentnotes[i] = -1;
654 noteidx[i] = -1;
655 for (j = 0; j < len; j++) {
656 noteobservers[i][j] = -1;
657 }
658 }
659 }
660
661 /**
662 * Stow the note number that is associated with an
663 * observer
664 *
665 */
666
667 private final void fileNote(int noteno, int observer) {
668 int i = 0;
669 while (observer != currentobservers[i]) {
670 i ++;
671 }
672 currentnotes[i] = noteno;
673 }
674
675 /**
676 * Stow an observer that is associated with a note
677 *
678 */
679
680 private final void fileObserver(int noteno, int observer) {
681
682 // first look up the note
683 int i = 0;
684 while (noteno != noteidx[i] && noteidx[i] != -1) {
685 i ++;
686 }
687 if (noteidx[i] == -1) { // note not seen previously
688 noteidx[i] = noteno;
689 noteobservers[i][0] = observer;
690 return;
691 }
692 int j = 0;
693 while (noteobservers[i][j] != -1 && noteobservers[i][j] !=
694 observer) {
695 j ++;
696 }
697 noteobservers[i][j] = observer;
698 }
699
700 /**
701 * Stow an observer that is associated with a note, but
702 * force the use of a new row in the matrix even if
703 * a row already exists for the specified note number.
704 * <p>
705 * This routine is used only when the note number is -2
706 * indicating that there is not really a note. It is used
707 * to make places in the matrix for notes that must be
708 * created in the data base. For example, if none of the
709 * observers has a note and if options call for each observer
710 * to have a note. In the final matrix all rows will be
711 * associated with note -2 and will have only one column.
712 * The column value will be that of one observer.
713 */
714
715 private final void fileObserverForceNew(int noteno, int observer) {
716
717 // first find the next unclaimed note holder
718 int i = 0;
719 while (noteidx[i] != -1) {
720 i ++;
721 }
722 // file the info
723 noteidx[i] = noteno;
724 noteobservers[i][0] = observer;
725 return;
726 }
727
728 private final void updateNotes() {
729
730 int i = 0;
731 String notes = null;
732 Collator col = Collator.getInstance();
733 while (i < noteidx.length && noteidx[i] != -1) {
734 if (noteidx[i] > 0) { // note exists
735 notes = dbase.getNoteText(noteidx[i]);
736 } else { // new note
737 notes = "<html>\n<head>\n</head>\n<body>\n</body>\n</html>\n";
738 }
739 // checksum for detecting change
740 CollationKey keycheck = col.getCollationKey(notes);
741 // observer numbers and names
742 // associated with note
743 int[] trimmedobs = clipIntArray(noteobservers[i]);
744 String[] trimmednames = correspondingNames(trimmedobs);
745 // be sure editor is ready
746 texteditor.join();
747 texteditor.setText(notes);
748 texteditor.setTitle(buildEditorTitle(trimmednames));
749 texteditor.setVisible(true); // this should block
750 if (texteditor.getDisposition() == 1) { // user clicked save
751 System.out.println("updateNotes: user clicked save");
752 boolean emptydoc = texteditor.isDocumentEmpty();
753 String updatednotes = texteditor.getText();
754 CollationKey newkey = col.getCollationKey(updatednotes);
755 if (newkey.compareTo(keycheck) != 0) { // note changed
756 if (emptydoc) { // delete note
757 dbase.unlinkNDeleteSpeciesNote(currenttrip,
758 currentspecies,
759 trimmedobs);
760 } else if (noteidx[i] > -1) { // update note
761 dbase.updateNoteText(noteidx[i], updatednotes);
762 } else { // add new note
763 int newnumb = dbase.addNewNote(updatednotes);
764 if (newnumb > -1) {
765 dbase.linkSpeciesNote(currenttrip,
766 currentspecies,
767 trimmedobs,
768 newnumb);
769 } else {
770 dbase.unanticipatedError("updateNotes: failed to " +
771 "obtain new note");
772 }
773 }
774 }
775 }
776 i += 1;
777 }
778 }
779
780 /**
781 * Extract leading non-negative values from an array and
782 * return them in a new array that contains no negative trailing
783 * elements.
784 *
785 */
786
787 private final int[] clipIntArray(int[] arra) {
788 int maxi = 0;
789 while (maxi < arra.length && arra[maxi] >= 0) {
790 maxi ++;
791 }
792 int[] answer = new int[maxi];
793 int i;
794 for (i = 0; i < maxi; i++) {
795 answer[i] = arra[i];
796 }
797 return answer;
798 }
799
800 /**
801 * Return a string array of names that correspond
802 * to observer numbers in the argument.
803 *
804 */
805
806 private final String[] correspondingNames(int[] obsnos) {
807 int len = obsnos.length;
808 String[] answer = new String[len];
809 int i;
810 int j;
811 for (i = 0; i < len; i++) {
812 boolean found = false;
813 j = 0;
814 while (!found && j < currentobservers.length) {
815 if (obsnos[i] == currentobservers[j]) {
816 found = true;
817 answer[i] = currentobsnames[j];
818 }
819 j ++;
820 }
821 if (! found) {
822 answer[i] = "";
823 }
824 }
825 return answer;
826 }
827
828 protected void setJTextEditor(JTextEditor ed) {
829 texteditor = ed;
830 }
831
832 protected JTextEditor getJTextEditor() {
833 return texteditor;
834 }
835
836 protected void setSpeciesSource(SpeciesNameIface iface) {
837 speciessource = iface;
838 }
839
840 protected String buildEditorTitle(String[] names) {
841 // start with species name
842 String[] specname = speciessource.getSpeciesName();
843 StringBuffer sb = new StringBuffer()
844 .append(specname[0])
845 .append(":");
846
847 // add observer names
848 for (int i = 0; i < names.length; i++) {
849 sb.append(" ")
850 .append(names[i]);
851 }
852
853 return sb.toString();
854 }
855
856 /**
857 * Display trip ticks in browser. Invoked by listener
858 * when the "Display ticks" button has been pushed.
859 * @since J-Bird 0.1.1
860 *
861 */
862
863 private final void displayTicks() {
864
865 // build reporter if necessary
866 TripReporter reporter = null;
867
868 if (reportref != null) {
869 reporter = (TripReporter)reportref.get();
870 }
871 if (reporter == null) {
872 try {
873 reporter = new TripReporter(dbase, jbirdoptions, progres);
874 }
875 catch(IOException e) {
876 dbase.oneParmMsg(5, "FailDisplayTicks", e.getMessage());
877 displaybutton.setEnabled(false);
878 return;
879 }
880 reporter.setTripInfo(false);
881 reporter.setTripNotes(false);
882 reporter.setCounts(true);
883 reporter.setObservers(true);
884 reporter.setSpeciesNotes(true);
885 reportref = new WeakReference(reporter);
886 }
887 reporter.setCommonNames(!jbirdoptions.scientificnames);
888 reporter.setCommonList(jbirdoptions.commonnamelist);
889 try {
890 reporter.writeReportToBrowser(currenttrip);
891 }
892 catch (Exception e) {
893 dbase.oneParmMsg(5, "FailDisplayTicks", e.getMessage());
894 }
895
896 reporter = null;
897 }
898
899 }