Statistics - initial version
[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 #if 0
163   viewScoreAct = new QAction(tr("&View Scores"), this);
164   connect(viewScoreAct, SIGNAL(triggered()), this, SLOT(viewScore()));
165
166   viewCourseAct = new QAction(tr("&View Courses"), this);
167   connect(viewCourseAct, SIGNAL(triggered()), this, SLOT(viewCourse()));
168 #endif
169
170   statAct = new QAction(tr("Statistics"), this);
171   connect(statAct, SIGNAL(triggered()), this, SLOT(viewStatistics()));
172
173   nextAct = new QAction(tr( "   Next   "), this);
174   connect(nextAct, SIGNAL(triggered()), this, SLOT(nextButtonClicked()));
175
176   prevAct = new QAction("   Prev   ", this);
177   connect(prevAct, SIGNAL(triggered()), this, SLOT(prevButtonClicked()));
178
179   firstAct = new QAction(tr("   First  "), this);
180   connect(firstAct, SIGNAL(triggered()), this, SLOT(firstButtonClicked()));
181
182   lastAct = new QAction(tr( "   Last   "), this);
183   connect(lastAct, SIGNAL(triggered()), this, SLOT(lastButtonClicked()));
184 }
185
186 void MainWindow::createMenus()
187 {
188   menu = menuBar()->addMenu("");
189 #if 0
190   menu->addAction(viewScoreAct);
191   menu->addAction(viewCourseAct);
192   menu->addAction(viewStatisticAct);
193 #endif
194   menu->addAction(newScoreAct);
195   menu->addAction(newCourseAct);
196   menu->addAction(editScoreAct);
197   menu->addAction(editCourseAct);
198   menu->addAction(statAct);
199 }
200
201 void MainWindow::updateStatusBar()
202 {
203   QString title = scoreTableModel->getInfoText();
204   if (title.isEmpty())
205     title = "ScoreCard - No Scores";
206
207   setWindowTitle(title);
208 }
209
210 void MainWindow::firstButtonClicked()
211 {
212   scoreTableModel->first();
213   updateStatusBar();
214 }
215
216 void MainWindow::lastButtonClicked()
217 {
218   scoreTableModel->last();
219   updateStatusBar();
220 }
221
222 void MainWindow::nextButtonClicked()
223 {
224   scoreTableModel->next();
225   updateStatusBar();
226 }
227
228 void MainWindow::prevButtonClicked()
229 {
230   scoreTableModel->prev();
231   updateStatusBar();
232 }
233
234 // FIXME: dup code from table-model.cpp
235 Club *MainWindow::findClub(QString &name)
236 {
237   QListIterator<Club *> i(clubList);
238   Club *c;
239
240   while (i.hasNext()) {
241     c = i.next();
242     if (c->getName() == name)
243       return c;
244   }
245   return 0;
246 }
247
248 void MainWindow::newCourse()
249 {
250   CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
251
252   int result = selectDialog->exec();
253   if (result) {
254     QString clubName;
255     QString courseName;
256     QString date;
257
258     selectDialog->results(clubName, courseName);
259
260     CourseDialog *courseDialog = new CourseDialog(this);
261     courseDialog->init();
262
263     QString title = "New Course: " + clubName + "," + courseName;
264     courseDialog->setWindowTitle(title);
265
266     int result = courseDialog->exec();
267     if (result) {
268       QVector<QString> par(18);
269       QVector<QString> hcp(18);
270       QVector<QString> len(18);
271
272       courseDialog->results(par, hcp, len);
273
274       Course *course = 0;
275       Club *club = findClub(clubName);
276       if (club) {
277         course = club->getCourse(courseName);
278         if (course) {
279           qDebug() << "Error: club/course already in the database";
280           return;
281         }
282         else {
283           course = new Course(courseName, par, hcp);
284           club->addCourse(course);
285         }
286       }
287       else {
288         // New club and course
289         club = new Club(clubName);
290         course = new Course(courseName, par, hcp);
291         club->addCourse(course);
292         clubList << club;
293       }
294       saveClubFile(clubFile, clubList);
295
296       // TODO: does this really work? No mem leaks?
297       scoreTableModel->setClub(clubList);
298     }
299   }
300 }
301
302 void MainWindow::editCourse()
303 {
304   Course *course = scoreTableModel->getCourse();
305
306   if (!course) {
307     qWarning() << "No course on edit";
308     return;
309   }
310
311   CourseDialog *courseDialog = new CourseDialog(this);
312   courseDialog->init(course);
313
314   QString title = "Edit Course: " + course->getName();
315   courseDialog->setWindowTitle(title);
316   
317   int result = courseDialog->exec();
318   if (result) {
319     QVector<QString> par(18);
320     QVector<QString> hcp(18);
321     QVector<QString> len(18);
322     
323     courseDialog->results(par, hcp, len);
324     
325     course->update(par, hcp, len);
326     saveClubFile(clubFile, clubList);
327   }
328 }
329
330 void MainWindow::newScore()
331 {
332   SelectDialog *selectDialog = new SelectDialog(this);
333
334   selectDialog->init(clubList);
335
336   int result = selectDialog->exec();
337   if (result) {
338     QString clubName;
339     QString courseName;
340     QString date;
341
342     selectDialog->results(clubName, courseName, date);
343
344     ScoreDialog *scoreDialog = new ScoreDialog(this);
345     QString title = "New Score: " + courseName + ", " + date;
346     scoreDialog->setWindowTitle(title);
347
348     Club *club = findClub(clubName);
349     if (!club) {
350       qWarning() << "Error: no such club:" << clubName;
351       return;
352     }
353     Course *course = club->getCourse(courseName);
354     if (!course) {
355       qWarning() << "Error: no such course:" << courseName;
356       return;
357     }
358     scoreDialog->init(course);
359     result = scoreDialog->exec();
360     if (result) {
361       QVector<QString> scores(18);
362
363       scoreDialog->results(scores);
364       Score *score = new Score(scores, clubName, courseName, date);
365       scoreList << score;
366
367       // Sort the scores based on dates
368       qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
369       // Save it
370       saveScoreFile(scoreFile, scoreList);
371
372       // TODO: does this really work? No mem leaks?
373       scoreTableModel->setScore(scoreList, score);
374       updateStatusBar();
375     }
376   }
377 }
378
379 void MainWindow::editScore()
380 {
381   Course *course = scoreTableModel->getCourse();
382   Score *score = scoreTableModel->getScore();
383   QString date = score->getDate();
384
385   ScoreDialog *scoreDialog = new ScoreDialog(this);
386   
387   QString title = "Edit Score: " + course->getName() + ", " + date;
388   scoreDialog->setWindowTitle(title);
389
390   scoreDialog->init(course, score);
391
392   int result = scoreDialog->exec();
393
394   if (result) {
395     QVector<QString> scores(18);
396
397     scoreDialog->results(scores);
398     
399     score->update(scores);
400
401     // Sort the scores based on dates
402     qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
403     // Save it
404     saveScoreFile(scoreFile, scoreList);
405
406     // TODO: does this really work? No mem leaks?
407     scoreTableModel->setScore(scoreList, score);
408     updateStatusBar();
409   }
410 }
411
412 void MainWindow::viewStatistics()
413 {
414   QMainWindow *win = new QMainWindow(this);
415   QString title = "Statistics";
416   win->setWindowTitle(title);
417
418   StatModel *statModel = new StatModel(clubList, scoreList);
419
420   QTableView *table = new QTableView;
421   table->showGrid();
422   table->setSelectionMode(QAbstractItemView::NoSelection);
423   table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
424   table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
425   table->verticalHeader()->setAutoFillBackground(true);
426   table->setModel(statModel);
427
428   QWidget *central = new QWidget(win);
429   win->setCentralWidget(central);
430
431   QPushButton *b1 = new QPushButton("Graphs");
432
433   QVBoxLayout *buttonLayout = new QVBoxLayout;
434   buttonLayout->addWidget(b1);
435
436   QTextEdit *textEdit = new QTextEdit;
437   //getStat(textEdit);
438
439   textEdit->setReadOnly(true);
440
441   QVBoxLayout *infoLayout = new QVBoxLayout;
442   infoLayout->addWidget(table);
443
444   QHBoxLayout *mainLayout = new QHBoxLayout(central);
445   mainLayout->addLayout(infoLayout);
446   mainLayout->addLayout(buttonLayout);
447
448   central->setLayout(mainLayout);
449
450   win->show();
451 }
452
453 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
454 {
455   ScoreXmlHandler handler(list);
456
457   if (handler.parse(fileName))
458     qDebug() << "File loaded:" << fileName << " entries:" << list.size();
459 }
460
461 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
462 {
463   ScoreXmlHandler handler(list);
464
465   if (handler.save(fileName))
466     // TODO: banner
467     qDebug() << "File saved:" << fileName << " entries:" << list.size();
468   else
469     qWarning() << "Unable to save:" << fileName;
470 }
471
472 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list)
473 {
474   ClubXmlHandler handler(list);
475
476   if (handler.parse(fileName))
477     qDebug() << "File loaded:" << fileName << " entries:" << list.size();
478 }
479
480 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
481 {
482   ClubXmlHandler handler(list);
483
484   if (handler.save(fileName))
485     // TODO: banner
486     qDebug() << "File saved:" << fileName << " entries:" << list.size();
487   else
488     qWarning() << "Unable to save:" << fileName;
489
490 }