2 * Copyright (C) 2009 Sakari Poussa
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.
11 #include <QMaemo5InformationBox>
14 #include "score-common.h"
15 #include "main-window.h"
16 #include "score-dialog.h"
17 #include "course-dialog.h"
18 #include "settings-dialog.h"
19 #include "stat-model.h"
20 #include "xml-dom-parser.h"
22 QString appName("scorecard");
23 QString topDir("/opt");
24 QString mmcDir("/media/mmc1");
25 QString dataDirName("data");
27 QString imgDir(topDir + "/pixmaps");
28 QString scoreFileName("score.xml");
30 QString clubFileName("club.xml");
32 QString masterFileName("club-master.xml");
34 QString logFile("/tmp/scorecard.log");
35 QString titleScores("ScoreCard - Scores");
36 QString titleCourses("ScoreCard - Courses");
38 bool dateLessThan(const Score *s1, const Score *s2)
43 bool dateMoreThan(const Score *s1, const Score *s2)
47 // Find score based on club and course name
48 Score *MainWindow::findScore(QString & clubName, QString & courseName)
51 QListIterator<Score *> i(scoreList);
56 if ((s->getClubName() == clubName) &&
57 (s->getCourseName() == courseName))
63 // Find club based on name
64 Club *MainWindow::findClub(QString &name)
67 QListIterator<Club *> i(clubList);
72 if (c->getName() == name)
78 // Find course based on club & course name
79 Course *MainWindow::findCourse(const QString &clubName,
80 const QString &courseName)
83 QListIterator<Club *> i(clubList);
88 if (c->getName() == clubName) {
89 return c->getCourse(courseName);
95 // Find course based on current selection on the list
96 // TODO: make sure this is only called when course list is the model...
97 Course *MainWindow::currentCourse()
100 QModelIndex index = selectionModel->currentIndex();
102 if (!index.isValid())
105 const QAbstractItemModel *model = selectionModel->model();
106 QString str = model->data(index, Qt::DisplayRole).toString();
108 QStringList strList = str.split(", ");
109 if (strList.count() != 2) {
110 showNote(tr("Invalid course selection"));
113 return findCourse(strList[0], strList[1]);
116 // Find score based on current selection on the list
117 // TODO: make sure this is only called when score list is the model...
118 Score *MainWindow::currentScore()
121 QModelIndex index = selectionModel->currentIndex();
123 if (!index.isValid())
126 return scoreList.at(index.row());
129 void MainWindow::flushReadOnlyItems()
132 QMutableListIterator<Club *> i(clubList);
135 while (i.hasNext()) {
137 if (c->isReadOnly()) {
138 qDebug() << "Del:" << c->getName();
145 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
150 setAttribute(Qt::WA_Maemo5StackedWindow);
155 centralWidget = new QWidget(this);
157 setCentralWidget(centralWidget);
159 loadScoreFile(scoreFile, scoreList);
160 if (conf.defaultCourses == "Yes")
161 loadClubFile(masterFile, clubList, true);
162 loadClubFile(clubFile, clubList);
164 // Sort the scores based on dates
165 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
169 createListView(scoreList, clubList);
171 createLayoutList(centralWidget);
173 scoreWindow = new ScoreWindow(this);
174 courseWindow = new CourseWindow(this);
177 void MainWindow::loadSettings(void)
180 bool external = false;
186 // TODO: make via user option, automatic will never work
190 dataDir = "./" + dataDirName;
193 dataDir = mmcDir + "/" + appName + "/" + dataDirName;
196 dataDir = topDir + "/" + appName + "/" + dataDirName;
199 scoreFile = dataDir + "/" + scoreFileName;
200 clubFile = dataDir + "/" + clubFileName;
201 masterFile = dataDir + "/" + masterFileName;
205 if (!dir.mkpath(dataDir)) {
206 qWarning() << "Unable to create: " + dataDir;
209 qDebug() << "Data is at:" + dataDir;
211 settings.beginGroup(settingsGroup);
212 conf.hcp = settings.value(settingsHcp);
213 conf.homeClub = settings.value(settingsHomeClub);
214 conf.defaultCourses = settings.value(settingsDefaultCourses);
217 // Use default courses if no settings for that
218 if (!conf.defaultCourses.isValid())
219 conf.defaultCourses = "Yes";
221 qDebug() << "Settings: " << conf.hcp << conf.homeClub << conf.defaultCourses;
224 void MainWindow::saveSettings(void)
227 settings.beginGroup(settingsGroup);
228 if (conf.hcp.isValid())
229 settings.setValue(settingsHcp, conf.hcp);
230 if (conf.homeClub.isValid())
231 settings.setValue(settingsHomeClub, conf.homeClub);
232 if (conf.defaultCourses.isValid())
233 settings.setValue(settingsDefaultCourses, conf.defaultCourses);
237 void MainWindow::createLayoutList(QWidget *parent)
240 QVBoxLayout * tableLayout = new QVBoxLayout;
241 tableLayout->addWidget(list);
243 QHBoxLayout *mainLayout = new QHBoxLayout(parent);
244 mainLayout->addLayout(tableLayout);
245 parent->setLayout(mainLayout);
248 void MainWindow::createListView(QList<Score *> &scoreList,
249 QList <Club *> &clubList)
252 list = new QListView(this);
254 scoreListModel = new ScoreListModel(scoreList, clubList);
255 courseListModel = new CourseListModel(clubList);
257 list->setStyleSheet(defaultStyleSheet);
259 list->setSelectionMode(QAbstractItemView::SingleSelection);
260 list->setProperty("FingerScrolling", true);
265 connect(list, SIGNAL(clicked(QModelIndex)),
266 this, SLOT(clickedList(QModelIndex)));
269 void MainWindow::listScores()
272 list->setModel(scoreListModel);
273 selectionModel = list->selectionModel();
274 updateTitleBar(titleScores);
277 void MainWindow::listCourses()
280 list->setModel(courseListModel);
281 selectionModel = list->selectionModel();
282 updateTitleBar(titleCourses);
285 void MainWindow::createActions()
288 newScoreAction = new QAction(tr("New Score"), this);
289 connect(newScoreAction, SIGNAL(triggered()), this, SLOT(newScore()));
291 newCourseAction = new QAction(tr("New Course"), this);
292 connect(newCourseAction, SIGNAL(triggered()), this, SLOT(newCourse()));
294 statAction = new QAction(tr("Statistics"), this);
295 connect(statAction, SIGNAL(triggered()), this, SLOT(viewStatistics()));
297 settingsAction = new QAction(tr("Settings"), this);
298 connect(settingsAction, SIGNAL(triggered()), this, SLOT(viewSettings()));
300 // Maemo5 style menu filters
301 filterGroup = new QActionGroup(this);
302 filterGroup->setExclusive(true);
304 listScoreAction = new QAction(tr("Scores"), filterGroup);
305 listScoreAction->setCheckable(true);
306 listScoreAction->setChecked(true);
307 connect(listScoreAction, SIGNAL(triggered()), this, SLOT(listScores()));
309 listCourseAction = new QAction(tr("Courses"), filterGroup);
310 listCourseAction->setCheckable(true);
311 connect(listCourseAction, SIGNAL(triggered()), this, SLOT(listCourses()));
314 void MainWindow::createMenus()
318 menu = menuBar()->addMenu("");
320 menu = menuBar()->addMenu("Menu");
323 menu->addAction(newScoreAction);
324 menu->addAction(newCourseAction);
325 menu->addAction(statAction);
326 menu->addAction(settingsAction);
327 menu->addActions(filterGroup->actions());
330 void MainWindow::updateTitleBar(QString & msg)
336 void MainWindow::showNote(QString msg)
339 QMaemo5InformationBox::information(this,
341 QMaemo5InformationBox::DefaultTimeout);
345 void MainWindow::clickedList(const QModelIndex &index)
348 int row = index.row();
350 const QAbstractItemModel *m = index.model();
351 if (m == scoreListModel) {
352 if (row < scoreList.count()) {
353 Score * score = scoreList.at(row);
354 Course * course = findCourse(score->getClubName(), score->getCourseName());
355 viewScore(score, course);
358 else if (m == courseListModel) {
359 QString str = courseListModel->data(index, Qt::DisplayRole).toString();
360 QStringList strList = str.split(", ");
362 if (strList.count() != 2) {
363 showNote(QString("Invalid course selection"));
366 Course * course = findCourse(strList.at(0), strList.at(1));
371 void MainWindow::viewScore(Score * score, Course * course)
374 scoreWindow->setup(score, course);
378 void MainWindow::newScore()
381 SelectDialog *selectDialog = new SelectDialog(this);
383 selectDialog->init(clubList);
385 int result = selectDialog->exec();
391 selectDialog->results(clubName, courseName, date);
393 ScoreDialog *scoreDialog = new ScoreDialog(this);
394 QString title = "New Score: " + courseName + ", " + date;
395 scoreDialog->setWindowTitle(title);
397 Club *club = findClub(clubName);
399 showNote(tr("Error: no such club"));
402 Course *course = club->getCourse(courseName);
404 showNote(tr("Error: no such course:"));
407 scoreDialog->init(course);
408 result = scoreDialog->exec();
410 QVector<QString> scores(18);
412 scoreDialog->results(scores);
413 Score *score = new Score(scores, clubName, courseName, date);
416 // Sort the scores based on dates
417 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
419 saveScoreFile(scoreFile, scoreList);
420 scoreListModel->update(scoreList);
426 void MainWindow::editScore()
430 Score *score = currentScore();
433 course = findCourse(score->getClubName(), score->getCourseName());
435 if (!course || !score) {
436 qDebug() << "No score/course to edit";
440 QString date = score->getDate();
442 ScoreDialog *scoreDialog = new ScoreDialog(this);
443 scoreDialog->init(course, score);
445 QString title = "Edit Score: " + course->getName() + ", " + date;
446 scoreDialog->setWindowTitle(title);
448 int result = scoreDialog->exec();
450 QVector<QString> scores(18);
452 scoreDialog->results(scores);
454 score->update(scores);
456 // Sort the scores based on dates
457 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
459 saveScoreFile(scoreFile, scoreList);
465 void MainWindow::deleteScore()
469 scoreWindow->close();
471 QModelIndex index = selectionModel->currentIndex();
472 if (!index.isValid()) {
473 qDebug() << "Invalid index";
477 scoreList.removeAt(index.row());
479 saveScoreFile(scoreFile, scoreList);
480 scoreListModel->update(scoreList);
484 void MainWindow::viewCourse(Course * course)
487 courseWindow->setup(course);
488 courseWindow->show();
491 void MainWindow::newCourse()
494 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
496 int result = selectDialog->exec();
502 selectDialog->results(clubName, courseName);
504 CourseDialog *courseDialog = new CourseDialog(this);
505 courseDialog->init();
506 QString title = "New Course: " + clubName + "," + courseName;
507 courseDialog->setWindowTitle(title);
509 int result = courseDialog->exec();
511 QVector<QString> par(18);
512 QVector<QString> hcp(18);
513 QVector<QString> len(18);
515 courseDialog->results(par, hcp, len);
518 Club *club = findClub(clubName);
520 course = club->getCourse(courseName);
522 showNote(tr("Club/course already in the database"));
526 course = new Course(courseName, par, hcp);
527 club->addCourse(course);
531 // New club and course
532 club = new Club(clubName);
533 course = new Course(courseName, par, hcp);
534 club->addCourse(course);
538 saveClubFile(clubFile, clubList);
539 courseListModel->update(clubList);
545 void MainWindow::editCourse()
548 Course *course = currentCourse();
551 showNote(tr("No course on edit"));
555 CourseDialog *courseDialog = new CourseDialog(this);
556 courseDialog->init(course);
558 QString title = "Edit Course: " + course->getName();
559 courseDialog->setWindowTitle(title);
561 int result = courseDialog->exec();
563 QVector<QString> par(18);
564 QVector<QString> hcp(18);
565 QVector<QString> len(18);
567 courseDialog->results(par, hcp, len);
569 course->update(par, hcp, len);
570 saveClubFile(clubFile, clubList);
576 void MainWindow::deleteCourse()
580 Course * course = currentCourse();
583 qDebug() << "Invalid course for deletion";
586 club = course->parent();
588 // Can not delete course if it has scores -- check
589 if (findScore(club->getName(), course->getName()) != 0) {
590 showNote(tr("Can not delete course, delete scores on the course first"));
595 courseWindow->close();
597 club->delCourse(course);
599 if (club->isEmpty()) {
600 int index = clubList.indexOf(club);
602 clubList.removeAt(index);
606 saveClubFile(clubFile, clubList);
607 courseListModel->update(clubList);
611 void MainWindow::viewStatistics()
614 QMainWindow *win = new QMainWindow(this);
615 QString title = "Statistics";
616 win->setWindowTitle(title);
618 win->setAttribute(Qt::WA_Maemo5StackedWindow);
621 StatModel *model = new StatModel(clubList, scoreList);
623 QTableView *table = new QTableView;
625 table->setSelectionMode(QAbstractItemView::NoSelection);
626 table->setStyleSheet(statStyleSheet);
627 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
628 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
629 table->verticalHeader()->setAutoFillBackground(true);
630 table->setModel(model);
632 QWidget *central = new QWidget(win);
633 win->setCentralWidget(central);
635 QTextEdit *textEdit = new QTextEdit;
637 textEdit->setReadOnly(true);
639 QVBoxLayout *infoLayout = new QVBoxLayout;
640 infoLayout->addWidget(table);
642 QHBoxLayout *mainLayout = new QHBoxLayout(central);
643 mainLayout->addLayout(infoLayout);
644 central->setLayout(mainLayout);
649 void MainWindow::viewSettings()
652 SettingsDialog *dlg = new SettingsDialog(this);
654 dlg->init(conf, clubList);
656 int result = dlg->exec();
658 QString oldValue = conf.defaultCourses.toString();
660 QString newValue = conf.defaultCourses.toString();
663 qDebug() << "Settings:" << oldValue << "->" << newValue;
665 // Reload club list, or drop r/o courses from list
666 if (oldValue == "Yes" && newValue == "No") {
667 flushReadOnlyItems();
668 courseListModel->update(clubList);
671 else if ((oldValue == "No" || oldValue == "") && newValue == "Yes") {
672 loadClubFile(masterFile, clubList, true);
673 courseListModel->update(clubList);
679 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
681 ScoreXmlHandler handler(list);
683 if (handler.parse(fileName))
684 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
687 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
689 ScoreXmlHandler handler(list);
691 if (handler.save(fileName))
693 qDebug() << "File saved:" << fileName << " entries:" << list.size();
695 qWarning() << "Unable to save:" << fileName;
698 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list, bool readOnly)
700 ClubXmlHandler handler(list);
702 if (handler.parse(fileName, readOnly))
703 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
706 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
708 ClubXmlHandler handler(list);
710 if (handler.save(fileName))
712 qDebug() << "File saved:" << fileName << " entries:" << list.size();
714 qWarning() << "Unable to save:" << fileName;