mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
remove ride map from RideCalendar
I think the previous implementation could have referenced already-deleted RideItem objects during calls to Split Ride. This commit removes the calendar's own map of RideItems, and instead uses the list of rides in MainWindow::allRideItems. Because I use binary search on that list, this implementation should be just as fast as the old one. But because I don't hang on to any RideItem pointers beyond a single call to RideCalendar::paintCell, it shouldn't be vulnerable to referencing already-deleted RideItem objects.
This commit is contained in:
@@ -129,7 +129,7 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
splitter->setContentsMargins(10, 20, 10, 10); // attempting to follow some UI guides
|
||||
|
||||
// Analysis toolbox contents
|
||||
calendar = new RideCalendar;
|
||||
calendar = new RideCalendar(this);
|
||||
calendar->setHome(home);
|
||||
|
||||
treeWidget = new QTreeWidget;
|
||||
@@ -197,7 +197,7 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
last = new RideItem(RIDE_TYPE, home.path(),
|
||||
name, dt, zones(), notesFileName);
|
||||
allRides->addChild(last);
|
||||
calendar->addRide(reinterpret_cast<RideItem*>(last));
|
||||
calendar->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +445,7 @@ MainWindow::addRide(QString name, bool bSelect /*=true*/)
|
||||
++index;
|
||||
}
|
||||
allRides->insertChild(index, last);
|
||||
calendar->addRide(last);
|
||||
calendar->update();
|
||||
criticalPowerWindow->newRideAdded();
|
||||
if (bSelect)
|
||||
{
|
||||
@@ -473,14 +473,11 @@ MainWindow::removeCurrentRide()
|
||||
}
|
||||
}
|
||||
|
||||
calendar->removeRide(item);
|
||||
if (x>0) {
|
||||
itemToSelect = allRides->child(x-1);
|
||||
calendar->addRide(reinterpret_cast<RideItem*>(itemToSelect));
|
||||
}
|
||||
if ((x+1)<allRides->childCount()) {
|
||||
itemToSelect = allRides->child(x+1);
|
||||
calendar->addRide(reinterpret_cast<RideItem*>(itemToSelect));
|
||||
}
|
||||
|
||||
QString strOldFileName = item->fileName;
|
||||
@@ -508,6 +505,7 @@ MainWindow::removeCurrentRide()
|
||||
|
||||
treeWidget->setCurrentItem(itemToSelect);
|
||||
rideTreeWidgetSelectionChanged();
|
||||
calendar->update();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
|
||||
#include "RideItem.h"
|
||||
#include "RideCalendar.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Settings.h"
|
||||
|
||||
RideCalendar::RideCalendar(QWidget *parent)
|
||||
: QCalendarWidget(parent)
|
||||
#include <algorithm>
|
||||
|
||||
RideCalendar::RideCalendar(MainWindow *parent) :
|
||||
QCalendarWidget(parent), mainWindow(parent)
|
||||
{
|
||||
this->setFirstDayOfWeek(Qt::Monday);
|
||||
this->addWorkoutCode(QString("race"), QColor(255,128,128));
|
||||
@@ -21,9 +25,72 @@ RideCalendar::RideCalendar(QWidget *parent)
|
||||
this->addWorkoutCode(QString("gym"), QColor(Qt::lightGray));
|
||||
};
|
||||
|
||||
struct RideIter
|
||||
{
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef const RideItem *value_type;
|
||||
typedef int difference_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
|
||||
MainWindow *mainWindow;
|
||||
int i;
|
||||
|
||||
RideIter() : mainWindow(NULL), i(0) {}
|
||||
RideIter(MainWindow *mainWindow, int i = 0) : mainWindow(mainWindow), i(i) {}
|
||||
const RideItem *operator*() {
|
||||
assert(mainWindow);
|
||||
assert(i < mainWindow->allRideItems()->childCount());
|
||||
return dynamic_cast<const RideItem*>(mainWindow->allRideItems()->child(i));
|
||||
}
|
||||
RideIter operator++() { /* preincrement */ ++i; return *this; }
|
||||
RideIter operator++(int) { RideIter result(mainWindow, i); ++i; return result; }
|
||||
const RideIter &operator+=(int j) { i += j; return *this; }
|
||||
};
|
||||
|
||||
bool operator==(const RideIter &a, const RideIter &b) { return a.i == b.i; }
|
||||
bool operator!=(const RideIter &a, const RideIter &b) { return a.i != b.i; }
|
||||
int operator-(const RideIter &a, const RideIter &b) { return a.i - b.i; }
|
||||
|
||||
struct RideItemDateLessThan
|
||||
{
|
||||
bool operator()(const RideItem *a, const RideItem *b) { return a->dateTime < b->dateTime; }
|
||||
};
|
||||
|
||||
struct RideItemDateGreaterThan
|
||||
{
|
||||
bool operator()(const RideItem *a, const RideItem *b) { return a->dateTime > b->dateTime; }
|
||||
};
|
||||
|
||||
void RideCalendar::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
|
||||
{
|
||||
if (!_rides.contains(date)) {
|
||||
QMultiMap<QDateTime, const RideItem*> ridesToday;
|
||||
RideIter begin(mainWindow, 0);
|
||||
RideIter end(mainWindow, mainWindow->allRideItems()->childCount());
|
||||
|
||||
boost::shared_ptr<QSettings> settings = GetApplicationSettings();
|
||||
bool ascending = settings->value(GC_ALLRIDES_ASCENDING, Qt::Checked).toInt() > 0;
|
||||
RideIter i;
|
||||
if (ascending) {
|
||||
RideItemDateLessThan comp;
|
||||
RideItem search(0, "", "", QDateTime(date), NULL, "");
|
||||
i = std::lower_bound(begin, end, &search, comp);
|
||||
}
|
||||
else {
|
||||
RideItemDateGreaterThan comp;
|
||||
RideItem search(0, "", "", QDateTime(date.addDays(1)), NULL, "");
|
||||
i = std::upper_bound(begin, end, &search, comp);
|
||||
}
|
||||
|
||||
while (i != end) {
|
||||
const RideItem *ride = *i;
|
||||
if (ride->dateTime.date() != date)
|
||||
break;
|
||||
ridesToday.insert(ride->dateTime, ride);
|
||||
++i;
|
||||
}
|
||||
|
||||
if (ridesToday.isEmpty()) {
|
||||
QCalendarWidget::paintCell(painter, rect, date);
|
||||
return;
|
||||
}
|
||||
@@ -33,29 +100,16 @@ void RideCalendar::paintCell(QPainter *painter, const QRect &rect, const QDate &
|
||||
* Fill in the text and color to some default
|
||||
*/
|
||||
QRect textRect;
|
||||
int number = _rides.count(date);
|
||||
int number = ridesToday.size();
|
||||
float count = 1;
|
||||
int startY, stopY;
|
||||
QPen pen(Qt::SolidLine);
|
||||
painter->setPen(pen);
|
||||
pen.setCapStyle(Qt::SquareCap);
|
||||
QMultiMap<QDateTime, RideItem*> ridesToday;
|
||||
RideItem * ride;
|
||||
QFont font = painter->font();
|
||||
font.setPointSize(font.pointSize() - 2);
|
||||
painter->setFont(font);
|
||||
|
||||
/*
|
||||
* Loop over all the matching rides, and record the time.
|
||||
* That way, the entries are sorted earliest -> latest.
|
||||
*/
|
||||
QMultiMap<QDate, RideItem *>::const_iterator j = _rides.find(date);
|
||||
while (j != _rides.end() && j.key() == date) {
|
||||
ride = j.value();
|
||||
ridesToday.insert(ride->dateTime, ride);
|
||||
++j;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over all the rides for today, and record colour and text.
|
||||
*/
|
||||
@@ -136,25 +190,6 @@ void RideCalendar::addWorkoutCode(QString string, QColor color)
|
||||
workoutCodes[string] = color;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a ride, to a specific date.
|
||||
*/
|
||||
void RideCalendar::addRide(RideItem* ride)
|
||||
{
|
||||
_rides.insert(ride->dateTime.date(), ride);
|
||||
update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the info for a current ride.
|
||||
*/
|
||||
void RideCalendar::removeRide(RideItem* ride)
|
||||
{
|
||||
QDate date = ride->dateTime.date();
|
||||
_rides.erase(_rides.find(date, ride));
|
||||
update();
|
||||
}
|
||||
|
||||
/*
|
||||
* We extend QT's QCalendarWidget's sizeHint() so we claim a little bit of
|
||||
* extra space.
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
#include <QCalendarWidget>
|
||||
#include <QMultiMap>
|
||||
#include "RideItem.h"
|
||||
class MainWindow;
|
||||
|
||||
class RideCalendar : public QCalendarWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RideCalendar(QWidget *parent = 0);
|
||||
void removeRide(RideItem*);
|
||||
void addRide(RideItem*);
|
||||
RideCalendar(MainWindow *parent);
|
||||
QSize sizeHint() const;
|
||||
void setHome(const QDir&);
|
||||
void addWorkoutCode(QString, QColor);
|
||||
@@ -21,9 +20,9 @@ protected:
|
||||
void paintCell(QPainter *, const QRect &, const QDate &) const;
|
||||
|
||||
private:
|
||||
QMultiMap<QDate, RideItem*> _rides;
|
||||
QMap<QString, QColor> workoutCodes;
|
||||
QDir home;
|
||||
MainWindow *mainWindow;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user