From 3cfa9048cfb33daecfe2e381ce7ca22f1a133632 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Mon, 11 Mar 2013 12:14:43 +0000 Subject: [PATCH] Reinstate mini calendar on sidebar This is the first step to reinstating the calendar on the analysis view sidebar. Next step is to enhance it to show multiple months and then to refactor the diary sidebar GcCalendar to use it. --- src/GcCalendar.cpp | 357 ++++++++++++++++++++++++++++++++++++++++++++ src/GcCalendar.h | 41 +++++ src/MainWindow.cpp | 8 +- src/MainWindow.h | 2 + src/RideNavigator.h | 2 + 5 files changed, 409 insertions(+), 1 deletion(-) diff --git a/src/GcCalendar.cpp b/src/GcCalendar.cpp index bbe6d12cb..dc97f2977 100644 --- a/src/GcCalendar.cpp +++ b/src/GcCalendar.cpp @@ -702,3 +702,360 @@ GcCalendar::setSummary() } } + +GcMiniCalendar::GcMiniCalendar(MainWindow *main) : main(main) +{ + setContentsMargins(0,0,0,0); + setAutoFillBackground(true); + + month = year = 0; + _ride = NULL; + + setStyleSheet("QLabel { color: gray; }"); + layout = new QVBoxLayout(this); + layout->setSpacing(0); + layout->setContentsMargins(10,10,10,10); + + black.setColor(QPalette::WindowText, Qt::gray); + white.setColor(QPalette::WindowText, Qt::white); + grey.setColor(QPalette::WindowText, Qt::gray); + + // get the model + fieldDefinitions = main->rideMetadata()->getFields(); + calendarModel = new GcCalendarModel(this, &fieldDefinitions, main); + calendarModel->setSourceModel(main->listView->sqlModel); + + QHBoxLayout *line = new QHBoxLayout; + line->setSpacing(0); + line->setContentsMargins(0,0,0,0); + + QFont font; + font.setPointSize(12); + left = new GcLabel("<", this); + left->setAutoFillBackground(false); + left->setPalette(white); + left->setFont(font); + left->setAlignment(Qt::AlignLeft); + line->addWidget(left); + connect (left, SIGNAL(clicked()), this, SLOT(previous())); + + font.setPointSize(12); + monthName = new GcLabel("January 2012", this); + monthName->setAutoFillBackground(false); + monthName->setPalette(white); + monthName->setFont(font); + monthName->setAlignment(Qt::AlignCenter); + line->addWidget(monthName); + + font.setPointSize(12); + right = new GcLabel(">", this); + right->setAutoFillBackground(false); + right->setPalette(white); + right->setFont(font); + right->setAlignment(Qt::AlignRight); + line->addWidget(right); + connect (right, SIGNAL(clicked()), this, SLOT(next())); + + QWidget *month = new QWidget(this); + month->setContentsMargins(0,0,0,0); + month->setFixedWidth(180); + month->setFixedHeight(180); + QGridLayout *dayLayout = new QGridLayout(month); + dayLayout->setSpacing(1); + dayLayout->setContentsMargins(0,0,0,0); + dayLayout->addLayout(line, 0,0,1,7); + layout->addWidget(month, Qt::AlignCenter); + + font.setWeight(QFont::Normal); + + // Mon + font.setPointSize(9); + GcLabel *day = new GcLabel("Mon", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 0); + + // Tue + day = new GcLabel("Tue", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 1); + + // Wed + day = new GcLabel("Wed", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 2); + + // Thu + day = new GcLabel("Thu", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 3); + + // Fri + day = new GcLabel("Fri", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 4); + + // Sat + day = new GcLabel("Sat", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 5); + + // Sun + day = new GcLabel("Sun", this); + day->setFont(font); + day->setAutoFillBackground(false); + day->setPalette(white); + day->setFont(font); + day->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(day, 1, 6); + + signalMapper = new QSignalMapper(this); + font.setPointSize(11); + for (int row=2; row<8; row++) { + + for (int col=0; col < 7; col++) { + + GcLabel *d = new GcLabel(QString("%1").arg((row-2)*7+col), this); + d->setFont(font); + d->setAutoFillBackground(false); + d->setPalette(grey); + d->setStyleSheet("color: gray;"); + d->setAlignment(Qt::AlignCenter); + dayLayout->addWidget(d,row,col); + + // we like squares + d->setFixedHeight(22); + d->setFixedWidth(22); + + dayLabels << d; + + if (row== 3 && col == 4) d->setSelected(true); + + connect (d, SIGNAL(clicked()), signalMapper, SLOT(map())); + signalMapper->setMapping(d, (row-2)*7+col); + } + } + layout->addStretch(); + + // day clicked + connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(dayClicked(int))); + + // refresh on these events... + connect(main, SIGNAL(rideAdded(RideItem*)), this, SLOT(refresh())); + connect(main, SIGNAL(rideDeleted(RideItem*)), this, SLOT(refresh())); + connect(main, SIGNAL(configChanged()), this, SLOT(refresh())); + + // set up for current selections + refresh(); +} + +void +GcMiniCalendar::refresh() +{ + calendarModel->setMonth(month, year); + repaint(); +} + +bool +GcMiniCalendar::event(QEvent *e) +{ + if (e->type() != QEvent::ToolTip && e->type() != QEvent::Paint && e->type() != QEvent::Destroy && + e->type() != QEvent::LayoutRequest) { + main->setBubble(""); + //qDebug()<<"event"<type(); + } + + if (e->type() == QEvent::Paint) { + // fill the background + QPainter painter(this); + QRect all(0,0,width(),height()); + //painter.fillRect(all, QColor("#B3B4BA")); + painter.fillRect(all, QColor(Qt::white)); + } + + int n=0; + if (e->type() == QEvent::ToolTip) { + + // are we hovering over a label? + foreach(GcLabel *label, dayLabels) { + if (label->underMouse()) { + if (dayLabels.at(n)->text() == "") return false; + + // select a ride if there is one for this one? + int row = n / 7; + int col = n % 7; + + QModelIndex p = calendarModel->index(row,col); + QStringList files = calendarModel->data(p, GcCalendarModel::FilenamesRole).toStringList(); + + QPoint pos = dynamic_cast(e)->pos(); + + // Popup bubble for ride + if (files.count()) { + if (files[0] == "calendar") ; // handle planned rides + else main->setBubble(files.at(0), mapToGlobal(pos+QPoint(+2,+2))); + } + } + n++; + } + } + return QWidget::event(e); +} + +void +GcMiniCalendar::dayClicked(int i) +{ + if (dayLabels.at(i)->text() == "") return; + + // select a ride if there is one for this one? + int row = i / 7; + int col = i % 7; + + + QModelIndex p = calendarModel->index(row,col); + QStringList files = calendarModel->data(p, GcCalendarModel::FilenamesRole).toStringList(); + + if (files.count()) // if more than one file cycle through them? + main->selectRideFile(QFileInfo(files[0]).fileName()); + +} + +void +GcMiniCalendar::previous() +{ + QList allDates = main->metricDB->db()->getAllDates(); + qSort(allDates); + + // begin of month + QDateTime bom(QDate(year,month,01), QTime(0,0,0)); + for(int i=allDates.count()-1; i>0; i--) { + if (allDates.at(i) < bom) { + + QDate date = allDates.at(i).date(); + calendarModel->setMonth(date.month(), date.year()); + + // find the day in the calendar... + for (int day=42; day>0;day--) { + + QModelIndex p = calendarModel->index(day/7,day%7); + QDate heredate = calendarModel->date(p); + if (date == heredate) { + // select this ride... + QStringList files = calendarModel->data(p, GcCalendarModel::FilenamesRole).toStringList(); + if (files.count()) main->selectRideFile(QFileInfo(files[0]).fileName()); + } + } + break; + } + } +} + +void +GcMiniCalendar::next() +{ + QList allDates = main->metricDB->db()->getAllDates(); + qSort(allDates); + + // end of month + QDateTime eom(QDate(year,month,01).addMonths(1), QTime(00,00,00)); + for(int i=0; i= eom) { + + QDate date = allDates.at(i).date(); + calendarModel->setMonth(date.month(), date.year()); + + // find the day in the calendar... + for (int day=0; day<42;day++) { + + QModelIndex p = calendarModel->index(day/7,day%7); + QDate heredate = calendarModel->date(p); + if (date == heredate) { + // select this ride... + QStringList files = calendarModel->data(p, GcCalendarModel::FilenamesRole).toStringList(); + if (files.count()) main->selectRideFile(QFileInfo(files[0]).fileName()); + } + } + break; + } + } +} + +void +GcMiniCalendar::setRide(RideItem *ride) +{ + _ride = ride; + + QDate when; + if (_ride && _ride->ride()) when = _ride->dateTime.date(); + else when = QDate::currentDate(); + + // refresh the model + if (when.month() != month || when.year() != year) { + calendarModel->setMonth(when.month(), when.year()); + year = when.year(); + month = when.month(); + + monthName->setText(when.toString("MMMM yyyy")); + } + + // now reapply for each row/col of calendar... + for (int row=0; row<6; row++) { + for (int col=0; col < 7; col++) { + + GcLabel *d = dayLabels.at(row*7+col); + QModelIndex p = calendarModel->index(row,col); + QDate date = calendarModel->date(p); + + if (date.month() != month || date.year() != year) { + d->setText(""); + d->setBg(false); + d->setSelected(false); + } else { + d->setText(QString("%1").arg(date.day())); + + // what color should it be? + // for taste we /currently/ just set to bg to + // highlight there is a ride there, colors /will/ come + // back later when worked out a way of making it look + // nice and not garish + QList colors = p.data(Qt::BackgroundRole).value >(); + if (colors.count()) { + d->setBg(true); + d->setPalette(black); + d->setBgColor(colors.at(0)); // use first always + } else { + d->setBg(false); + d->setPalette(white); + } + if (date == when) { + d->setSelected(true); + d->setPalette(white); + } else d->setSelected(false); + } + } + } + refresh(); +} diff --git a/src/GcCalendar.h b/src/GcCalendar.h index 0d8e76e27..63fdcaaf4 100644 --- a/src/GcCalendar.h +++ b/src/GcCalendar.h @@ -64,6 +64,47 @@ protected: QColor bgColor; }; +class GcMiniCalendar : public QWidget +{ + Q_OBJECT + + public: + + GcMiniCalendar(MainWindow *); + + public slots: + + void setRide(RideItem *ride); + void refresh(); + + void dayClicked(int num); // for when a day is selected + void next(); + void previous(); + + bool event(QEvent *e); + + signals: + + protected: + MainWindow *main; + RideItem *_ride; + int month, year; + + QVBoxLayout *layout; + + GcLabel *left, *right; // < ... > + GcLabel *monthName; // January 2012 + GcLabel *dayNames[7]; // Mon .. Sun + + QList dayLabels; // 1 .. 31 + + QSignalMapper *signalMapper; // for mapping dayLabels "clicked" + + QPalette black, grey, white; + QList fieldDefinitions; + GcCalendarModel *calendarModel; +}; + class GcCalendar : public QWidget // not a GcWindow - belongs on sidebar { Q_OBJECT diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 20a2e8a64..2fb0d2834 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -659,12 +659,16 @@ MainWindow::MainWindow(const QDir &home) : intervalSplitter->setCollapsible(0, false); intervalSplitter->setCollapsible(1, false); + GcSplitterItem *calendarItem = new GcSplitterItem(tr("Calendar"), iconFromPNG(":images/sidebar/calendar.png"), this); + gcMiniCalendar = new GcMiniCalendar(this); + calendarItem->addWidget(gcMiniCalendar); + analItem = new GcSplitterItem(tr("Activities"), iconFromPNG(":images/sidebar/folder.png"), this); QAction *moreAnalAct = new QAction(iconFromPNG(":images/sidebar/extra.png"), tr("Menu"), this); analItem->addAction(moreAnalAct); connect(moreAnalAct, SIGNAL(triggered(void)), this, SLOT(analysisPopup())); - analItem->addWidget(activityHistory); + intervalItem = new GcSplitterItem(tr("Intervals"), iconFromPNG(":images/mac/stop.png"), this); QAction *moreIntervalAct = new QAction(iconFromPNG(":images/sidebar/extra.png"), tr("Menu"), this); intervalItem->addAction(moreIntervalAct); @@ -672,6 +676,7 @@ MainWindow::MainWindow(const QDir &home) : intervalItem->addWidget(intervalSplitter); analSidebar = new GcSplitter(Qt::Vertical); + analSidebar->addWidget(calendarItem); analSidebar->addWidget(analItem); analSidebar->addWidget(intervalItem); analSidebar->prepare(cyclist, "analysis"); @@ -1235,6 +1240,7 @@ MainWindow::rideTreeWidgetSelectionChanged() diaryWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); trainWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); gcCalendar->setRide(ride); + gcMiniCalendar->setRide(ride); enableSaveButton(); // should it be enabled or not? diff --git a/src/MainWindow.h b/src/MainWindow.h index 4f941c168..243fb1245 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -57,6 +57,7 @@ class IntervalSummaryWindow; class RideNavigator; class GcToolBar; class GcCalendar; +class GcMiniCalendar; class GcBubble; class LTMSidebar; class LionFullScreen; @@ -415,6 +416,7 @@ class MainWindow : public QMainWindow QMenu *windowMenu; GcBubble *bubble; GcCalendar *gcCalendar; + GcMiniCalendar *gcMiniCalendar; // each view has its own controls XXX more to come QStackedWidget *masterControls, diff --git a/src/RideNavigator.h b/src/RideNavigator.h index 3972497a9..f4e459713 100644 --- a/src/RideNavigator.h +++ b/src/RideNavigator.h @@ -39,6 +39,7 @@ class SearchFilterBox; class DiaryWindow; class BUGFIXQSortFilterProxyModel; class DataFilter; +class GcMiniCalendar; // // The RideNavigator @@ -62,6 +63,7 @@ class RideNavigator : public GcWindow friend class ::GroupByModel; friend class ::DiaryWindow; friend class ::GcCalendar; + friend class ::GcMiniCalendar; friend class ::DataFilter; public: