mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 00:28:42 +00:00
Add Calendar
This commit is contained in:
committed by
Sean Rhea
parent
55f0b19ff5
commit
ec8d3e9949
@@ -44,7 +44,7 @@
|
||||
#include <qwt_data.h>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include "DaysScaleDraw.h"
|
||||
|
||||
#include "RideCalendar.h"
|
||||
#include "DatePickerDialog.h"
|
||||
#include "ToolsDialog.h"
|
||||
#include "MetricAggregator.h"
|
||||
@@ -136,6 +136,9 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
setCentralWidget(splitter);
|
||||
splitter->setContentsMargins(10, 20, 10, 10); // attempting to follow some UI guides
|
||||
|
||||
calendar = new RideCalendar;
|
||||
calendar->setFirstDayOfWeek(Qt::Monday);
|
||||
|
||||
treeWidget = new QTreeWidget;
|
||||
treeWidget->setColumnCount(3);
|
||||
treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
@@ -143,7 +146,7 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
treeWidget->header()->resizeSection(0,70);
|
||||
treeWidget->header()->resizeSection(1,95);
|
||||
treeWidget->header()->resizeSection(2,70);
|
||||
treeWidget->setMaximumWidth(250);
|
||||
//treeWidget->setMaximumWidth(250);
|
||||
treeWidget->header()->hide();
|
||||
treeWidget->setAlternatingRowColors (true);
|
||||
treeWidget->setIndentation(5);
|
||||
@@ -151,7 +154,19 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
allRides = new QTreeWidgetItem(treeWidget, FOLDER_TYPE);
|
||||
allRides->setText(0, tr("All Rides"));
|
||||
treeWidget->expandItem(allRides);
|
||||
splitter->addWidget(treeWidget);
|
||||
|
||||
leftLayout = new QSplitter;
|
||||
leftLayout->setOrientation(Qt::Vertical);
|
||||
leftLayout->addWidget(calendar);
|
||||
leftLayout->setCollapsible(0, false);
|
||||
leftLayout->addWidget(treeWidget);
|
||||
leftLayout->setCollapsible(1, false);
|
||||
splitter->addWidget(leftLayout);
|
||||
splitter->setCollapsible(0, false);
|
||||
QVariant calendarSizes = settings->value(GC_SETTINGS_CALENDAR_SIZES);
|
||||
if (calendarSizes != QVariant()) {
|
||||
leftLayout->restoreState(calendarSizes.toByteArray());
|
||||
}
|
||||
|
||||
QTreeWidgetItem *last = NULL;
|
||||
QStringListIterator i(RideFileFactory::instance().listRideFiles(home));
|
||||
@@ -162,6 +177,39 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
last = new RideItem(RIDE_TYPE, home.path(),
|
||||
name, dt, &zones, notesFileName);
|
||||
allRides->addChild(last);
|
||||
|
||||
/*
|
||||
* We want to display these things inside the Calendar.
|
||||
* Pick a colour (this should really be configurable)
|
||||
* - red for races
|
||||
* - yellow for sick days
|
||||
* - green for rides
|
||||
*/
|
||||
QString notesPath = home.absolutePath() + "/" + notesFileName;
|
||||
QFile notesFile(notesPath);
|
||||
QColor color(Qt::green);
|
||||
QString line("Ride");
|
||||
if (notesFile.exists()) {
|
||||
if (notesFile.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream in(¬esFile);
|
||||
line = in.readLine();
|
||||
notesFile.close();
|
||||
if (line.contains("race", Qt::CaseInsensitive)) {
|
||||
color = QColor(Qt::red);
|
||||
line = "RACE";
|
||||
}
|
||||
if (line.contains("sick", Qt::CaseInsensitive)) {
|
||||
color = QColor(Qt::red);
|
||||
}
|
||||
if (line.contains("swim", Qt::CaseInsensitive)) {
|
||||
color = QColor(Qt::blue);
|
||||
}
|
||||
if (line.contains("gym", Qt::CaseInsensitive)) {
|
||||
color = QColor(Qt::gray);
|
||||
}
|
||||
}
|
||||
}
|
||||
calendar->addEvent(dt.date(), line, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +308,7 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
|
||||
tabWidget->addTab(window, "Ride Plot");
|
||||
splitter->addWidget(tabWidget);
|
||||
splitter->setCollapsible(1, false);
|
||||
|
||||
QVariant splitterSizes = settings->value(GC_SETTINGS_SPLITTER_SIZES);
|
||||
if (splitterSizes != QVariant())
|
||||
@@ -505,6 +554,10 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
|
||||
////////////////////////////// Signals //////////////////////////////
|
||||
|
||||
connect(calendar, SIGNAL(clicked(const QDate &)),
|
||||
this, SLOT(dateChanged(const QDate &)));
|
||||
connect(leftLayout, SIGNAL(splitterMoved(int,int)),
|
||||
this, SLOT(leftLayoutMoved()));
|
||||
connect(treeWidget, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(rideSelected()));
|
||||
connect(splitter, SIGNAL(splitterMoved(int,int)),
|
||||
@@ -1130,6 +1183,7 @@ MainWindow::rideSelected()
|
||||
}
|
||||
|
||||
ride = (RideItem*) which;
|
||||
calendar->setSelectedDate(ride->dateTime.date());
|
||||
rideSummary->setHtml(ride->htmlSummary());
|
||||
rideSummary->setAlignment(Qt::AlignCenter);
|
||||
if (ride) {
|
||||
@@ -1186,7 +1240,7 @@ void MainWindow::getBSFactors(float &timeBS, float &distanceBS)
|
||||
BSdays.setValue(30); // by default look back no more than 30 days
|
||||
|
||||
// if there are rides, find most recent ride so we count back from there:
|
||||
if (allRides->childCount() > 0)
|
||||
if (allRides->childCount() > 0)
|
||||
lastRideItem = (RideItem*) allRides->child(allRides->childCount() - 1);
|
||||
else
|
||||
lastRideItem = ride; // not enough rides, use current ride
|
||||
@@ -1553,7 +1607,7 @@ void MainWindow::generateWeeklySummary()
|
||||
|
||||
// Now open any notes associated with the new ride.
|
||||
rideNotes->setPlainText("");
|
||||
QString notesPath = home.absolutePath() + "/" + ride->notesFileName;
|
||||
QString notesPath = home.absolutePath() + "/" + ride->notesFileName;
|
||||
QFile notesFile(notesPath);
|
||||
|
||||
if (notesFile.exists()) {
|
||||
@@ -1561,7 +1615,7 @@ void MainWindow::generateWeeklySummary()
|
||||
QTextStream in(¬esFile);
|
||||
rideNotes->setPlainText(in.readAll());
|
||||
notesFile.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(
|
||||
this, tr("Read Error"),
|
||||
@@ -1569,7 +1623,7 @@ void MainWindow::generateWeeklySummary()
|
||||
}
|
||||
}
|
||||
|
||||
currentNotesFile = ride->notesFileName;
|
||||
currentNotesFile = ride->notesFileName;
|
||||
currentNotesChanged = false;
|
||||
}
|
||||
|
||||
@@ -1591,7 +1645,7 @@ void MainWindow::saveNotes()
|
||||
tr("Can't rename %1 to %2")
|
||||
.arg(tmpPath).arg(notesPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(
|
||||
this, tr("Write Error"),
|
||||
@@ -1647,7 +1701,13 @@ MainWindow::closeEvent(QCloseEvent*)
|
||||
saveNotes();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MainWindow::leftLayoutMoved()
|
||||
{
|
||||
settings->setValue(GC_SETTINGS_CALENDAR_SIZES, leftLayout->saveState());
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::splitterMoved()
|
||||
{
|
||||
settings->setValue(GC_SETTINGS_SPLITTER_SIZES, splitter->saveState());
|
||||
@@ -2112,3 +2172,23 @@ void MainWindow::setHistWidgets(RideItem *rideItem)
|
||||
withZerosCheckBox->setEnabled(false);
|
||||
lnYHistCheckBox->setEnabled(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* This slot gets called when the user picks a new date, using the mouse,
|
||||
* in the calendar. We have to adjust TreeView to match.
|
||||
*/
|
||||
void MainWindow::dateChanged(const QDate &date)
|
||||
{
|
||||
for (int i = 0; i < allRides->childCount(); i++)
|
||||
{
|
||||
ride = (RideItem*) allRides->child(i);
|
||||
if (ride->dateTime.date() == date) {
|
||||
treeWidget->scrollToItem(allRides->child(i),
|
||||
QAbstractItemView::EnsureVisible);
|
||||
treeWidget->setCurrentItem(allRides->child(i));
|
||||
i = allRides->childCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ class QwtPlotPicker;
|
||||
class QwtPlotZoomer;
|
||||
class RideFile;
|
||||
class Zones;
|
||||
class RideCalendar;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@@ -54,6 +55,7 @@ class MainWindow : public QMainWindow
|
||||
|
||||
private slots:
|
||||
void rideSelected();
|
||||
void leftLayoutMoved();
|
||||
void splitterMoved();
|
||||
void newCyclist();
|
||||
void openCyclist();
|
||||
@@ -93,6 +95,7 @@ class MainWindow : public QMainWindow
|
||||
void importRideToDB();
|
||||
void scanForMissing();
|
||||
void generateWeeklySummary();
|
||||
void dateChanged(const QDate &);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -105,6 +108,7 @@ class MainWindow : public QMainWindow
|
||||
|
||||
QSettings *settings;
|
||||
|
||||
RideCalendar *calendar;
|
||||
QSplitter *splitter;
|
||||
QTreeWidget *treeWidget;
|
||||
QTabWidget *tabWidget;
|
||||
@@ -140,6 +144,7 @@ class MainWindow : public QMainWindow
|
||||
QwtPlotCurve *weeklyBaselineCurve;
|
||||
QwtPlotCurve *weeklyBSBaselineCurve;
|
||||
QwtPlot *weeklyBSPlot;
|
||||
QSplitter *leftLayout;
|
||||
|
||||
QwtPlotCurve *weeklyBSCurve;
|
||||
QwtPlotCurve *weeklyRICurve;
|
||||
|
||||
79
src/RideCalendar.cpp
Normal file
79
src/RideCalendar.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <QCalendarWidget>
|
||||
#include <QMultiMap>
|
||||
#include <QPainter>
|
||||
#include <QObject>
|
||||
#include <QDate>
|
||||
#include <QAbstractItemView>
|
||||
#include <QSize>
|
||||
#include <QTextCharFormat>
|
||||
#include <QPen>
|
||||
|
||||
#include "RideCalendar.h"
|
||||
|
||||
RideCalendar::RideCalendar(QWidget *parent)
|
||||
: QCalendarWidget(parent)
|
||||
{
|
||||
};
|
||||
|
||||
void RideCalendar::addEvent(QDate date, QString string, QColor color)
|
||||
{
|
||||
_text[date] = string;
|
||||
_color[date] = color;
|
||||
update();
|
||||
}
|
||||
|
||||
void RideCalendar::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
|
||||
{
|
||||
if (_text.contains(date)) {
|
||||
painter->save();
|
||||
|
||||
/*
|
||||
* Draw a rectangle in the color specified. If this is the
|
||||
* currently selected date, draw a black outline.
|
||||
*/
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setCapStyle(Qt::SquareCap);
|
||||
painter->setBrush(_color[date]);
|
||||
if (date == selectedDate()) {
|
||||
pen.setColor(Qt::black);
|
||||
pen.setWidth(1);
|
||||
} else {
|
||||
pen.setColor(_color[date]);
|
||||
}
|
||||
painter->setPen(pen);
|
||||
/*
|
||||
* We have to draw to height-1 and width-1 because Qt draws outlines
|
||||
* outside the box by default.
|
||||
*/
|
||||
painter->drawRect(rect.x(), rect.y(), rect.width() - 1, rect.height() - 1);
|
||||
|
||||
/*
|
||||
* Display the text.
|
||||
*/
|
||||
pen.setColor(Qt::black);
|
||||
painter->setPen(pen);
|
||||
QString text = QString::number(date.day());
|
||||
text = text + "\n" + _text[date];
|
||||
QFont font = painter->font();
|
||||
font.setPointSize(font.pointSize() - 2);
|
||||
painter->setFont(font);
|
||||
painter->drawText(rect, Qt::AlignHCenter | Qt::TextWordWrap, text);
|
||||
|
||||
painter->restore();
|
||||
} else {
|
||||
QCalendarWidget::paintCell(painter, rect, date);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We extend QT's QCalendarWidget's sizeHint() so we claim a little bit of
|
||||
* extra space.
|
||||
*/
|
||||
QSize RideCalendar::sizeHint() const
|
||||
{
|
||||
QSize hint = QCalendarWidget::sizeHint();
|
||||
hint.setHeight(hint.height() * 2);
|
||||
hint.setWidth(hint.width() * 2);
|
||||
return hint;
|
||||
}
|
||||
|
||||
25
src/RideCalendar.h
Normal file
25
src/RideCalendar.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef EVENT_CALENDAR_WIDGET_H
|
||||
#define EVENT_CALENDAR_WIDGET_H
|
||||
|
||||
#include <QCalendarWidget>
|
||||
#include <QMultiMap>
|
||||
|
||||
class RideCalendar : public QCalendarWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RideCalendar(QWidget *parent = 0);
|
||||
|
||||
void addEvent(QDate, QString, QColor);
|
||||
QSize sizeHint() const;
|
||||
|
||||
protected:
|
||||
void paintCell(QPainter *, const QRect &, const QDate &) const;
|
||||
|
||||
private:
|
||||
QMap<QDate, QString> _text;
|
||||
QMap<QDate, QColor> _color;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,7 @@
|
||||
#define GC_SETTINGS_MAIN_Y "mainwindow/y"
|
||||
#define GC_SETTINGS_MAIN_GEOM "mainwindow/geometry"
|
||||
#define GC_SETTINGS_SPLITTER_SIZES "mainwindow/splitterSizes"
|
||||
#define GC_SETTINGS_CALENDAR_SIZES "mainwindow/calendarSizes"
|
||||
#define GC_DATETIME_FORMAT "ddd MMM dd, yyyy, hh:mm AP"
|
||||
#define GC_UNIT "unit"
|
||||
#define GC_SETTINGS_LAST_IMPORT_PATH "mainwindow/lastImportPath"
|
||||
|
||||
@@ -75,7 +75,8 @@ HEADERS += \
|
||||
Settings.h \
|
||||
XmlRideFile.h \
|
||||
ManualRideFile.h \
|
||||
ManualRideDialog.h
|
||||
ManualRideDialog.h \
|
||||
RideCalendar.h
|
||||
|
||||
SOURCES += \
|
||||
AllPlot.cpp \
|
||||
@@ -121,7 +122,8 @@ SOURCES += \
|
||||
SplitRideDialog.cpp \
|
||||
XmlRideFile.cpp \
|
||||
ManualRideFile.cpp \
|
||||
ManualRideDialog.cpp
|
||||
ManualRideDialog.cpp \
|
||||
RideCalendar.cpp
|
||||
|
||||
# win32 is after SOURCES and HEADERS so we can remove Serial.h/.cpp
|
||||
win32 {
|
||||
|
||||
Reference in New Issue
Block a user