1
2
3
4 package ca.spaz.cron.ui;
5
6 import java.awt.*;
7 import java.awt.event.*;
8 import java.text.*;
9 import java.util.*;
10 import java.util.List;
11
12 import javax.swing.*;
13 import javax.swing.event.*;
14 import javax.swing.table.*;
15
16 import org.apache.log4j.Logger;
17
18 import ca.spaz.cron.CRONOMETER;
19 import ca.spaz.cron.database.*;
20 import ca.spaz.cron.datasource.Datasources;
21 import ca.spaz.cron.summary.NutritionSummaryPanel;
22 import ca.spaz.gui.*;
23 import ca.spaz.util.ImageFactory;
24
25 /***
26 * Shows all data for a particular date
27 *
28 * @todo: Calendar widget to skip to ANY date
29 *
30 * @author davidson
31 */
32 public class DailySummary extends JPanel {
33 private static final Color TITLE_COLOR = new Color(230, 230, 250);
34
35 private static final int FOOD_COL = 0;
36 private static final int AMOUNT_COL = 1;
37 private static final int MEASURE_COL = 2;
38 private static final int CALORIES_COL = 3;
39
40 public class ServingTableModel extends AbstractTableModel {
41
42 private String[] columnNames = { "Food", "Amount", "Measure", "Calories" };
43
44 /***
45 * Logger for this class
46 */
47 private final Logger logger = Logger.getLogger(ServingTableModel.class);
48
49 public Class getColumnClass(int col) {
50 Object o = getValueAt(0, col);
51 if (o != null) {
52 return o.getClass();
53 }
54 return String.class;
55 }
56
57 public int getColumnCount() {
58 return columnNames.length;
59 }
60
61 public String getColumnName(int col) {
62 return columnNames[col].toString();
63 }
64
65 public Serving getServing(int i) {
66 return (Serving) consumed.get(i);
67 }
68
69 public int getRowCount() {
70 return consumed.size();
71 }
72
73 public Object getValueAt(int row, int col) {
74 Serving c = getServing(row);
75 if (c != null) {
76 switch (col) {
77 case FOOD_COL:
78 return c.getFood().getDescription();
79 case CALORIES_COL:
80 double kcals = c.getFood().getMacroNutrients().kcals;
81 return kcalf.format(kcals * c.getGrams()/100.0);
82 case AMOUNT_COL:
83 return kcalf.format(c.getAmount());
84 case MEASURE_COL:
85 return c.getMeasure();
86 }
87 }
88 return "";
89 }
90
91 public boolean isCellEditable(int row, int col) {
92 if (col == AMOUNT_COL) return true;
93 if (col == MEASURE_COL) return true;
94 if (col == CALORIES_COL) return true;
95 return false;
96 }
97
98 public void setValueAt(Object value, int row, int col) {
99 Serving s = getServing(row);
100 if (value == null || s == null) return;
101 if (col == AMOUNT_COL) {
102 double val = Double.parseDouble((String)value);
103 s.setAmount(val);
104 } else if (col == MEASURE_COL) {
105 s.setMeasure((Measure)value);
106 } else if (col == CALORIES_COL) {
107
108 double val = Double.parseDouble((String)value);
109 double kcals = s.getFood().getMacroNutrients().kcals;
110 double grams = val / (kcals/100.0);
111 s.setGrams(grams);
112 }
113 s.updateDatabase();
114 fireTableRowsUpdated(row, row);
115 }
116
117 }
118
119 private class NextAction extends AbstractAction {
120 public NextAction() {
121 super();
122 putValue(Action.SMALL_ICON, new ImageIcon(ImageFactory.getInstance().loadImage("/img/Forward24.gif")));
123 }
124
125 public void actionPerformed(ActionEvent e) {
126 setDate(new Date(curDate.getTime() + ONE_DAY));
127 }
128 }
129
130 private class PrevAction extends AbstractAction {
131
132 public PrevAction() {
133 super();
134 putValue(Action.SMALL_ICON, new ImageIcon(ImageFactory.getInstance().loadImage("/img/Back24.gif")));
135 }
136
137 public void actionPerformed(ActionEvent e) {
138 setDate(new Date(curDate.getTime() - ONE_DAY));
139 }
140 }
141
142 /***
143 * Logger for this class
144 */
145 private static final Logger logger = Logger.getLogger(DailySummary.class);
146
147 private static final long ONE_DAY = 1000 * 60 * 60 * 24;
148
149 private BiomarkerPanel bioMarkerPanel;
150
151 private List consumed = new ArrayList();
152
153 private Date curDate = new Date(System.currentTimeMillis());
154
155 private CRONOMETER cwapp;
156
157 private JComponent dailyTracker;
158
159 private DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
160
161 private JPanel dietPanel;
162
163 private JPanel exercisePanel;
164
165 private DecimalFormat kcalf = new DecimalFormat("######0.0");
166
167 private ServingTableModel model = new ServingTableModel();
168
169 private Action nextAction;
170
171 private JButton nextButton;
172
173 private Action prevAction;
174
175 private JButton prevButton;
176
177 private JTable resultTable;
178
179 private JLabel titleLabel;
180
181 private JPanel toolBar;
182
183 private NutritionSummaryPanel totals;
184
185 private JComboBox measureBox = new JComboBox();
186
187
188 public DailySummary(CRONOMETER cwapp) {
189 this.cwapp = cwapp;
190
191 initialize();
192
193 notifyObservers();
194 }
195
196 public void addServing(Serving c) {
197 c.setDate(curDate);
198 Datasources.getInstance().getMutableDataSource().addServing(c);
199 notifyObservers();
200 }
201
202 /***
203 * Prompt the user for a specific calendar date and set the panel to that
204 * current date.
205 */
206 public void chooseDate() {
207
208
209
210
211
212
213
214 }
215
216 public void deselect() {
217 getResultTable().getSelectionModel().clearSelection();
218 }
219
220 private JPanel getBioMarkersPanel() {
221 if (null == bioMarkerPanel) {
222 bioMarkerPanel = new BiomarkerPanel();
223 }
224 return bioMarkerPanel;
225 }
226
227 private JComponent getDailyTrackerPanel() {
228 if (null == dailyTracker) {
229 dailyTracker = new JTabbedPane();
230 dailyTracker.add("Diet", getDietPanel());
231 dailyTracker.add("Exercise", getExercisePanel());
232 dailyTracker.add("Biomarkers", getBioMarkersPanel());
233 }
234 return dailyTracker;
235 }
236
237 private JPanel getDietPanel() {
238 if (null == dietPanel) {
239 dietPanel = new JPanel(new BorderLayout(4, 4));
240 dietPanel.add(makeConsumedList(), BorderLayout.CENTER);
241 dietPanel.add(getTotalsPanel(), BorderLayout.SOUTH);
242 }
243 return dietPanel;
244 }
245
246
247
248
249
250
251
252
253
254 private JPanel getExercisePanel() {
255 if (null == exercisePanel) {
256 exercisePanel = new JPanel(new BorderLayout(4, 4));
257 }
258 return exercisePanel;
259 }
260
261 private Action getNextAction() {
262 if (null == nextAction) {
263 nextAction = new NextAction();
264 }
265 return nextAction;
266 }
267
268 private JButton getNextButton() {
269 if (null == nextButton) {
270 nextButton = new JButton(getNextAction());
271 nextButton.setFocusable(false);
272 nextButton.setBorderPainted(false);
273 nextButton.setOpaque(false);
274 }
275 return nextButton;
276 }
277
278 private Action getPrevAction() {
279 if (null == prevAction) {
280 prevAction = new PrevAction();
281 }
282 return prevAction;
283 }
284
285 private JButton getPreviousButton() {
286 if (null == prevButton) {
287 prevButton = new JButton(getPrevAction());
288 prevButton.setFocusable(false);
289 prevButton.setBorderPainted(false);
290 prevButton.setOpaque(false);
291 }
292 return prevButton;
293 }
294
295
296 private JTable getResultTable() {
297 if (null == resultTable) {
298 resultTable = new PrettyTable();
299 resultTable.setModel(model);
300 resultTable.setColumnSelectionAllowed(false);
301 resultTable.getSelectionModel().setSelectionMode(
302 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
303 resultTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
304 resultTable.getTableHeader().setReorderingAllowed(false);
305
306 resultTable.getColumnModel().getColumn(AMOUNT_COL).setMaxWidth(50);
307 resultTable.getColumnModel().getColumn(MEASURE_COL).setMaxWidth(100);
308 resultTable.getColumnModel().getColumn(CALORIES_COL).setMaxWidth(50);
309
310 resultTable.getColumnModel().getColumn(MEASURE_COL).setCellEditor(
311 new DefaultCellEditor(measureBox));
312
313
314 TableColumnModel tcm = resultTable.getColumnModel();
315 DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
316 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
317 tcm.getColumn(AMOUNT_COL).setCellRenderer(renderer);
318 tcm.getColumn(CALORIES_COL).setCellRenderer(renderer);
319
320 resultTable.getSelectionModel().addListSelectionListener(
321 new ListSelectionListener() {
322 public void valueChanged(ListSelectionEvent e) {
323
324
325 ListSelectionModel lsm = (ListSelectionModel)e .getSource();
326 if (!lsm.isSelectionEmpty()) {
327 int selectedRow = lsm.getMinSelectionIndex();
328 int sel = resultTable.getSelectedRow();
329 if (sel != -1) {
330 setMeasureBox(model.getServing(sel));
331 }
332 }
333 }
334 });
335
336
337 resultTable.addKeyListener(new KeyAdapter() {
338 public void keyTyped(KeyEvent e) {
339 if (logger.isDebugEnabled()) {
340 logger.debug("keyTyped(KeyEvent)" + e);
341 }
342 if (e.getKeyChar() == KeyEvent.VK_DELETE
343 || e.getKeyChar() == KeyEvent.VK_BACK_SPACE) {
344 int sel = resultTable.getSelectedRow();
345 if (sel != -1) {
346 Serving c = model.getServing(sel);
347 c.deleteFromDatabase();
348 deselect();
349 notifyObservers();
350 }
351 }
352 }
353 });
354
355 }
356 return resultTable;
357 }
358
359 /***
360 * Set the comboBox table cell editor to the currently
361 * selected measure list
362 * @param serving the selected serving
363 */
364 private void setMeasureBox(Serving s) {
365 if (s != null) {
366 measureBox.removeAllItems();
367 List measures = s.getFood().getMeasures();
368 for (int i=0; i<measures.size(); i++) {
369 measureBox.addItem(measures.get(i));
370 }
371 measureBox.setSelectedItem(s.getMeasure());
372 }
373 cwapp.getSearchPanel().deselect();
374 cwapp.getSearchPanel().foodSelected(s.getFood());
375 cwapp.getSearchPanel().getServingEditor().setServing(new Serving(s.getFood()));
376 }
377
378 private void addTableClickListener() {
379 resultTable.addMouseListener(new MouseAdapter() {
380 public void mouseClicked(MouseEvent e) {
381
382 int rowIndex = resultTable.rowAtPoint(e.getPoint());
383
384
385
386 if (rowIndex != -1) {
387 setMeasureBox(model.getServing(rowIndex));
388 }
389 }
390 });
391 }
392
393 /***
394 * @return the title label for this component
395 */
396 private JLabel getTitle() {
397 if (null == titleLabel) {
398 titleLabel = new JLabel(" ", JLabel.CENTER);
399 titleLabel.setFont(new Font("Application", Font.BOLD, 16));
400 titleLabel.setText(df.format(curDate));
401 titleLabel.addMouseListener(new MouseAdapter() {
402 public void mousePressed(MouseEvent e) {
403 chooseDate();
404 }
405 });
406 titleLabel.setForeground(Color.WHITE);
407 }
408 return titleLabel;
409 }
410
411 /***
412 * @return
413 */
414 private JComponent getToolbar() {
415 if (null == toolBar) {
416
417
418 toolBar = new TranslucentPanel(0.75f);
419 toolBar.setBackground(Color.BLACK);
420 toolBar.setLayout(new BoxLayout(toolBar, BoxLayout.X_AXIS));
421 toolBar.setBorder(BorderFactory.createCompoundBorder(
422
423 BorderFactory.createEmptyBorder(4, 4, 4, 4),
424 BorderFactory.createEmptyBorder(4, 4, 4, 4)));
425 toolBar.add(getPreviousButton());
426 toolBar.add(Box.createHorizontalGlue());
427 toolBar.add(getTitle());
428 toolBar.add(Box.createHorizontalGlue());
429 toolBar.add(getNextButton());
430 }
431 return toolBar;
432 }
433
434 private JComponent getTotalsPanel() {
435 if (null == totals) {
436 totals = new NutritionSummaryPanel();
437 }
438 return totals;
439 }
440
441 /***
442 *
443 */
444 private void initialize() {
445 setLayout(new BorderLayout(4, 4));
446
447
448 setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
449 add(getToolbar(), BorderLayout.NORTH);
450 add(getDailyTrackerPanel(), BorderLayout.CENTER);
451 }
452
453 private JComponent makeConsumedList() {
454 JScrollPane jsp = new JScrollPane(getResultTable());
455 jsp.setPreferredSize(new Dimension(400, 300));
456 jsp.getViewport().setBackground(Color.WHITE);
457 jsp.setBorder(BorderFactory.createEtchedBorder());
458 return jsp;
459 }
460
461 public void notifyObservers() {
462 consumed = Datasources.getInstance().getMutableDataSource().getConsumedOn(curDate);
463 getTitle().setText(df.format(curDate));
464 model.fireTableDataChanged();
465 totals.update(null, consumed);
466
467 }
468
469 public void setDate(Date d) {
470 curDate = d;
471 bioMarkerPanel.setDate(d);
472 notifyObservers();
473 }
474
475 }