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