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:
Sean Rhea
2010-01-03 19:32:22 -05:00
parent ea8fe63abd
commit e76247a25b
3 changed files with 78 additions and 46 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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