1
2
3
4 package ca.spaz.cron;
5
6 import java.awt.BorderLayout;
7 import java.awt.event.*;
8 import java.io.*;
9 import java.util.*;
10
11 import javax.swing.*;
12
13 import org.apache.log4j.*;
14
15 import ca.spaz.cron.database.Food;
16 import ca.spaz.cron.datasource.*;
17 import ca.spaz.cron.targets.TargetEditor;
18 import ca.spaz.cron.ui.*;
19 import ca.spaz.cron.user.NewUserWizard;
20 import ca.spaz.cron.user.impl.CRONUser;
21 import ca.spaz.gui.SpazMenuBar;
22 import ca.spaz.task.*;
23 import ca.spaz.util.*;
24
25 import com.jgoodies.looks.plastic.Plastic3DLookAndFeel;
26
27 /***
28 * The main app. This is more of a place holder class at the moment. I'm not yet
29 * decided how to structure the overall program, as I'm not yet sure of all the
30 * screens and components and how they'll interact. Right now, it's just
31 * handling the main JFrame of the app and providing some global access to data
32 * structures.
33 * <ul>
34 * <li>@TODO: Ensure good program architecture</li>
35 * <li>@TODO: Figure out using multiple databases</li>
36 * <li>@TODO: biomarker tracker (weight, temp, etc...)</li>
37 * <li>@TODO: XML format for import/export of food data</li>
38 * <li>@TODO: Manual / help</li>
39 * <li>@TODO: Recipie editor / meal planner / food search</li>
40 * <li>@TODO: Generate reports, ranged summaries, dietary suggestions</li>
41 * </ul>
42 *
43 * @author davidson
44 */
45 public class CRONOMETER extends JFrame implements TaskListener {
46
47 private static final class SplashScreenTask implements Task, ProgressListener {
48 int prog = 0;
49 private TaskListener tl;
50
51 public int getTaskProgress() {
52 return prog;
53 }
54
55 public void abortTask() {
56 }
57
58 public boolean canAbortTask() {
59 return false;
60 }
61
62 public String getTaskDescription() {
63 return "Starting CRON-O-METER...";
64 }
65
66 public void run() {
67 Datasources.initialize(this);
68 }
69
70
71
72
73 public void progressStart() {
74 prog = 0;
75 }
76
77
78
79
80 public void progressFinish() {
81 prog = 100;
82 }
83
84
85
86
87 public void progress(int percent) {
88 prog = percent;
89 }
90 }
91
92 /***
93 * Logger for this class
94 */
95 private static final Logger logger = Logger.getLogger(CRONOMETER.class);
96
97 private SearchPanel sp;
98
99 private DailySummary ds;
100
101 private SpazMenuBar menu;
102
103 private JPanel mainPanel;
104
105 private static boolean isLoggerConfigured = false;
106
107 private static CRONOMETER instance;
108
109 public static CRONOMETER getInstance() {
110 if (null == instance) {
111 instance = new CRONOMETER();
112 }
113 return instance;
114 }
115
116 /***
117 * Constructor
118 */
119 public CRONOMETER() {
120
121 }
122
123 /***
124 *
125 */
126 private void initGUI() {
127 setJMenuBar(getMenu());
128 ImageIcon icon = new ImageIcon(ImageFactory.getInstance().loadImage("/img/icon.png"));
129 setIconImage(icon.getImage());
130 setTitle("CRON-O-METER");
131 getContentPane().add(getMainPanel());
132 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
133 addWindowListener(new WindowAdapter() {
134
135
136
137 public void windowClosing(WindowEvent e) {
138 doQuit();
139 }
140 });
141 pack();
142 ToolBox.centerFrame(this);
143 if (((CRONUser)CRONUser.getUser()).firstRun()) {
144 ((CRONUser)CRONUser.getUser()).setFirstRun(false);
145 doNewUserWizard();
146 }
147 }
148
149 /***
150 * @return
151 */
152 private JMenuBar getMenu() {
153 if (null == menu) {
154 menu = new SpazMenuBar(getClass().getResourceAsStream("menubar.xml"), this);
155 }
156 return menu;
157 }
158
159 private JPanel getMainPanel() {
160 if (null == mainPanel) {
161 mainPanel = new JPanel(new BorderLayout(4, 4));
162 mainPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
163 JSplitPane jsplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
164 getSearchPanel(), getDailySummary());
165 jsplit.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
166 mainPanel.add(jsplit, BorderLayout.CENTER);
167 }
168 return mainPanel;
169 }
170
171 public SearchPanel getSearchPanel() {
172 if (null == sp) {
173 sp = new SearchPanel(this);
174 }
175 return sp;
176 }
177
178 public DailySummary getDailySummary() {
179 if (null == ds) {
180 ds = new DailySummary(this);
181 }
182 return ds;
183 }
184
185 public void doCreateNewFood() {
186 Food f = Datasources.getInstance().getMutableDataSource().createNewFood();
187 FoodEditor.editFood(f);
188 }
189
190 public void doEditTargets() {
191 TargetEditor.editTargets();
192 }
193
194 public void doNewUserWizard() {
195 NewUserWizard.createNewUser(CRONUser.getUser());
196 }
197
198 public void doQuit() {
199 Datasources.getInstance().closeAll();
200 System.exit(0);
201 }
202
203 public void doUSDAImport() {
204 USDAImportDialog dlg = new USDAImportDialog(this);
205 dlg.setModal(true);
206 dlg.setVisible(true);
207 }
208
209 /***
210 * @param args
211 */
212 public static void main(String[] args) {
213 configureLogger();
214 try {
215 UIManager.setLookAndFeel(new Plastic3DLookAndFeel());
216
217 } catch (Exception e) {
218 logger.error("main() - Error configuring UI delegate", e);
219 }
220
221 final CRONOMETER cron = CRONOMETER.getInstance();
222 SplashScreen scr = new SplashScreen(new SplashScreenTask());
223 scr.addTaskListener(cron);
224 scr.start();
225 }
226
227 /***
228 *
229 */
230 public static void configureLogger() {
231 if (!isLoggerConfigured) {
232 Properties p = new Properties();
233 InputStream psrc = CRONOMETER.class
234 .getResourceAsStream("/logger.properties");
235 try {
236 p.load(psrc);
237 } catch (IOException e1) {
238 e1.printStackTrace();
239 }
240 PropertyConfigurator.configure(p);
241 isLoggerConfigured = true;
242 }
243 }
244
245
246
247
248 public void taskStarted(Task t) {
249
250 }
251
252
253
254
255 public void taskFinished(Task t) {
256 SwingUtilities.invokeLater(new Runnable() {
257
258 public void run() {
259 checkDataSources();
260 initGUI();
261 setVisible(true);
262 }});
263 }
264
265 /***
266 * @todo Add a wizard page for each unavailable datasource.
267 * @todo Check the user for existence, as well.
268 * @todo Invoke the New User wizard (needs a better name) before firing the UI up
269 */
270 protected void checkDataSources() {
271 Set incomplete = new HashSet();
272 List sources = Datasources.getInstance().getDatasources(true);
273 for (Iterator iter = sources.iterator(); iter.hasNext();) {
274 IFoodDatasource ds = (IFoodDatasource) iter.next();
275 if (!ds.isAvailable()) {
276 incomplete.add(ds);
277 }
278 }
279
280 for (Iterator iter = incomplete.iterator(); iter.hasNext();) {
281 IFoodDatasource ds = (IFoodDatasource) iter.next();
282 logger.warn(ds.getName() + " is not functional");
283 }
284 }
285
286
287
288
289 public void taskAborted(Task t) {
290 logger.error("Startup tasks aborted unexpectedly. Halting...");
291 System.exit(1);
292 }
293
294 }