Statistics - final bits including all stats and error handling
[scorecard] / src / main-window.cpp
1 #include <QtGui>
2
3 #include "main-window.h"
4 #include "score-dialog.h"
5 #include "course-dialog.h"
6 #include "stat-model.h"
7 #include "xml-dom-parser.h"
8
9 QString appName("scorecard");
10 QString topDir("/opt");
11 QString mmcDir("/media/mmc1");
12 QString dataDirName("data");
13 QString dataDir;
14 QString imgDir(topDir + "/pixmaps");
15 QString scoreFileName("score.xml");
16 QString scoreFile;
17 QString clubFileName("club.xml");
18 QString clubFile;
19 QString logFile("/tmp/scorecard.log");
20
21 bool dateLessThan(const Score *s1, const Score *s2)
22 {
23   return (*s1) < (*s2);
24 }
25
26 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
27 {
28   resize(800, 480);
29
30   loadSettings();
31
32   centralWidget = new QWidget(this);
33
34   setCentralWidget(centralWidget);
35
36   loadScoreFile(scoreFile, scoreList);
37   loadClubFile(clubFile, clubList);
38
39   // Sort the scores based on dates
40   qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
41   createActions();
42   createMenus();
43
44   createTableView(scoreList, clubList);
45   createStatusBar();
46
47   createLayout(centralWidget);
48 }
49
50 void MainWindow::loadSettings(void)
51 {
52   bool external = false;
53
54   QDir mmc(mmcDir);
55   if (mmc.exists())
56     external = true;
57
58   // TODO: make via user option, automatic will never work
59   external = false;
60
61 #ifndef Q_WS_HILDON
62   dataDir = "./" + dataDirName;
63 #else
64   if (external) {
65     dataDir = mmcDir + "/" + appName + "/" + dataDirName;
66   }
67   else {
68     dataDir = topDir + "/" + appName + "/" + dataDirName;
69   }
70 #endif
71   scoreFile = dataDir + "/" + scoreFileName;
72   clubFile = dataDir + "/" + clubFileName;
73
74   QDir dir(dataDir);
75   if (!dir.exists())
76     if (!dir.mkpath(dataDir)) {
77       qWarning() << "Unable to create: " + dataDir;
78       return;
79     }
80   qDebug() << "Data is at:" + dataDir;
81 }
82
83 void MainWindow::createLayout(QWidget *parent)
84 {
85
86   buttonLayout = new QVBoxLayout;
87   //labelLayout->addStretch();
88   buttonLayout->addWidget(nextButton);
89   buttonLayout->addWidget(prevButton);
90   buttonLayout->addWidget(lastButton);
91   buttonLayout->addWidget(firstButton);
92
93   tableLayout = new QVBoxLayout;
94   tableLayout->addWidget(table);
95
96   QHBoxLayout *mainLayout = new QHBoxLayout(parent);
97   mainLayout->addLayout(tableLayout);
98   mainLayout->addLayout(buttonLayout);
99   parent->setLayout(mainLayout);
100 }
101
102 // Setup 'score' tab view
103 void MainWindow::createTableView(QList<Score *> &scoreList, QList <Club *> &clubList)
104 {
105   table = new QTableView;
106
107   nextButton = new QPushButton(tr("Next"));
108   prevButton = new QPushButton(tr("Prev"));
109   firstButton = new QPushButton(tr("First"));
110   lastButton = new QPushButton(tr("Last"));
111
112   connect(nextButton, SIGNAL(clicked()), this, SLOT(nextButtonClicked()));
113   connect(prevButton, SIGNAL(clicked()), this, SLOT(prevButtonClicked()));
114   connect(firstButton, SIGNAL(clicked()), this, SLOT(firstButtonClicked()));
115   connect(lastButton, SIGNAL(clicked()), this, SLOT(lastButtonClicked()));
116
117   scoreTableModel = new ScoreTableModel();
118
119   table->showGrid();
120
121   table->setModel(scoreTableModel);
122   table->setSelectionMode(QAbstractItemView::NoSelection);
123
124   scoreTableModel->setScore(scoreList);
125   scoreTableModel->setClub(clubList);
126
127   // Fill out all the space with the tables
128   table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
129   table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
130   table->verticalHeader()->setAutoFillBackground(true);
131   table->horizontalHeader()->hide();
132 }
133
134 void MainWindow::createStatusBar()
135 {
136 #if 0
137   // TODO: use toolbar or buttons. Toolbar seems not to be ready and
138   // requires more work.
139   toolbar = addToolBar(tr("foo"));
140   toolbar->addAction(firstAct);
141   toolbar->addAction(lastAct);
142   toolbar->addAction(prevAct);
143   toolbar->addAction(nextAct);
144 #endif
145   updateStatusBar();
146 }
147
148 void MainWindow::createActions()
149 {
150   newScoreAct = new QAction(tr("New Score"), this);
151   connect(newScoreAct, SIGNAL(triggered()), this, SLOT(newScore()));
152
153   newCourseAct = new QAction(tr("New Course"), this);
154   connect(newCourseAct, SIGNAL(triggered()), this, SLOT(newCourse()));
155
156   editScoreAct = new QAction(tr("Edit Score"), this);
157   connect(editScoreAct, SIGNAL(triggered()), this, SLOT(editScore()));
158
159   editCourseAct = new QAction(tr("Edit Course"), this);
160   connect(editCourseAct, SIGNAL(triggered()), this, SLOT(editCourse()));
161
162   statAct = new QAction(tr("Statistics"), this);
163   connect(statAct, SIGNAL(triggered()), this, SLOT(viewStatistics()));
164
165   nextAct = new QAction(tr( "   Next   "), this);
166   connect(nextAct, SIGNAL(triggered()), this, SLOT(nextButtonClicked()));
167
168   prevAct = new QAction("   Prev   ", this);
169   connect(prevAct, SIGNAL(triggered()), this, SLOT(prevButtonClicked()));
170
171   firstAct = new QAction(tr("   First  "), this);
172   connect(firstAct, SIGNAL(triggered()), this, SLOT(firstButtonClicked()));
173
174   lastAct = new QAction(tr( "   Last   "), this);
175   connect(lastAct, SIGNAL(triggered()), this, SLOT(lastButtonClicked()));
176 }
177
178 void MainWindow::createMenus()
179 {
180 #ifdef Q_WS_HILDON
181   menu = menuBar()->addMenu("");
182 #else
183   menu = menuBar()->addMenu("Menu");
184 #endif
185
186   menu->addAction(newScoreAct);
187   menu->addAction(newCourseAct);
188   menu->addAction(editScoreAct);
189   menu->addAction(editCourseAct);
190   menu->addAction(statAct);
191 }
192
193 void MainWindow::updateStatusBar()
194 {
195   QString title = scoreTableModel->getInfoText();
196   if (title.isEmpty())
197     title = "ScoreCard - No Scores";
198
199   setWindowTitle(title);
200 }
201
202 void MainWindow::firstButtonClicked()
203 {
204   scoreTableModel->first();
205   updateStatusBar();
206 }
207
208 void MainWindow::lastButtonClicked()
209 {
210   scoreTableModel->last();
211   updateStatusBar();
212 }
213
214 void MainWindow::nextButtonClicked()
215 {
216   scoreTableModel->next();
217   updateStatusBar();
218 }
219
220 void MainWindow::prevButtonClicked()
221 {
222   scoreTableModel->prev();
223   updateStatusBar();
224 }
225
226 // FIXME: dup code from table-model.cpp
227 Club *MainWindow::findClub(QString &name)
228 {
229   QListIterator<Club *> i(clubList);
230   Club *c;
231
232   while (i.hasNext()) {
233     c = i.next();
234     if (c->getName() == name)
235       return c;
236   }
237   return 0;
238 }
239
240 void MainWindow::newCourse()
241 {
242   CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
243
244   int result = selectDialog->exec();
245   if (result) {
246     QString clubName;
247     QString courseName;
248     QString date;
249
250     selectDialog->results(clubName, courseName);
251
252     CourseDialog *courseDialog = new CourseDialog(this);
253     courseDialog->init();
254
255     QString title = "New Course: " + clubName + "," + courseName;
256     courseDialog->setWindowTitle(title);
257
258     int result = courseDialog->exec();
259     if (result) {
260       QVector<QString> par(18);
261       QVector<QString> hcp(18);
262       QVector<QString> len(18);
263
264       courseDialog->results(par, hcp, len);
265
266       Course *course = 0;
267       Club *club = findClub(clubName);
268       if (club) {
269         course = club->getCourse(courseName);
270         if (course) {
271           qDebug() << "Error: club/course already in the database";
272           return;
273         }
274         else {
275           course = new Course(courseName, par, hcp);
276           club->addCourse(course);
277         }
278       }
279       else {
280         // New club and course
281         club = new Club(clubName);
282         course = new Course(courseName, par, hcp);
283         club->addCourse(course);
284         clubList << club;
285       }
286       saveClubFile(clubFile, clubList);
287
288       // TODO: does this really work? No mem leaks?
289       scoreTableModel->setClub(clubList);
290     }
291   }
292 }
293
294 void MainWindow::editCourse()
295 {
296   Course *course = scoreTableModel->getCourse();
297
298   if (!course) {
299     qWarning() << "No course on edit";
300     return;
301   }
302
303   CourseDialog *courseDialog = new CourseDialog(this);
304   courseDialog->init(course);
305
306   QString title = "Edit Course: " + course->getName();
307   courseDialog->setWindowTitle(title);
308   
309   int result = courseDialog->exec();
310   if (result) {
311     QVector<QString> par(18);
312     QVector<QString> hcp(18);
313     QVector<QString> len(18);
314     
315     courseDialog->results(par, hcp, len);
316     
317     course->update(par, hcp, len);
318     saveClubFile(clubFile, clubList);
319   }
320 }
321
322 void MainWindow::newScore()
323 {
324   SelectDialog *selectDialog = new SelectDialog(this);
325
326   selectDialog->init(clubList);
327
328   int result = selectDialog->exec();
329   if (result) {
330     QString clubName;
331     QString courseName;
332     QString date;
333
334     selectDialog->results(clubName, courseName, date);
335
336     ScoreDialog *scoreDialog = new ScoreDialog(this);
337     QString title = "New Score: " + courseName + ", " + date;
338     scoreDialog->setWindowTitle(title);
339
340     Club *club = findClub(clubName);
341     if (!club) {
342       qWarning() << "Error: no such club:" << clubName;
343       return;
344     }
345     Course *course = club->getCourse(courseName);
346     if (!course) {
347       qWarning() << "Error: no such course:" << courseName;
348       return;
349     }
350     scoreDialog->init(course);
351     result = scoreDialog->exec();
352     if (result) {
353       QVector<QString> scores(18);
354
355       scoreDialog->results(scores);
356       Score *score = new Score(scores, clubName, courseName, date);
357       scoreList << score;
358
359       // Sort the scores based on dates
360       qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
361       // Save it
362       saveScoreFile(scoreFile, scoreList);
363
364       // TODO: does this really work? No mem leaks?
365       scoreTableModel->setScore(scoreList, score);
366       updateStatusBar();
367     }
368   }
369 }
370
371 void MainWindow::editScore()
372 {
373   Course *course = scoreTableModel->getCourse();
374   Score *score = scoreTableModel->getScore();
375   QString date = score->getDate();
376
377   ScoreDialog *scoreDialog = new ScoreDialog(this);
378   
379   QString title = "Edit Score: " + course->getName() + ", " + date;
380   scoreDialog->setWindowTitle(title);
381
382   scoreDialog->init(course, score);
383
384   int result = scoreDialog->exec();
385
386   if (result) {
387     QVector<QString> scores(18);
388
389     scoreDialog->results(scores);
390     
391     score->update(scores);
392
393     // Sort the scores based on dates
394     qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
395     // Save it
396     saveScoreFile(scoreFile, scoreList);
397
398     // TODO: does this really work? No mem leaks?
399     scoreTableModel->setScore(scoreList, score);
400     updateStatusBar();
401   }
402 }
403
404 void MainWindow::viewStatistics()
405 {
406   QMainWindow *win = new QMainWindow(this);
407   QString title = "Statistics";
408   win->setWindowTitle(title);
409
410   StatModel *statModel = new StatModel(clubList, scoreList);
411
412   QTableView *table = new QTableView;
413   table->showGrid();
414   table->setSelectionMode(QAbstractItemView::NoSelection);
415   table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
416   table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
417   table->verticalHeader()->setAutoFillBackground(true);
418   table->setModel(statModel);
419
420   QWidget *central = new QWidget(win);
421   win->setCentralWidget(central);
422
423   QPushButton *b1 = new QPushButton("Graphs");
424
425   QVBoxLayout *buttonLayout = new QVBoxLayout;
426   buttonLayout->addWidget(b1);
427
428   QTextEdit *textEdit = new QTextEdit;
429   //getStat(textEdit);
430
431   textEdit->setReadOnly(true);
432
433   QVBoxLayout *infoLayout = new QVBoxLayout;
434   infoLayout->addWidget(table);
435
436   QHBoxLayout *mainLayout = new QHBoxLayout(central);
437   mainLayout->addLayout(infoLayout);
438   mainLayout->addLayout(buttonLayout);
439
440   central->setLayout(mainLayout);
441
442   win->show();
443 }
444
445 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
446 {
447   ScoreXmlHandler handler(list);
448
449   if (handler.parse(fileName))
450     qDebug() << "File loaded:" << fileName << " entries:" << list.size();
451 }
452
453 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
454 {
455   ScoreXmlHandler handler(list);
456
457   if (handler.save(fileName))
458     // TODO: banner
459     qDebug() << "File saved:" << fileName << " entries:" << list.size();
460   else
461     qWarning() << "Unable to save:" << fileName;
462 }
463
464 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list)
465 {
466   ClubXmlHandler handler(list);
467
468   if (handler.parse(fileName))
469     qDebug() << "File loaded:" << fileName << " entries:" << list.size();
470 }
471
472 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
473 {
474   ClubXmlHandler handler(list);
475
476   if (handler.save(fileName))
477     // TODO: banner
478     qDebug() << "File saved:" << fileName << " entries:" << list.size();
479   else
480     qWarning() << "Unable to save:" << fileName;
481
482 }