GPLv2 license
[scorecard] / src / main-window.cpp
1 /*
2  * Copyright (C) 2009 Sakari Poussa
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, version 2.
7  */
8
9 #include <QtGui>
10
11 #include "main-window.h"
12 #include "score-dialog.h"
13 #include "course-dialog.h"
14 #include "stat-model.h"
15 #include "xml-dom-parser.h"
16
17 QString appName("scorecard");
18 QString topDir("/opt");
19 QString mmcDir("/media/mmc1");
20 QString dataDirName("data");
21 QString dataDir;
22 QString imgDir(topDir + "/pixmaps");
23 QString scoreFileName("score.xml");
24 QString scoreFile;
25 QString clubFileName("club.xml");
26 QString clubFile;
27 QString logFile("/tmp/scorecard.log");
28
29 bool dateLessThan(const Score *s1, const Score *s2)
30 {
31   return (*s1) < (*s2);
32 }
33
34 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
35 {
36   resize(800, 480);
37
38   loadSettings();
39
40   centralWidget = new QWidget(this);
41
42   setCentralWidget(centralWidget);
43
44   loadScoreFile(scoreFile, scoreList);
45   loadClubFile(clubFile, clubList);
46
47   // Sort the scores based on dates
48   qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
49   createActions();
50   createMenus();
51
52   createTableView(scoreList, clubList);
53   createStatusBar();
54
55   createLayout(centralWidget);
56 }
57
58 void MainWindow::loadSettings(void)
59 {
60   bool external = false;
61
62   QDir mmc(mmcDir);
63   if (mmc.exists())
64     external = true;
65
66   // TODO: make via user option, automatic will never work
67   external = false;
68
69 #ifndef Q_WS_HILDON
70   dataDir = "./" + dataDirName;
71 #else
72   if (external) {
73     dataDir = mmcDir + "/" + appName + "/" + dataDirName;
74   }
75   else {
76     dataDir = topDir + "/" + appName + "/" + dataDirName;
77   }
78 #endif
79   scoreFile = dataDir + "/" + scoreFileName;
80   clubFile = dataDir + "/" + clubFileName;
81
82   QDir dir(dataDir);
83   if (!dir.exists())
84     if (!dir.mkpath(dataDir)) {
85       qWarning() << "Unable to create: " + dataDir;
86       return;
87     }
88   qDebug() << "Data is at:" + dataDir;
89 }
90
91 void MainWindow::createLayout(QWidget *parent)
92 {
93
94   buttonLayout = new QVBoxLayout;
95   //labelLayout->addStretch();
96   buttonLayout->addWidget(nextButton);
97   buttonLayout->addWidget(prevButton);
98   buttonLayout->addWidget(lastButton);
99   buttonLayout->addWidget(firstButton);
100
101   tableLayout = new QVBoxLayout;
102   tableLayout->addWidget(table);
103
104   QHBoxLayout *mainLayout = new QHBoxLayout(parent);
105   mainLayout->addLayout(tableLayout);
106   mainLayout->addLayout(buttonLayout);
107   parent->setLayout(mainLayout);
108 }
109
110 // Setup 'score' tab view
111 void MainWindow::createTableView(QList<Score *> &scoreList, QList <Club *> &clubList)
112 {
113   table = new QTableView;
114
115   nextButton = new QPushButton(tr("Next"));
116   prevButton = new QPushButton(tr("Prev"));
117   firstButton = new QPushButton(tr("First"));
118   lastButton = new QPushButton(tr("Last"));
119
120   connect(nextButton, SIGNAL(clicked()), this, SLOT(nextButtonClicked()));
121   connect(prevButton, SIGNAL(clicked()), this, SLOT(prevButtonClicked()));
122   connect(firstButton, SIGNAL(clicked()), this, SLOT(firstButtonClicked()));
123   connect(lastButton, SIGNAL(clicked()), this, SLOT(lastButtonClicked()));
124
125   scoreTableModel = new ScoreTableModel();
126
127   table->showGrid();
128
129   table->setModel(scoreTableModel);
130   table->setSelectionMode(QAbstractItemView::NoSelection);
131
132   scoreTableModel->setScore(scoreList);
133   scoreTableModel->setClub(clubList);
134
135   // Fill out all the space with the tables
136   table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
137   table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
138   table->verticalHeader()->setAutoFillBackground(true);
139   table->horizontalHeader()->hide();
140 }
141
142 void MainWindow::createStatusBar()
143 {
144 #if 0
145   // TODO: use toolbar or buttons. Toolbar seems not to be ready and
146   // requires more work.
147   toolbar = addToolBar(tr("foo"));
148   toolbar->addAction(firstAct);
149   toolbar->addAction(lastAct);
150   toolbar->addAction(prevAct);
151   toolbar->addAction(nextAct);
152 #endif
153   updateStatusBar();
154 }
155
156 void MainWindow::createActions()
157 {
158   newScoreAct = new QAction(tr("New Score"), this);
159   connect(newScoreAct, SIGNAL(triggered()), this, SLOT(newScore()));
160
161   newCourseAct = new QAction(tr("New Course"), this);
162   connect(newCourseAct, SIGNAL(triggered()), this, SLOT(newCourse()));
163
164   editScoreAct = new QAction(tr("Edit Score"), this);
165   connect(editScoreAct, SIGNAL(triggered()), this, SLOT(editScore()));
166
167   editCourseAct = new QAction(tr("Edit Course"), this);
168   connect(editCourseAct, SIGNAL(triggered()), this, SLOT(editCourse()));
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 #ifdef Q_WS_HILDON
189   menu = menuBar()->addMenu("");
190 #else
191   menu = menuBar()->addMenu("Menu");
192 #endif
193
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 }