Low level support for more details in scores including putts, sand saves, fairwayhits...
[scorecard] / src / score-dialog.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 #include <QInputContext>
11 #ifdef Q_WS_MAEMO_5
12 #include <QMaemo5InformationBox>
13 #endif
14
15 #include "score-dialog.h"
16 #include "score-common.h"
17 #include "table-model.h"
18
19 ////////////////////////////////////////////////////////////////////////////////
20 // ScoreWindow based on QMainWindow
21 ////////////////////////////////////////////////////////////////////////////////
22 ScoreWindow::ScoreWindow(QWidget *parent) : QMainWindow(parent)
23 {
24 #ifdef Q_WS_MAEMO_5
25     setAttribute(Qt::WA_Maemo5StackedWindow);
26 #endif
27
28     QAction *editAction = new QAction(tr("Edit"), this);
29     connect(editAction, SIGNAL(triggered()), parent, SLOT(editScore()));
30     menuBar()->addAction(editAction);
31
32     QAction *delAction = new QAction(tr("Delete"), this);
33     connect(delAction, SIGNAL(triggered()), parent, SLOT(deleteScore()));
34     menuBar()->addAction(delAction);
35
36     model = new ScoreTableModel;
37     
38     QTableView * table = new QTableView;
39     table->showGrid();
40     table->setSelectionMode(QAbstractItemView::NoSelection);
41     table->setStyleSheet(defaultStyleSheet);
42     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
43     table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
44     table->horizontalHeader()->hide();
45     table->setModel(model);
46     
47     QWidget *central = new QWidget(this);
48     setCentralWidget(central);
49     
50     QVBoxLayout *layout = new QVBoxLayout;
51     layout->addWidget(table);
52     
53     central->setLayout(layout);
54 }
55
56 ScoreWindow::~ScoreWindow()
57 {
58     TRACE;
59 }
60
61 void ScoreWindow::setup(Score *score, Course *course)
62 {
63     TRACE;
64     QString title = QString("%1, %2 - %3").arg(score->getClubName()).arg(score->getCourseName()).arg(score->getDate());
65     setWindowTitle(title);
66     model->set(score, course);
67 }
68
69
70 ////////////////////////////////////////////////////////////////////////////////
71 // SelectDialog based on QDialog
72 ////////////////////////////////////////////////////////////////////////////////
73 SelectDialog::SelectDialog(QWidget *parent) : QDialog(parent)
74 {
75     resize(800, 350);
76
77     QWidget *centralWidget = new QWidget(this);
78     createLayout(centralWidget);
79
80     setWindowTitle(tr("ScoreCard: Select Course and Date"));
81 }
82
83 void SelectDialog::createLayout(QWidget *parent)
84 {
85     listWidgetClub = new QListWidget(parent);
86     pushButtonNext = new QPushButton(tr("Next"));
87
88     connect(pushButtonNext, SIGNAL(clicked()), this, SLOT(next()));
89
90     QDialogButtonBox * buttonBox = new QDialogButtonBox(Qt::Vertical);
91     buttonBox->addButton(pushButtonNext, QDialogButtonBox::ActionRole);
92
93     leftLayout = new QVBoxLayout;
94     leftLayout->addWidget(listWidgetClub);
95
96 #ifdef Q_WS_MAEMO_5
97     dateButton = new QMaemo5ValueButton();
98     dateButton->setValueLayout(QMaemo5ValueButton::ValueUnderText);
99     dateButton->setPickSelector(new QMaemo5DatePickSelector());
100     dateButton->setText(QString::fromUtf8("Date"));
101     leftLayout->addWidget(dateButton);
102 #else
103     QDate today(QDate::currentDate());
104     lineEditDate = new QLineEdit;
105     lineEditDate->setText(today.toString("yyyy-MM-dd"));
106     date = new QDateEdit;
107     leftLayout->addWidget(date);
108     leftLayout->addWidget(lineEditDate);
109 #endif
110
111     rightLayout = new QVBoxLayout;
112     rightLayout->addStretch();
113     rightLayout->addWidget(buttonBox);
114
115     QHBoxLayout *mainLayout = new QHBoxLayout(parent);
116     mainLayout->addLayout(leftLayout);
117     mainLayout->addLayout(rightLayout);
118
119     setLayout(mainLayout);
120 }
121
122 void SelectDialog::init(QList<Club *> &list)
123 {
124     TRACE;
125     clubList = list;
126
127     QListIterator<Club *> i(clubList);
128     int index = 0;
129     bool markedFlag = false;
130
131     while (i.hasNext()) {
132         Club *club = i.next();
133
134         QList<Course *> courseList = club->getCourseList();
135
136         QListIterator<Course *> j(courseList);
137         while (j.hasNext()) {
138             Course *course = j.next();
139
140             QListWidgetItem *newItem = new QListWidgetItem;
141             
142             QString entry = club->getName() + ", " + course->getName();
143
144             newItem->setText(entry);
145             listWidgetClub->insertItem(index, newItem);
146
147             if (!markedFlag & club->isHomeClub()) {
148                 listWidgetClub->setCurrentRow(index);
149                 // Mark the 1st course of the home club the selection
150                 markedFlag = true;
151             }
152             index++;
153         }
154     }
155 }
156
157 void SelectDialog::results(QString &club, 
158                            QString &course, 
159                            QString &date)
160 {  
161     QListWidgetItem *current = listWidgetClub->currentItem();
162
163     if (current) {
164         QString tmp = current->text();
165
166         QStringList stringList = tmp.split(", ");
167         club = stringList[0];
168         course = stringList[1];
169 #ifdef Q_WS_MAEMO_5
170         QMaemo5DatePickSelector *sel = (QMaemo5DatePickSelector *)dateButton->pickSelector();
171         QDate d = sel->currentDate();
172         // TODO: change to QDate
173         date = d.toString(Qt::ISODate);
174 #else
175         date = lineEditDate->text();
176 #endif
177     }
178 }
179
180 bool SelectDialog::validate(void)
181 {
182     return true;
183 }
184
185 void SelectDialog::next(void)
186 {
187     if (validate())
188         done(1);
189     else {
190         qDebug() << "SelectDialog: invalid data, cancel or correct";
191     }
192 }
193
194 void SelectDialog::reject(void)
195 {
196     done(0);
197 }
198
199 ////////////////////////////////////////////////////////////////////////////////
200 // ScoreDialog based on QDialog
201 ////////////////////////////////////////////////////////////////////////////////
202 ScoreDialog::ScoreDialog(QWidget *parent) : QDialog(parent)
203 {
204     TRACE;
205     resize(800, 400);
206     QFont font;
207     font.setPointSize(fontSize);
208     setFont(font);
209
210     QWidget *centralWidget = new QWidget(this);
211
212     createTable();
213     createButton();
214     
215     createLayout(centralWidget);
216 }
217
218 ScoreDialog::~ScoreDialog()
219 {
220     //if (centralWidget)
221     //  delete centralWidget;
222     if (leftLayout)
223         delete leftLayout;
224     if (rightLayout)
225         delete rightLayout;
226     //if (mainLayout)
227     //  delete mainLayout;
228     if (table)
229         delete table;
230 }
231
232 void ScoreDialog::createLayout(QWidget *parent)
233 {
234     TRACE;
235     leftLayout = new QVBoxLayout;
236     leftLayout->addWidget(table);
237
238     QDialogButtonBox * buttonBoxUp = new QDialogButtonBox(Qt::Vertical);
239     buttonBoxUp->addButton(pushButtonUp, QDialogButtonBox::ActionRole);
240     buttonBoxUp->addButton(pushButtonDown, QDialogButtonBox::ActionRole);
241     buttonBoxUp->addButton(pushButtonNext, QDialogButtonBox::ActionRole);
242
243     QDialogButtonBox * buttonBoxDown = new QDialogButtonBox(Qt::Vertical);
244     buttonBoxDown->addButton(pushButtonFinish, QDialogButtonBox::ActionRole);
245
246     rightLayout = new QVBoxLayout;
247     rightLayout->addWidget(buttonBoxUp);
248     rightLayout->addStretch();
249     rightLayout->addWidget(buttonBoxDown);
250
251     QHBoxLayout *mainLayout = new QHBoxLayout(parent);
252     mainLayout->addLayout(leftLayout);
253     mainLayout->addLayout(rightLayout);
254     setLayout(mainLayout);
255 }
256
257 void ScoreDialog::createTable(QWidget *parent)
258 {
259     TRACE;
260     table = new QTableWidget(ROWS, COLS, parent);
261
262     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
263     table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
264     table->horizontalHeader()->hide();
265
266     table->setStyleSheet(defaultStyleSheet);
267
268     QStringList headers;
269     headers << "" << "Par" << "HCP" << "Score" << "" << "Par" << "HCP" << "Score";
270     table->setVerticalHeaderLabels(headers);
271 }
272
273 void ScoreDialog::createButton(QWidget *parent)
274 {
275     TRACE;
276     Q_UNUSED(parent);
277     pushButtonUp = new QPushButton(tr("+"));
278     connect(pushButtonUp, SIGNAL(clicked()), this, SLOT(up()));
279     
280     pushButtonDown = new QPushButton(tr("-"));
281     connect(pushButtonDown, SIGNAL(clicked()), this, SLOT(down()));
282   
283     pushButtonNext = new QPushButton(tr("Next"));
284     connect(pushButtonNext, SIGNAL(clicked()), this, SLOT(next()));
285
286     pushButtonFinish = new QPushButton(tr("Finish"));
287     connect(pushButtonFinish, SIGNAL(clicked()), this, SLOT(finish()));
288 }
289
290 void ScoreDialog::init(Course *course, Score *score)
291 {
292     TRACE;
293     QTableWidgetItem *par, *hcp, *scoreItem, *holeNum;
294
295     for (int i = 0; i < 18; i++) {
296         par = new QTableWidgetItem(course->getPar(i));
297         hcp = new QTableWidgetItem(course->getHcp(i));
298         if (score)
299             scoreItem = new QTableWidgetItem(score->getScore(i));
300         else
301             scoreItem = new QTableWidgetItem("");
302         holeNum = new QTableWidgetItem(QString::number(i+1));
303
304         holeNum->setTextAlignment(Qt::AlignCenter);
305         holeNum->setFlags(Qt::NoItemFlags);
306         holeNum->setForeground(ScoreColor::holeBg());
307         
308         par->setTextAlignment(Qt::AlignCenter);
309         par->setFlags(Qt::NoItemFlags);
310
311         hcp->setTextAlignment(Qt::AlignCenter);
312         hcp->setFlags(Qt::NoItemFlags);
313         
314         scoreItem->setTextAlignment(Qt::AlignCenter);
315
316         if (i < 9) {
317             table->setItem(ROW_HOLE, i, holeNum);
318             table->setItem(ROW_PAR, i, par);
319             table->setItem(ROW_HCP, i, hcp);
320             table->setItem(ROW_SCORE, i, scoreItem);
321         }
322         else {
323             table->setItem(ROW_HOLE_2, i-9, holeNum);
324             table->setItem(ROW_PAR_2, i-9, par);
325             table->setItem(ROW_HCP_2, i-9, hcp);
326             table->setItem(ROW_SCORE_2, i-9, scoreItem);
327         }
328     }
329     // This - for some unknown reason - does not work ...
330     table->setInputMethodHints(Qt::ImhDigitsOnly);
331
332     // Set focus to 1st cell
333     table->setCurrentCell(ROW_SCORE, 0);
334     if (!score)
335         setDefaultScore(table);
336 }
337
338 // Set default score to par if not set
339 void ScoreDialog::setDefaultScore(QTableWidget *table)
340 {
341     int row = table->currentRow();
342     int col = table->currentColumn();
343   
344     if (row == ROW_SCORE)
345         row = ROW_PAR;
346     else if (row == ROW_SCORE_2)
347         row = ROW_PAR_2;
348     else {
349         qDebug() << "ERROR: unknown row in default score";
350         return;
351     }
352     QTableWidgetItem *par = table->item(row, col);
353     QTableWidgetItem *score = table->item(row + 2, col);
354
355     if (par && score && score->text() == "") {
356         QVariant value(par->text());
357         score->setData(Qt::DisplayRole, value);
358     }
359 }
360
361 void ScoreDialog::up(void)
362 {
363     QTableWidgetItem *item = table->currentItem();
364
365     if (!item) {
366         qWarning() << "ERROR: no current item";
367         return;
368     }
369
370     int i = (item->text()).toInt();
371     QVariant value(i+1);
372     item->setData(Qt::DisplayRole, value);
373 }
374
375 void ScoreDialog::down(void)
376 {
377     QTableWidgetItem *item = table->currentItem();
378
379     if (!item)
380         return;
381
382     int i = (item->text()).toInt();
383     QVariant value(i-1);
384     item->setData(Qt::DisplayRole, value);
385 }
386
387 void ScoreDialog::next(void)
388 {
389     if (table) {
390         QTableWidgetItem *item = table->currentItem();
391         moveToNextCell(item);
392         setDefaultScore(table);
393     }
394 }
395
396 void ScoreDialog::moveToNextCell(QTableWidgetItem *item)
397 {
398     if (!item)
399         return;
400
401     QTableWidget *table = item->tableWidget();
402
403     if (!table)
404         return;
405
406     int row = table->currentRow();
407     int col = table->currentColumn();
408
409     if (col < (COLS-1)) {
410         col++;
411     }
412     else if (col == (COLS-1)) {
413         col = 0;
414         row = (row == ROW_SCORE_2) ? ROW_SCORE : ROW_SCORE_2;
415     }
416     table->setCurrentCell(row, col);
417 }
418
419 void ScoreDialog::results(QVector<QString> &scores)
420 {
421     TRACE;
422     for (int i = 0; i < 9; i++) {
423         QTableWidgetItem *frontItem = table->item(ROW_SCORE, i);
424         QTableWidgetItem *backItem = table->item(ROW_SCORE_2, i);
425
426         if (frontItem)
427             scores[i] = frontItem->text();
428
429         if (backItem)
430             scores[i+9] = backItem->text();
431     }
432 }
433
434 bool ScoreDialog::validate(void)
435 {
436     for (int i=0; i<9; i++) {
437         QTableWidgetItem *frontItem = table->item(ROW_SCORE, i);
438         QTableWidgetItem *backItem = table->item(ROW_SCORE_2, i);
439     
440         if (!frontItem || !backItem)
441             return false;
442     
443         QString str1 = frontItem->text();
444         QString str2 = backItem->text();
445     
446         if (str1.isEmpty() || str2.isEmpty())
447             return false;
448     }
449     return true;
450 }
451
452 void ScoreDialog::finish(void)
453 {
454     if (validate())
455         done(1);
456     else {
457         showNote("Invalid data - cancel or correct");
458     }
459 }
460
461 void ScoreDialog::reject(void)
462 {
463     done(0);
464 }
465
466 void ScoreDialog::showNote(QString msg)
467 {
468 #ifdef Q_WS_MAEMO_5
469     QMaemo5InformationBox::information(this, 
470                                        msg,
471                                        QMaemo5InformationBox::DefaultTimeout);
472 #endif
473 }