New colors, Graphs button removed
[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   updateTitleBar();
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::createActions()
143 {
144   newScoreAct = new QAction(tr("New Score"), this);
145   connect(newScoreAct, SIGNAL(triggered()), this, SLOT(newScore()));
146
147   newCourseAct = new QAction(tr("New Course"), this);
148   connect(newCourseAct, SIGNAL(triggered()), this, SLOT(newCourse()));
149
150   editScoreAct = new QAction(tr("Edit Score"), this);
151   connect(editScoreAct, SIGNAL(triggered()), this, SLOT(editScore()));
152
153   editCourseAct = new QAction(tr("Edit Course"), this);
154   connect(editCourseAct, SIGNAL(triggered()), this, SLOT(editCourse()));
155
156   statAct = new QAction(tr("Statistics"), this);
157   connect(statAct, SIGNAL(triggered()), this, SLOT(viewStatistics()));
158
159   nextAct = new QAction(tr( "   Next   "), this);
160   connect(nextAct, SIGNAL(triggered()), this, SLOT(nextButtonClicked()));
161
162   prevAct = new QAction("   Prev   ", this);
163   connect(prevAct, SIGNAL(triggered()), this, SLOT(prevButtonClicked()));
164
165   firstAct = new QAction(tr("   First  "), this);
166   connect(firstAct, SIGNAL(triggered()), this, SLOT(firstButtonClicked()));
167
168   lastAct = new QAction(tr( "   Last   "), this);
169   connect(lastAct, SIGNAL(triggered()), this, SLOT(lastButtonClicked()));
170 }
171
172 void MainWindow::createMenus()
173 {
174 #ifdef Q_WS_HILDON
175   menu = menuBar()->addMenu("");
176 #else
177   menu = menuBar()->addMenu("Menu");
178 #endif
179
180   menu->addAction(newScoreAct);
181   menu->addAction(newCourseAct);
182   menu->addAction(editScoreAct);
183   menu->addAction(editCourseAct);
184   menu->addAction(statAct);
185 }
186
187 void MainWindow::updateTitleBar()
188 {
189   QString title = scoreTableModel->getInfoText();
190   if (title.isEmpty())
191     title = "ScoreCard - No Scores";
192
193   setWindowTitle(title);
194 }
195
196 void MainWindow::firstButtonClicked()
197 {
198   scoreTableModel->first();
199   updateTitleBar();
200 }
201
202 void MainWindow::lastButtonClicked()
203 {
204   scoreTableModel->last();
205   updateTitleBar();
206 }
207
208 void MainWindow::nextButtonClicked()
209 {
210   scoreTableModel->next();
211   updateTitleBar();
212 }
213
214 void MainWindow::prevButtonClicked()
215 {
216   scoreTableModel->prev();
217   updateTitleBar();
218 }
219
220 // FIXME: dup code from table-model.cpp
221 Club *MainWindow::findClub(QString &name)
222 {
223   QListIterator<Club *> i(clubList);
224   Club *c;
225
226   while (i.hasNext()) {
227     c = i.next();
228     if (c->getName() == name)
229       return c;
230   }
231   return 0;
232 }
233
234 void MainWindow::newCourse()
235 {
236   CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
237
238   int result = selectDialog->exec();
239   if (result) {
240     QString clubName;
241     QString courseName;
242     QString date;
243
244     selectDialog->results(clubName, courseName);
245
246     CourseDialog *courseDialog = new CourseDialog(this);
247     courseDialog->init();
248
249     QString title = "New Course: " + clubName + "," + courseName;
250     courseDialog->setWindowTitle(title);
251
252     int result = courseDialog->exec();
253     if (result) {
254       QVector<QString> par(18);
255       QVector<QString> hcp(18);
256       QVector<QString> len(18);
257
258       courseDialog->results(par, hcp, len);
259
260       Course *course = 0;
261       Club *club = findClub(clubName);
262       if (club) {
263         course = club->getCourse(courseName);
264         if (course) {
265           qDebug() << "Error: club/course already in the database";
266           return;
267         }
268         else {
269           course = new Course(courseName, par, hcp);
270           club->addCourse(course);
271         }
272       }
273       else {
274         // New club and course
275         club = new Club(clubName);
276         course = new Course(courseName, par, hcp);
277         club->addCourse(course);
278         clubList << club;
279       }
280       saveClubFile(clubFile, clubList);
281
282       // TODO: does this really work? No mem leaks?
283       scoreTableModel->setClub(clubList);
284     }
285   }
286 }
287
288 void MainWindow::editCourse()
289 {
290   Course *course = scoreTableModel->getCourse();
291
292   if (!course) {
293     qWarning() << "No course on edit";
294     return;
295   }
296
297   CourseDialog *courseDialog = new CourseDialog(this);
298   courseDialog->init(course);
299
300   QString title = "Edit Course: " + course->getName();
301   courseDialog->setWindowTitle(title);
302   
303   int result = courseDialog->exec();
304   if (result) {
305     QVector<QString> par(18);
306     QVector<QString> hcp(18);
307     QVector<QString> len(18);
308     
309     courseDialog->results(par, hcp, len);
310     
311     course->update(par, hcp, len);
312     saveClubFile(clubFile, clubList);
313   }
314 }
315
316 void MainWindow::newScore()
317 {
318   SelectDialog *selectDialog = new SelectDialog(this);
319
320   selectDialog->init(clubList);
321
322   int result = selectDialog->exec();
323   if (result) {
324     QString clubName;
325     QString courseName;
326     QString date;
327
328     selectDialog->results(clubName, courseName, date);
329
330     ScoreDialog *scoreDialog = new ScoreDialog(this);
331     QString title = "New Score: " + courseName + ", " + date;
332     scoreDialog->setWindowTitle(title);
333
334     Club *club = findClub(clubName);
335     if (!club) {
336       qWarning() << "Error: no such club:" << clubName;
337       return;
338     }
339     Course *course = club->getCourse(courseName);
340     if (!course) {
341       qWarning() << "Error: no such course:" << courseName;
342       return;
343     }
344     scoreDialog->init(course);
345     result = scoreDialog->exec();
346     if (result) {
347       QVector<QString> scores(18);
348
349       scoreDialog->results(scores);
350       Score *score = new Score(scores, clubName, courseName, date);
351       scoreList << score;
352
353       // Sort the scores based on dates
354       qSort(scoreList.begin(), scoreList.end(), dateLessThan); 
355       // Save it
356       saveScoreFile(scoreFile, scoreList);
357
358       // TODO: does this really work? No mem leaks?
359       scoreTableModel->setScore(scoreList, score);
360       updateTitleBar();
361     }
362   }
363 }
364
365 void MainWindow::editScore()
366 {
367   Course *course = scoreTableModel->getCourse();
368   Score *score = scoreTableModel->getScore();
369
370   if (!course || !score) {
371     qDebug() << "No score/course to edit";
372     return;
373   }
374
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     updateTitleBar();
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 }