1 /*
2 J-Bird net/sourceforge/jbird/ListSpecies.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.Choice;
10 import java.awt.Color;
11 import java.awt.Cursor;
12 import java.awt.Frame;
13 import java.awt.GridBagConstraints;
14 import java.awt.GridBagLayout;
15 import java.awt.Insets;
16 import java.awt.Label;
17 import java.awt.Panel;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.ActionListener;
20 import java.awt.event.ItemEvent;
21 import java.awt.event.ItemListener;
22 import java.io.IOException;
23 import java.sql.SQLException;
24 import java.text.MessageFormat;
25 import java.text.ParseException;
26 import java.util.ResourceBundle;
27
28 import net.sourceforge.jbird.SpeciesTable;
29 import net.sourceforge.jbird.awt.DateRange;
30 import net.sourceforge.jbird.awt.OrderedChoice;
31 import net.sourceforge.jbird.iface.LogListener;
32 import net.sourceforge.jbird.iface.ObjectListener;
33 import net.sourceforge.jbird.swing.JWait;
34 import net.sourceforge.jbird.util.IntStringArrays;
35
36 /**
37 * MainFrameComponent for generating lists of observed species (e.g., life
38 * lists).
39 * @author Dick Repasky
40 * @since J-Bird 0.1.3
41 *
42 */
43
44 public class ListSpecies extends Panel implements MainFrameComponent {
45
46 /** Index used to store/retrieve component state.
47 @since J-Bird 0.1.3 */
48 public static final int COLUMN_CHOICE = 0;
49 /** Index used to store/retrieve component state.
50 @since J-Bird 0.1.3 */
51 public static final int CELL_CHOICE = 1;
52 /** Index used to store/retrieve component state.
53 @since J-Bird 0.1.3 */
54 public static final int CHECKLIST_CHOICE = 2;
55
56 protected Frame owner;
57
58 protected Label col_label;
59 protected OrderedChoice col_choice;
60
61 protected Label cell_label;
62 protected OrderedChoice cell_choice;
63
64 protected Label checklist_label;
65 /** Use getSelectedIndex() - 1 as subscript to
66 checklist_numbers. */
67 protected Choice checklist_choice;
68 protected int[] checklist_numbers;
69
70 protected QRestrictPanel restrictions;
71
72 protected Button go_button;
73
74 protected SpeciesListQuery list_query;
75
76 protected JBirdOptions jbird_options;
77 protected ResourceBundle progres;
78 protected LogListener log;
79 /** Receives exceptions from SpeciesTableDialog. */
80 protected ObjectListener exception_listener;
81
82 /** Subscripts correspond to awt.DateRange.SAME_* constants. */
83 /* hold for possible future use. search on date_formats.
84 protected static final String[] date_formats = { "dd", // same day
85 "dd", // same month
86 "MM-dd", // same year
87 "yyyy-MM-dd"//multi-year
88 };
89 */
90
91 protected JWait wait_window;
92 public ListSpecies(JbirdDB db, ResourceBundle rb,
93 JBirdOptions jo, LogListener logger,
94 Frame owner) {
95 super();
96 this.owner = owner;
97 progres = rb;
98 log = logger;
99 jbird_options = jo;
100
101 setLayout(new GridBagLayout());
102 GridBagConstraints c = new GridBagConstraints();
103 Insets insets = new Insets(0, 5, 0, 0);
104 c.anchor = GridBagConstraints.WEST;
105 c.insets = insets;
106
107 c.gridx = 0;
108 c.gridy = 0;
109 Panel choice_panel = buildChoices(db, rb);
110 add(choice_panel, c);
111
112 buildGoButton(rb);
113 c.gridy = 2;
114 insets.bottom = 5;
115 add(go_button, c);
116
117 restrictions = new QRestrictPanel(db, rb,
118 jo, logger, owner);
119 c.gridy = 1;
120 c.fill = GridBagConstraints.BOTH;
121 insets.bottom = 0;
122 add(restrictions, c);
123
124 list_query = new SpeciesListQuery(db, rb);
125
126 /** Used when SpeciesTableDialog experiences
127 an IOException. */
128 class ExceptionListener implements ObjectListener {
129 public void receiveObject(Object object) {
130 tableSaveError((IOException)object);
131 }
132 }
133 exception_listener = new ExceptionListener();
134 }
135
136 public final int getSelectedChecklist() {
137 int answer = -1;
138 int choice = checklist_choice.getSelectedIndex() - 1;
139 if (choice >= 0) {
140 answer = checklist_numbers[choice];
141 }
142 return answer;
143 }
144
145 ///////////////////// protected methods below ///////////////////
146
147 protected final Choice buildChecklistChoice(JbirdDB db)
148 throws SQLException {
149 IntStringArrays checklists = db.getChecklists();
150 Choice checklist_choice = new Choice();
151 checklist_choice.add(progres.getString("-NONE-"));
152 checklist_numbers = checklists.inta;
153 int max = checklists.inta.length;
154 for (int idx = 0; idx < max; idx ++) {
155 checklist_choice.add(checklists.stringa[idx]);
156 }
157 return checklist_choice;
158 }
159
160
161 protected final Panel buildChoices(JbirdDB db, ResourceBundle rb) {
162 Panel cp = new Panel();
163 // set up columns
164 int[] colchoiceorder = (int[])
165 rb.getObject("species_list_choice_order");
166 String[] colchoices = (String[])
167 rb.getObject("species_list_choices");
168 col_choice = new OrderedChoice(colchoices, colchoiceorder);
169 col_label = new Label(rb.getString("Table_columns:_species_+"));
170 // set up cells
171 int[] cellchoiceorder = (int[])
172 rb.getObject("species_list_cell_order");
173 String[] cellchoices = (String[])
174 rb.getObject("species_list_cell_choices");
175 cell_choice = new OrderedChoice(cellchoices, cellchoiceorder);
176 cell_label = new Label(rb.getString("Table_cell_values:"));
177
178 checklist_label = new Label(rb.getString("Include_from_checklist:"));
179 try {
180 checklist_choice = buildChecklistChoice(db);
181 }
182 catch (SQLException e) {
183 log.popupError(progres.getString
184 ("Error_reading_checklists"), true);
185 log.error(e.getMessage());
186 }
187
188 cp.setLayout(new GridBagLayout());
189 GridBagConstraints c = new GridBagConstraints();
190 c.anchor = GridBagConstraints.WEST;
191 c.gridx = 0;
192 c.gridy = 0;
193 cp.add(col_label, c);
194 c.gridx = 1;
195 cp.add(col_choice, c);
196
197 c.gridx = 0;
198 c.gridy = 1;
199 cp.add(cell_label, c);
200 c.gridx = 1;
201 cp.add(cell_choice, c);
202
203 if (checklist_choice != null) {
204 c.gridx = 0;
205 c.gridy = 2;
206 cp.add(checklist_label, c);
207 c.gridx = 1;
208 cp.add(checklist_choice, c);
209 }
210 col_choice.selectLogical(SpeciesListQuery.COLUMNS_OBSERVER + 1);
211 cell_choice.selectLogical(SpeciesListQuery.CELL_TYPE_BOOLEAN);
212 if (checklist_choice != null) {
213 checklist_choice.select(0);
214 }
215 col_choice.addItemListener(new ColumnChoiceListener());
216 return cp;
217 }
218
219 protected final void buildGoButton(ResourceBundle rb) {
220 go_button = new Button(rb.getString("GO!"));
221 go_button.addActionListener(new GButtonListener());
222 }
223
224 /**
225 * Build a simple table and dialog that does not contain a
226 * reference column of species. Used when only a list of
227 * species has been requested although it could be used
228 * for tables with multiple columns.
229 *
230 */
231
232 protected final SpeciesTableDialog buildMonoTable(
233 SpeciesTableModel tablemodel,
234 int datespan) {
235 SpeciesTable table = new SpeciesTable(tablemodel);
236 // These are a waste, but you never know when I'll
237 // want to use this method for a multi-column table.
238 //table.setDefaultRenderer(Date.class,
239 //new DateRenderer(new SimpleDateFormat(
240 //date_formats[datespan])));
241 //table.setDefaultRenderer(Boolean.class,
242 //new BooleanRenderer());
243 return new SpeciesTableDialog(owner, table);
244 }
245
246 /**
247 * Build a table and dialog that has a reference column
248 * of species names. Used when the table contains more
249 * columns than just species names.
250 */
251
252 protected final SpeciesTableDialog buildSplitTable(
253 SpeciesTableModel tablemodel,
254 int datespan) {
255 SpeciesDataTable jrctable = new SpeciesDataTable(tablemodel);
256 jrctable.setRefcolWidth(250);
257 jrctable.setBodycolWidths(100);
258 return new SpeciesTableDialog(owner,
259 jrctable,
260 (SpeciesTable)jrctable.getRefcolTable());
261 }
262
263 protected final void columnChoiceChanged() {
264 if (col_choice.getSelectedIndex() == 0) {
265 cell_choice.setEnabled(false);
266 cell_label.setEnabled(false);
267 } else if (! cell_choice.isEnabled()) {
268 cell_choice.setEnabled(true);
269 cell_label.setEnabled(true);
270 }
271 }
272
273
274 protected final void popupWaitWindow() {
275 if (wait_window == null) {
276 wait_window = new JWait(owner,
277 progres.getString("Working"));
278 }
279 wait_window.activate(2000);
280 }
281
282 protected final void pushedGo() {
283 try {
284 restrictions.configure(list_query);
285 }
286 catch(ParseException pe) {
287 log.error("ListSpecies.pushedGo: ParseException - "
288 + pe.getMessage());
289 log.popupError(progres.getString("Date_format"), false);
290 wait_window.setVisible(false);
291 return;
292 }
293 int[] checklists;
294 int checklist = getSelectedChecklist();
295 if (checklist > -1) {
296 checklists = new int[1];
297 checklists[0] = checklist;
298 } else {
299 checklists = null;
300 }
301 int coltype = col_choice.getSelectedLogicalIndex() - 1;
302 int celltype = cell_choice.getSelectedLogicalIndex();
303 SpeciesComparatorSortOrder comp = new SpeciesComparatorSortOrder();
304 SpeciesTableModel tablemodel;
305 try {
306 tablemodel = list_query.query(coltype,
307 celltype,
308 checklists,
309 1, // WORK HERE - common names
310 comp);
311 }
312 catch (SQLException e) {
313 log.error("ListSpecies.pushedGo: SQLException - "
314 + e.getMessage());
315 Object[] oba = new Object[1];
316 oba[0] = e.getMessage();
317 log.popupError(MessageFormat.format(
318 progres.getString("Unanticipated_error"), oba),
319 false);
320 wait_window.setVisible(false);
321 return;
322 }
323 if (tablemodel == null) {
324 log.popupWarning(progres.getString("Empty_query"),
325 false);
326 wait_window.setVisible(false);
327 return;
328 }
329 boolean scientific;
330 if (jbird_options.scientificnames) {
331 scientific = true;
332 } else {
333 scientific = false;
334 }
335 tablemodel.setShowScientific(scientific);
336 tablemodel.setShowFamilies(true);
337 tablemodel.setAllFamiliesVisible(true);
338 tablemodel.setCollapsable(true);
339 int datespan = DateRange.MULTI_YEAR;
340 try {
341 datespan = restrictions.getDateSpan();
342 } catch (ParseException pe) {
343 // fail silently and with default date format
344 }
345 if (datespan <= DateRange.NA) {
346 datespan = DateRange.MULTI_YEAR;
347 }
348 SpeciesTableDialog jtd;
349 if (coltype >= 0) {
350 jtd = buildSplitTable(tablemodel, datespan);
351 } else {
352 jtd = buildMonoTable(tablemodel, datespan);
353 }
354 jtd.localize(progres);
355
356 jtd.center(jtd.getPreferredSize());
357 jtd.setMenuText(progres.getString("File"));
358 jtd.setCloseText(progres.getString("Close"));
359 jtd.setCSVText(progres.getString("Save_as_CSV"));
360 jtd.setHTMLText(progres.getString("Save_as_HTML"));
361 jtd.setFileButton(progres.getString("Accept"));
362 // prepare to handle IOExceptions
363 jtd.setExceptionListener(exception_listener);
364 wait_window.setVisible(false);
365 jtd.setVisible(true);
366 jtd.setNullifyOnClose(true);
367 System.gc();
368 }
369
370 /**
371 * Select checklist using its number in the database.
372 *
373 */
374
375 protected final void selectChecklist(int listno) {
376 int max = checklist_numbers.length;
377 for (int idx = 0; idx < max; idx ++) {
378 if (listno == checklist_numbers[idx]) {
379 checklist_choice.select((idx + 1));
380 return;
381 }
382 }
383 }
384
385 /**
386 * This method is called when the SpeciesTableDialog
387 * experiences an IOException while trying to save
388 * a table as either a CSV file or as an HTML
389 * document.
390 *
391 */
392
393 protected final void tableSaveError(IOException e) {
394 log.popupError(
395 progres.getString("Error_saving_table"), true);
396 log.error(e.getMessage());
397 }
398
399 /////////////////// internal classes below /////////////////////
400
401 class GButtonListener implements ActionListener {
402 public void actionPerformed(ActionEvent e) {
403 popupWaitWindow();
404 Runnable runner = new Runnable() {
405 public void run() {
406 setCursor(Cursor.getPredefinedCursor(
407 Cursor.WAIT_CURSOR));
408 Color fg = go_button.getForeground();
409 Color bg = go_button.getBackground();
410 go_button.setForeground(bg);
411 go_button.setBackground(fg);
412 pushedGo();
413 setCursor(Cursor.getDefaultCursor());
414 go_button.setForeground(fg);
415 go_button.setBackground(bg);
416 }
417 };
418 new Thread(runner).start();
419 }
420 }
421
422 class ColumnChoiceListener implements ItemListener {
423 public void itemStateChanged(ItemEvent e) {
424 columnChoiceChanged();
425 }
426 }
427
428 //////////////// Methods implementing MainFrameComponent
429
430 public void checkOptions() {
431 }
432
433 public void close() {
434 if (wait_window != null) {
435 wait_window.dispose();
436 wait_window = null;
437 }
438 }
439
440 public int getComponentID() {
441 return MainFrame.LISTQUERY;
442 }
443
444 public final MainFrameState getState() {
445 MainFrameState answer = new MainFrameState();
446 return getState(answer);
447 }
448
449 public final MainFrameState getState(MainFrameState template) {
450 template.setComponentType(MainFrame.LISTQUERY);
451 int[] state = new int[3];
452 state[COLUMN_CHOICE] = col_choice.getSelectedLogicalIndex();
453 state[CELL_CHOICE] = cell_choice.getSelectedLogicalIndex();
454 state[CHECKLIST_CHOICE] = getSelectedChecklist();
455 template.setComponentState(MainFrame.LISTQUERY, state);
456 template.setComponentState(MainFrame.QUERY_RESTRICTIONS,
457 restrictions.getState());
458 return template;
459 }
460
461
462 public final void setState(MainFrameState to) {
463 to.setComponentType(MainFrame.LISTQUERY);
464 int[] state = (int[])to.getComponentState(MainFrame.LISTQUERY);
465 if (state != null) {
466 col_choice.selectLogical(state[COLUMN_CHOICE]);
467 cell_choice.selectLogical(state[CELL_CHOICE]);
468 selectChecklist(state[CHECKLIST_CHOICE]);
469 }
470 restrictions.setState(
471 to.getComponentState(MainFrame.QUERY_RESTRICTIONS));
472 }
473
474 public final void checkNameType() {
475 }
476
477 ///// End methods implementing MainFrameComponent
478
479 }
480