mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
Multi Metrics support for Agenda (#4793)
Agenda used to display entries similar to the Calendar: Primary line for a field, secondary line for one metric, tertiary line for a multi-line field. As the agenda has more space available per line, this change adds support for multiple metrics in the secondary line. Defaults are Duration and TriScore.
This commit is contained in:
committed by
GitHub
parent
6fde458393
commit
24269f0dbf
@@ -48,7 +48,6 @@ AgendaWindow::AgendaWindow(Context *context)
|
||||
setAgendaFutureDays(7);
|
||||
setPrimaryMainField("Route");
|
||||
setPrimaryFallbackField("Workout Code");
|
||||
setSecondaryMetric("workout_time");
|
||||
setShowSecondaryLabel(true);
|
||||
setTertiaryField("Notes");
|
||||
setShowTertiaryFor(0);
|
||||
@@ -69,7 +68,7 @@ AgendaWindow::AgendaWindow(Context *context)
|
||||
connect(context, &Context::rideDeleted, this, &AgendaWindow::updateActivitiesIfInRange);
|
||||
connect(context, &Context::rideChanged, this, &AgendaWindow::updateActivitiesIfInRange);
|
||||
connect(context, &Context::configChanged, this, &AgendaWindow::configChanged);
|
||||
connect(agendaView, &AgendaView::showInTrainMode, this, [context](const CalendarEntry &activity) {
|
||||
connect(agendaView, &AgendaView::showInTrainMode, this, [context](const AgendaEntry &activity) {
|
||||
for (RideItem *rideItem : context->athlete->rideCache->rides()) {
|
||||
if (rideItem != nullptr && rideItem->fileName == activity.reference) {
|
||||
QString filter = buildWorkoutFilter(rideItem);
|
||||
@@ -82,7 +81,7 @@ AgendaWindow::AgendaWindow(Context *context)
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(agendaView, &AgendaView::viewActivity, this, [context](const CalendarEntry &activity) {
|
||||
connect(agendaView, &AgendaView::viewActivity, this, [context](const AgendaEntry &activity) {
|
||||
for (RideItem *rideItem : context->athlete->rideCache->rides()) {
|
||||
if (rideItem != nullptr && rideItem->fileName == activity.reference) {
|
||||
context->notifyRideSelected(rideItem);
|
||||
@@ -181,18 +180,34 @@ AgendaWindow::setPrimaryFallbackField
|
||||
|
||||
|
||||
void
|
||||
AgendaWindow::setSecondaryMetric
|
||||
(const QString &name)
|
||||
AgendaWindow::setSecondaryMetrics
|
||||
(const QString &metrics)
|
||||
{
|
||||
secondaryCombo->setCurrentIndex(std::max(0, secondaryCombo->findData(name)));
|
||||
multiMetricSelector->setSymbols(metrics.split(',', Qt::SkipEmptyParts));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AgendaWindow::setSecondaryMetrics
|
||||
(const QStringList &metrics)
|
||||
{
|
||||
multiMetricSelector->setSymbols(metrics);
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
AgendaWindow::getSecondaryMetric
|
||||
AgendaWindow::getSecondaryMetrics
|
||||
() const
|
||||
{
|
||||
return secondaryCombo->currentData(Qt::UserRole).toString();
|
||||
return multiMetricSelector->getSymbols().join(',');
|
||||
}
|
||||
|
||||
|
||||
QStringList
|
||||
AgendaWindow::getSecondaryMetricsList
|
||||
() const
|
||||
{
|
||||
return multiMetricSelector->getSymbols();
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +305,7 @@ AgendaWindow::configChanged
|
||||
if ( (what & CONFIG_FIELDS)
|
||||
|| (what & CONFIG_USERMETRICS)) {
|
||||
updatePrimaryConfigCombos();
|
||||
updateSecondaryConfigCombo();
|
||||
multiMetricSelector->updateMetrics();
|
||||
updateTertiaryConfigCombo();
|
||||
}
|
||||
if (what & CONFIG_APPEARANCE) {
|
||||
@@ -370,27 +385,31 @@ AgendaWindow::mkControls
|
||||
agendaPastDaysSpin = new QSpinBox();
|
||||
agendaPastDaysSpin->setMaximum(31);
|
||||
agendaPastDaysSpin->setSuffix(" " + tr("day(s)"));
|
||||
|
||||
agendaFutureDaysSpin = new QSpinBox();
|
||||
agendaFutureDaysSpin->setMaximum(31);
|
||||
agendaFutureDaysSpin->setSuffix(" " + tr("day(s)"));
|
||||
|
||||
primaryMainCombo = new QComboBox();
|
||||
primaryFallbackCombo = new QComboBox();
|
||||
secondaryCombo = new QComboBox();
|
||||
showSecondaryLabelCheck = new QCheckBox(tr("Show Label"));
|
||||
|
||||
QStringList summaryMetrics { "workout_time", "triscore" };
|
||||
multiMetricSelector = new MultiMetricSelector(tr("Available Metrics"), tr("Selected Metrics"), summaryMetrics);
|
||||
multiMetricSelector->setContentsMargins(10 * dpiXFactor, 10 * dpiYFactor, 10 * dpiXFactor, 10 * dpiYFactor);
|
||||
multiMetricSelector->setMinimumHeight(300 * dpiYFactor);
|
||||
|
||||
QPushButton *gotoMetrics = new QPushButton(tr("Configure Metrics"));
|
||||
|
||||
showSecondaryLabelCheck = new QCheckBox(tr("Show Names of Metrics"));
|
||||
showTertiaryForCombo = new QComboBox();
|
||||
tertiaryCombo = new QComboBox();
|
||||
updatePrimaryConfigCombos();
|
||||
updateSecondaryConfigCombo();
|
||||
showTertiaryForCombo->addItem(tr("all dates"));
|
||||
showTertiaryForCombo->addItem(tr("today"));
|
||||
showTertiaryForCombo->addItem(tr("no dates"));
|
||||
updateTertiaryConfigCombo();
|
||||
primaryMainCombo->setCurrentText("Route");
|
||||
primaryFallbackCombo->setCurrentText("Workout Code");
|
||||
int secondaryIndex = secondaryCombo->findData("workout_time");
|
||||
if (secondaryIndex >= 0) {
|
||||
secondaryCombo->setCurrentIndex(secondaryIndex);
|
||||
}
|
||||
activityMaxTertiaryLinesSpin = new QSpinBox();
|
||||
activityMaxTertiaryLinesSpin->setRange(1, 5);
|
||||
eventMaxTertiaryLinesSpin = new QSpinBox();
|
||||
@@ -407,7 +426,7 @@ AgendaWindow::mkControls
|
||||
activityForm->addRow(tr("Fallback Field"), primaryFallbackCombo);
|
||||
activityForm->addItem(new QSpacerItem(0, 20 * dpiYFactor));
|
||||
activityForm->addRow(new QLabel(HLO + tr("Metric Line") + HLC));
|
||||
activityForm->addRow(tr("Metric"), secondaryCombo);
|
||||
activityForm->addRow("", gotoMetrics);
|
||||
activityForm->addRow("", showSecondaryLabelCheck);
|
||||
activityForm->addItem(new QSpacerItem(0, 20 * dpiYFactor));
|
||||
activityForm->addRow(new QLabel(HLO + tr("Detail Line") + HLC));
|
||||
@@ -430,13 +449,15 @@ AgendaWindow::mkControls
|
||||
|
||||
QTabWidget *controlsTabs = new QTabWidget();
|
||||
controlsTabs->addTab(activityScroller, tr("Activities"));
|
||||
controlsTabs->addTab(multiMetricSelector, tr("Metrics"));
|
||||
controlsTabs->addTab(eventScroller, tr("Events"));
|
||||
|
||||
connect(agendaPastDaysSpin, &QSpinBox::valueChanged, this, &AgendaWindow::setAgendaPastDays);
|
||||
connect(agendaFutureDaysSpin, &QSpinBox::valueChanged, this, &AgendaWindow::setAgendaFutureDays);
|
||||
connect(primaryMainCombo, &QComboBox::currentIndexChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(primaryFallbackCombo, &QComboBox::currentIndexChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(secondaryCombo, &QComboBox::currentIndexChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(multiMetricSelector, &MultiMetricSelector::selectedChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(gotoMetrics, &QPushButton::clicked, this, [controlsTabs]() { controlsTabs->setCurrentIndex(1); });
|
||||
connect(showTertiaryForCombo, &QComboBox::currentIndexChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(tertiaryCombo, &QComboBox::currentIndexChanged, this, &AgendaWindow::updateActivities);
|
||||
connect(activityMaxTertiaryLinesSpin, &QSpinBox::valueChanged, this, &AgendaWindow::setActivityMaxTertiaryLines);
|
||||
@@ -473,27 +494,6 @@ AgendaWindow::updatePrimaryConfigCombos
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AgendaWindow::updateSecondaryConfigCombo
|
||||
()
|
||||
{
|
||||
QString symbol = getSecondaryMetric();
|
||||
|
||||
secondaryCombo->blockSignals(true);
|
||||
secondaryCombo->clear();
|
||||
const RideMetricFactory &factory = RideMetricFactory::instance();
|
||||
for (const QString &metricSymbol : factory.allMetrics()) {
|
||||
if (metricSymbol.startsWith("compatibility_")) {
|
||||
continue;
|
||||
}
|
||||
secondaryCombo->addItem(Utils::unprotect(factory.rideMetric(metricSymbol)->name()), metricSymbol);
|
||||
}
|
||||
|
||||
secondaryCombo->blockSignals(false);
|
||||
setSecondaryMetric(symbol);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AgendaWindow::updateTertiaryConfigCombo
|
||||
()
|
||||
@@ -514,26 +514,33 @@ AgendaWindow::updateTertiaryConfigCombo
|
||||
}
|
||||
|
||||
|
||||
QHash<QDate, QList<CalendarEntry>>
|
||||
QHash<QDate, QList<AgendaEntry>>
|
||||
AgendaWindow::getActivities
|
||||
(const QDate &firstDay, const QDate &today, const QDate &lastDay) const
|
||||
{
|
||||
QHash<QDate, QList<CalendarEntry>> activities;
|
||||
QHash<QDate, QList<AgendaEntry>> activities;
|
||||
const RideMetricFactory &factory = RideMetricFactory::instance();
|
||||
const RideMetric *rideMetric = factory.rideMetric(getSecondaryMetric());
|
||||
QString rideMetricName;
|
||||
QString rideMetricUnit;
|
||||
if (rideMetric != nullptr) {
|
||||
rideMetricName = rideMetric->name();
|
||||
if ( ! rideMetric->isTime()
|
||||
&& ! rideMetric->isDate()) {
|
||||
rideMetricUnit = rideMetric->units(GlobalContext::context()->useMetricUnits);
|
||||
QList<RideMetric const *> rideMetrics;
|
||||
QStringList rideMetricNames;
|
||||
QStringList rideMetricUnits;
|
||||
for (const QString &metric : getSecondaryMetricsList()) {
|
||||
RideMetric const *rideMetric = factory.rideMetric(metric);
|
||||
if (rideMetric != nullptr) {
|
||||
rideMetrics << rideMetric;
|
||||
rideMetricNames << rideMetric->name();
|
||||
if ( ! rideMetric->isTime()
|
||||
&& ! rideMetric->isDate()) {
|
||||
rideMetricUnits << rideMetric->units(GlobalContext::context()->useMetricUnits);
|
||||
} else {
|
||||
rideMetricUnits << "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int showTertiaryFor = getShowTertiaryFor();
|
||||
for (RideItem *rideItem : context->athlete->rideCache->rides()) {
|
||||
if ( rideItem == nullptr
|
||||
|| ! rideItem->planned
|
||||
|| rideItem->dateTime.date() < firstDay
|
||||
|| rideItem->dateTime.date() > lastDay
|
||||
|| rideItem->hasLinkedActivity()) {
|
||||
@@ -545,7 +552,7 @@ AgendaWindow::getActivities
|
||||
}
|
||||
|
||||
QString sport = rideItem->sport;
|
||||
CalendarEntry activity;
|
||||
AgendaEntry activity;
|
||||
|
||||
QString primaryMain = rideItem->getText(getPrimaryMainField(), "").trimmed();
|
||||
if (! primaryMain.isEmpty()) {
|
||||
@@ -560,42 +567,41 @@ AgendaWindow::getActivities
|
||||
activity.primary = tr("<unknown>");
|
||||
}
|
||||
}
|
||||
if (rideMetric != nullptr && rideMetric->isRelevantForRide(rideItem)) {
|
||||
activity.secondary = rideItem->getStringForSymbol(getSecondaryMetric(), GlobalContext::context()->useMetricUnits);
|
||||
if (! rideMetricUnit.isEmpty()) {
|
||||
activity.secondary += " " + rideMetricUnit;
|
||||
for (int i = 0; i < rideMetrics.count(); ++i) {
|
||||
RideMetric const *rideMetric = rideMetrics[i];
|
||||
if (rideMetric->isRelevantForRide(rideItem)) {
|
||||
QString value = rideItem->getStringForSymbol(rideMetric->symbol(), GlobalContext::context()->useMetricUnits);
|
||||
if (! rideMetricUnits.value(i, "").isEmpty()) {
|
||||
value.append(" " + rideMetricUnits.value(i, ""));
|
||||
}
|
||||
activity.secondaryValues << Utils::unprotect(value);
|
||||
if (isShowSecondaryLabel()) {
|
||||
activity.secondaryLabels << Utils::unprotect(rideMetricNames.value(i, ""));
|
||||
} else {
|
||||
activity.secondaryLabels << "";
|
||||
}
|
||||
}
|
||||
if (isShowSecondaryLabel()) {
|
||||
activity.secondaryMetric = rideMetricName;
|
||||
}
|
||||
} else {
|
||||
activity.secondary = tr("N/A");
|
||||
activity.secondaryMetric = "";
|
||||
}
|
||||
if (activity.secondaryValues.count() == 0) {
|
||||
activity.secondaryValues << tr("N/A");
|
||||
activity.secondaryLabels << "";
|
||||
}
|
||||
if (showTertiaryFor == 0 || (showTertiaryFor == 1 && rideItem->dateTime.date() == today)) {
|
||||
activity.tertiary = rideItem->getText(getTertiaryField(), "").trimmed();
|
||||
activity.tertiary = Utils::unprotect(activity.tertiary);
|
||||
}
|
||||
activity.primary = Utils::unprotect(activity.primary);
|
||||
activity.secondary = Utils::unprotect(activity.secondary);
|
||||
activity.secondaryMetric = Utils::unprotect(activity.secondaryMetric);
|
||||
|
||||
activity.iconFile = IconManager::instance().getFilepath(rideItem);
|
||||
if (rideItem->color.alpha() < 255 || rideItem->planned) {
|
||||
activity.color = GColor(CCALPLANNED);
|
||||
} else {
|
||||
activity.color = rideItem->color;
|
||||
}
|
||||
activity.color = GColor(CCALPLANNED);
|
||||
activity.reference = rideItem->fileName;
|
||||
activity.start = rideItem->dateTime.time();
|
||||
activity.durationSecs = rideItem->getForSymbol("workout_time", GlobalContext::context()->useMetricUnits);
|
||||
activity.type = rideItem->planned ? ENTRY_TYPE_PLANNED_ACTIVITY : ENTRY_TYPE_ACTIVITY;
|
||||
activity.isRelocatable = rideItem->planned;
|
||||
activity.hasTrainMode = rideItem->planned && sport == "Bike" && ! buildWorkoutFilter(rideItem).isEmpty();
|
||||
activity.type = ENTRY_TYPE_PLANNED_ACTIVITY;
|
||||
activity.hasTrainMode = sport == "Bike" && ! buildWorkoutFilter(rideItem).isEmpty();
|
||||
activities[rideItem->dateTime.date()] << activity;
|
||||
}
|
||||
for (auto dayIt = activities.begin(); dayIt != activities.end(); ++dayIt) {
|
||||
std::sort(dayIt.value().begin(), dayIt.value().end(), [](const CalendarEntry &a, const CalendarEntry &b) {
|
||||
std::sort(dayIt.value().begin(), dayIt.value().end(), [](const AgendaEntry &a, const AgendaEntry &b) {
|
||||
if (a.start == b.start) {
|
||||
return a.primary < b.primary;
|
||||
} else {
|
||||
@@ -607,12 +613,12 @@ AgendaWindow::getActivities
|
||||
}
|
||||
|
||||
|
||||
std::pair<QList<CalendarEntry>, QList<CalendarEntry>>
|
||||
std::pair<QList<AgendaEntry>, QList<AgendaEntry>>
|
||||
AgendaWindow::getPhases
|
||||
(const Season &season, const QDate &firstDay) const
|
||||
{
|
||||
QList<CalendarEntry> ongoingPhases;
|
||||
QList<CalendarEntry> futurePhases;
|
||||
QList<AgendaEntry> ongoingPhases;
|
||||
QList<AgendaEntry> futurePhases;
|
||||
for (const Phase &phase : season.phases) {
|
||||
if (phase.getAbsoluteStart().isValid() && phase.getAbsoluteEnd().isValid()) {
|
||||
QString phaseType;
|
||||
@@ -623,37 +629,36 @@ AgendaWindow::getPhases
|
||||
default:
|
||||
phaseType = Phase::types[static_cast<int>(phase.getType()) - static_cast<int>(Phase::phase)];
|
||||
}
|
||||
CalendarEntry entry;
|
||||
AgendaEntry entry;
|
||||
entry.primary = phase.getName();
|
||||
entry.iconFile = ":images/breeze/network-mobile-100.svg";
|
||||
entry.color = GColor(CCALPHASE);
|
||||
entry.reference = phase.id().toString();
|
||||
entry.start = QTime(0, 0, 1);
|
||||
entry.type = ENTRY_TYPE_PHASE;
|
||||
entry.isRelocatable = false;
|
||||
entry.spanStart = phase.getAbsoluteStart();
|
||||
entry.spanEnd = phase.getAbsoluteEnd();
|
||||
int duration = entry.spanStart.daysTo(entry.spanEnd);
|
||||
ShowDaysAsUnit unit = showDaysAs(duration);
|
||||
if (unit == ShowDaysAsUnit::Days) {
|
||||
if (duration > 1) {
|
||||
entry.secondary = tr("%1 • %2 days").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 days").arg(phaseType).arg(duration);
|
||||
} else {
|
||||
entry.secondary = tr("%1 • %2 day").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 day").arg(phaseType).arg(duration);
|
||||
}
|
||||
} else if (unit == ShowDaysAsUnit::Weeks) {
|
||||
duration = daysToWeeks(duration);
|
||||
if (duration > 1) {
|
||||
entry.secondary = tr("%1 • %2 weeks").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 weeks").arg(phaseType).arg(duration);
|
||||
} else {
|
||||
entry.secondary = tr("%1 • %2 week").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 week").arg(phaseType).arg(duration);
|
||||
}
|
||||
} else {
|
||||
duration = daysToMonths(duration);
|
||||
if (duration > 1) {
|
||||
entry.secondary = tr("%1 • %2 months").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 months").arg(phaseType).arg(duration);
|
||||
} else {
|
||||
entry.secondary = tr("%1 • %2 month").arg(phaseType).arg(duration);
|
||||
entry.secondaryValues << tr("%1 • %2 month").arg(phaseType).arg(duration);
|
||||
}
|
||||
}
|
||||
if (phase.getAbsoluteStart() <= firstDay && phase.getAbsoluteEnd() >= firstDay) {
|
||||
@@ -663,10 +668,10 @@ AgendaWindow::getPhases
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(ongoingPhases.begin(), ongoingPhases.end(), [](const CalendarEntry &a, const CalendarEntry &b) {
|
||||
std::sort(ongoingPhases.begin(), ongoingPhases.end(), [](const AgendaEntry &a, const AgendaEntry &b) {
|
||||
return a.spanEnd < b.spanEnd;
|
||||
});
|
||||
std::sort(futurePhases.begin(), futurePhases.end(), [](const CalendarEntry &a, const CalendarEntry &b) {
|
||||
std::sort(futurePhases.begin(), futurePhases.end(), [](const AgendaEntry &a, const AgendaEntry &b) {
|
||||
return a.spanStart < b.spanStart;
|
||||
});
|
||||
|
||||
@@ -674,11 +679,11 @@ AgendaWindow::getPhases
|
||||
}
|
||||
|
||||
|
||||
QHash<QDate, QList<CalendarEntry>>
|
||||
QHash<QDate, QList<AgendaEntry>>
|
||||
AgendaWindow::getEvents
|
||||
(const QDate &firstDay) const
|
||||
{
|
||||
QHash<QDate, QList<CalendarEntry>> events;
|
||||
QHash<QDate, QList<AgendaEntry>> events;
|
||||
QList<Season> tmpSeasons = context->athlete->seasons->seasons;
|
||||
std::sort(tmpSeasons.begin(), tmpSeasons.end(), Season::LessThanForStarts);
|
||||
for (const Season &s : tmpSeasons) {
|
||||
@@ -686,36 +691,34 @@ AgendaWindow::getEvents
|
||||
if ( ( ( firstDay.isValid()
|
||||
&& event.date >= firstDay)
|
||||
|| ! firstDay.isValid())) {
|
||||
CalendarEntry entry;
|
||||
AgendaEntry entry;
|
||||
entry.primary = event.name;
|
||||
if (event.priority == 0) {
|
||||
entry.iconFile = ":images/breeze/task-process-4.svg";
|
||||
entry.secondary = tr("Uncategorized");
|
||||
entry.secondaryValues << tr("Uncategorized");
|
||||
} else if (event.priority == 1) {
|
||||
entry.iconFile = ":images/breeze/task-process-4.svg";
|
||||
entry.secondary = tr("Category A");
|
||||
entry.secondaryValues << tr("Category A");
|
||||
} else if (event.priority == 2) {
|
||||
entry.iconFile = ":images/breeze/task-process-3.svg";
|
||||
entry.secondary = tr("Category B");
|
||||
entry.secondaryValues << tr("Category B");
|
||||
} else if (event.priority == 3) {
|
||||
entry.iconFile = ":images/breeze/task-process-2.svg";
|
||||
entry.secondary = tr("Category C");
|
||||
entry.secondaryValues << tr("Category C");
|
||||
} else if (event.priority == 4) {
|
||||
entry.iconFile = ":images/breeze/task-process-1.svg";
|
||||
entry.secondary = tr("Category D");
|
||||
entry.secondaryValues << tr("Category D");
|
||||
} else {
|
||||
entry.iconFile = ":images/breeze/task-process-0.svg";
|
||||
entry.secondary = tr("Category E");
|
||||
entry.secondaryValues << tr("Category E");
|
||||
}
|
||||
entry.tertiary = event.description.trimmed();
|
||||
entry.color = GColor(CCALEVENT);
|
||||
entry.reference = event.id;
|
||||
entry.start = QTime(0, 0, 0);
|
||||
entry.durationSecs = 0;
|
||||
entry.type = ENTRY_TYPE_EVENT;
|
||||
entry.spanStart = event.date;
|
||||
entry.spanEnd = event.date;
|
||||
entry.isRelocatable = false;
|
||||
events[event.date] << entry;
|
||||
}
|
||||
}
|
||||
@@ -733,9 +736,9 @@ AgendaWindow::updateActivities
|
||||
agendaView->updateDate();
|
||||
return;
|
||||
}
|
||||
QHash<QDate, QList<CalendarEntry>> activities = getActivities(agendaView->firstVisibleDay(), agendaView->selectedDate(), agendaView->lastVisibleDay());
|
||||
std::pair<QList<CalendarEntry>, QList<CalendarEntry>> phases;
|
||||
QHash<QDate, QList<CalendarEntry>> events;
|
||||
QHash<QDate, QList<AgendaEntry>> activities = getActivities(agendaView->firstVisibleDay(), agendaView->selectedDate(), agendaView->lastVisibleDay());
|
||||
std::pair<QList<AgendaEntry>, QList<AgendaEntry>> phases;
|
||||
QHash<QDate, QList<AgendaEntry>> events;
|
||||
QString seasonName;
|
||||
|
||||
tertiaryCombo->setEnabled(getShowTertiaryFor() != 2);
|
||||
@@ -765,7 +768,7 @@ AgendaWindow::updateActivitiesIfInRange
|
||||
|
||||
void
|
||||
AgendaWindow::editPhaseEntry
|
||||
(const CalendarEntry &entry)
|
||||
(const AgendaEntry &entry)
|
||||
{
|
||||
if (entry.type != ENTRY_TYPE_PHASE) {
|
||||
return;
|
||||
@@ -799,7 +802,7 @@ AgendaWindow::editPhaseEntry
|
||||
|
||||
void
|
||||
AgendaWindow::editEventEntry
|
||||
(const CalendarEntry &entry)
|
||||
(const AgendaEntry &entry)
|
||||
{
|
||||
if (entry.type != ENTRY_TYPE_EVENT) {
|
||||
return;
|
||||
@@ -810,13 +813,14 @@ AgendaWindow::editEventEntry
|
||||
for (SeasonEvent &event : s.events) {
|
||||
// FIXME: Ugly comparison required because SeasonEvent::id is not populated
|
||||
if ( event.name == entry.primary
|
||||
&& ( (event.priority == 0 && entry.secondary == tr("Uncategorized"))
|
||||
|| (event.priority == 1 && entry.secondary == tr("Category A"))
|
||||
|| (event.priority == 2 && entry.secondary == tr("Category B"))
|
||||
|| (event.priority == 3 && entry.secondary == tr("Category C"))
|
||||
|| (event.priority == 4 && entry.secondary == tr("Category D"))
|
||||
&& entry.secondaryValues.count() == 1
|
||||
&& ( (event.priority == 0 && entry.secondaryValues[0] == tr("Uncategorized"))
|
||||
|| (event.priority == 1 && entry.secondaryValues[0] == tr("Category A"))
|
||||
|| (event.priority == 2 && entry.secondaryValues[0] == tr("Category B"))
|
||||
|| (event.priority == 3 && entry.secondaryValues[0] == tr("Category C"))
|
||||
|| (event.priority == 4 && entry.secondaryValues[0] == tr("Category D"))
|
||||
|| ( (event.priority < 0 || event.priority > 4)
|
||||
&& entry.secondary == tr("Category E")))
|
||||
&& entry.secondaryValues[0] == tr("Category E")))
|
||||
&& event.description.trimmed() == entry.tertiary
|
||||
&& event.id == entry.reference
|
||||
&& event.date == entry.spanStart
|
||||
|
||||
@@ -42,7 +42,9 @@ class AgendaWindow : public GcChartWindow
|
||||
Q_PROPERTY(int agendaFutureDays READ getAgendaFutureDays WRITE setAgendaFutureDays USER true)
|
||||
Q_PROPERTY(QString primaryMainField READ getPrimaryMainField WRITE setPrimaryMainField USER true)
|
||||
Q_PROPERTY(QString primaryFallbackField READ getPrimaryFallbackField WRITE setPrimaryFallbackField USER true)
|
||||
Q_PROPERTY(QString secondaryMetric READ getSecondaryMetric WRITE setSecondaryMetric USER true)
|
||||
|
||||
Q_PROPERTY(QString secondaryMetrics READ getSecondaryMetrics WRITE setSecondaryMetrics USER true)
|
||||
|
||||
Q_PROPERTY(bool showSecondaryLabel READ isShowSecondaryLabel WRITE setShowSecondaryLabel USER true)
|
||||
Q_PROPERTY(int showTertiaryFor READ getShowTertiaryFor WRITE setShowTertiaryFor USER true)
|
||||
Q_PROPERTY(QString tertiaryField READ getTertiaryField WRITE setTertiaryField USER true)
|
||||
@@ -59,7 +61,8 @@ class AgendaWindow : public GcChartWindow
|
||||
|
||||
QString getPrimaryMainField() const;
|
||||
QString getPrimaryFallbackField() const;
|
||||
QString getSecondaryMetric() const;
|
||||
QString getSecondaryMetrics() const;
|
||||
QStringList getSecondaryMetricsList() const;
|
||||
bool isShowSecondaryLabel() const;
|
||||
int getShowTertiaryFor() const;
|
||||
QString getTertiaryField() const;
|
||||
@@ -71,7 +74,8 @@ class AgendaWindow : public GcChartWindow
|
||||
void setAgendaFutureDays(int days);
|
||||
void setPrimaryMainField(const QString &name);
|
||||
void setPrimaryFallbackField(const QString &name);
|
||||
void setSecondaryMetric(const QString &name);
|
||||
void setSecondaryMetrics(const QString &metrics);
|
||||
void setSecondaryMetrics(const QStringList &metrics);
|
||||
void setShowSecondaryLabel(bool showSecondaryLabel);
|
||||
void setShowTertiaryFor(int showFor);
|
||||
void setTertiaryField(const QString &name);
|
||||
@@ -90,7 +94,7 @@ class AgendaWindow : public GcChartWindow
|
||||
QSpinBox *agendaFutureDaysSpin;
|
||||
QComboBox *primaryMainCombo;
|
||||
QComboBox *primaryFallbackCombo;
|
||||
QComboBox *secondaryCombo;
|
||||
MultiMetricSelector *multiMetricSelector;
|
||||
QCheckBox *showSecondaryLabelCheck;
|
||||
QComboBox *showTertiaryForCombo;
|
||||
QComboBox *tertiaryCombo;
|
||||
@@ -100,17 +104,16 @@ class AgendaWindow : public GcChartWindow
|
||||
|
||||
void mkControls();
|
||||
void updatePrimaryConfigCombos();
|
||||
void updateSecondaryConfigCombo();
|
||||
void updateTertiaryConfigCombo();
|
||||
QHash<QDate, QList<CalendarEntry>> getActivities(const QDate &firstDay, const QDate &today, const QDate &lastDay) const;
|
||||
std::pair<QList<CalendarEntry>, QList<CalendarEntry>> getPhases(const Season &season, const QDate &firstDay) const;
|
||||
QHash<QDate, QList<CalendarEntry>> getEvents(const QDate &firstDay) const;
|
||||
QHash<QDate, QList<AgendaEntry>> getActivities(const QDate &firstDay, const QDate &today, const QDate &lastDay) const;
|
||||
std::pair<QList<AgendaEntry>, QList<AgendaEntry>> getPhases(const Season &season, const QDate &firstDay) const;
|
||||
QHash<QDate, QList<AgendaEntry>> getEvents(const QDate &firstDay) const;
|
||||
|
||||
private slots:
|
||||
void updateActivities();
|
||||
void updateActivitiesIfInRange(RideItem *rideItem);
|
||||
void editPhaseEntry(const CalendarEntry &entry);
|
||||
void editEventEntry(const CalendarEntry &entry);
|
||||
void editPhaseEntry(const AgendaEntry &entry);
|
||||
void editEventEntry(const AgendaEntry &entry);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -377,7 +377,7 @@ ActivityTree::ActivityTree
|
||||
|
||||
QVariant data = item->data(1, AgendaEntryDelegate::EntryRole);
|
||||
if (! data.isNull()) {
|
||||
CalendarEntry entry = data.value<CalendarEntry>();
|
||||
AgendaEntry entry = data.value<AgendaEntry>();
|
||||
if (entry.type == ENTRY_TYPE_PLANNED_ACTIVITY) {
|
||||
emit viewActivity(entry);
|
||||
}
|
||||
@@ -406,7 +406,7 @@ ActivityTree::setFutureDays
|
||||
|
||||
void
|
||||
ActivityTree::fillEntries
|
||||
(const QHash<QDate, QList<CalendarEntry>> &activities)
|
||||
(const QHash<QDate, QList<AgendaEntry>> &activities)
|
||||
{
|
||||
QDate today = selectedDate();
|
||||
QDate pastFirst = today.addDays(-pastDays);
|
||||
@@ -417,13 +417,13 @@ ActivityTree::fillEntries
|
||||
bool todayHasPlanned = false;
|
||||
QList<QDate> missedDays;
|
||||
QList<QDate> upcomingDays;
|
||||
QHash<QDate, QList<CalendarEntry>> missedEntries;
|
||||
QList<CalendarEntry> todayEntries;
|
||||
QHash<QDate, QList<CalendarEntry>> upcomingEntries;
|
||||
QHash<QDate, QList<AgendaEntry>> missedEntries;
|
||||
QList<AgendaEntry> todayEntries;
|
||||
QHash<QDate, QList<AgendaEntry>> upcomingEntries;
|
||||
for (QDate date = pastFirst; date <= futureLast; date = date.addDays(1)) {
|
||||
QList<CalendarEntry> dateEntries;
|
||||
QList<AgendaEntry> dateEntries;
|
||||
dateEntries = activities.value(date);
|
||||
for (const CalendarEntry &entry : dateEntries) {
|
||||
for (const AgendaEntry &entry : dateEntries) {
|
||||
if (entry.type == ENTRY_TYPE_PLANNED_ACTIVITY) {
|
||||
if (date < today) {
|
||||
if (! missedDays.contains(date)) {
|
||||
@@ -547,29 +547,30 @@ ActivityTree::createContextMenu
|
||||
if (entryData.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
CalendarEntry entry = entryData.value<CalendarEntry>();
|
||||
AgendaEntry entry = entryData.value<AgendaEntry>();
|
||||
if (entry.type != ENTRY_TYPE_PLANNED_ACTIVITY) {
|
||||
return nullptr;
|
||||
}
|
||||
QMenu *contextMenu = new QMenu(this);
|
||||
contextMenu->addAction(tr("View planned activity..."), this, [this, entry]() {
|
||||
emit viewActivity(entry);
|
||||
});
|
||||
if (entry.hasTrainMode) {
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(tr("Show in train mode..."), this, [this, entry]() {
|
||||
emit showInTrainMode(entry);
|
||||
});
|
||||
}
|
||||
contextMenu->addAction(tr("View planned activity..."), this, [this, entry]() {
|
||||
emit viewActivity(entry);
|
||||
});
|
||||
return contextMenu;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ActivityTree::addEntries
|
||||
(const QDate &today, const QDate &date, const QList<CalendarEntry> &activities, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
(const QDate &today, const QDate &date, const QList<AgendaEntry> &activities, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
{
|
||||
int activityIdx = 0;
|
||||
for (const CalendarEntry &activity : activities) {
|
||||
for (const AgendaEntry &activity : activities) {
|
||||
QTreeWidgetItem *entryItem = new QTreeWidgetItem();
|
||||
QString diffStr;
|
||||
int diff = date.daysTo(today);
|
||||
@@ -607,7 +608,7 @@ ActivityTree::addEntries
|
||||
|
||||
void
|
||||
PhaseTree::fillEntries
|
||||
(const std::pair<QList<CalendarEntry>, QList<CalendarEntry>> &phases)
|
||||
(const std::pair<QList<AgendaEntry>, QList<AgendaEntry>> &phases)
|
||||
{
|
||||
QDate today = selectedDate();
|
||||
if (! today.isValid()) {
|
||||
@@ -665,7 +666,7 @@ PhaseTree::createContextMenu
|
||||
if (entryData.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
CalendarEntry entry = entryData.value<CalendarEntry>();
|
||||
AgendaEntry entry = entryData.value<AgendaEntry>();
|
||||
if (entry.type != ENTRY_TYPE_PHASE) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -679,9 +680,9 @@ PhaseTree::createContextMenu
|
||||
|
||||
void
|
||||
PhaseTree::addEntries
|
||||
(const QDate &today, const QList<CalendarEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
(const QDate &today, const QList<AgendaEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
{
|
||||
for (const CalendarEntry &phase : phases) {
|
||||
for (const AgendaEntry &phase : phases) {
|
||||
QTreeWidgetItem *entryItem = new QTreeWidgetItem();
|
||||
QString diffStr;
|
||||
int diffStart = today.daysTo(phase.spanStart);
|
||||
@@ -760,7 +761,7 @@ PhaseTree::addEntries
|
||||
|
||||
void
|
||||
EventTree::fillEntries
|
||||
(const QHash<QDate, QList<CalendarEntry>> &events)
|
||||
(const QHash<QDate, QList<AgendaEntry>> &events)
|
||||
{
|
||||
QDate today = selectedDate();
|
||||
if (! today.isValid()) {
|
||||
@@ -807,7 +808,7 @@ EventTree::createContextMenu
|
||||
if (entryData.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
CalendarEntry entry = entryData.value<CalendarEntry>();
|
||||
AgendaEntry entry = entryData.value<AgendaEntry>();
|
||||
if (entry.type != ENTRY_TYPE_EVENT) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -821,10 +822,10 @@ EventTree::createContextMenu
|
||||
|
||||
void
|
||||
EventTree::addEntries
|
||||
(const QDate &today, const QList<CalendarEntry> &events, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
(const QDate &today, const QList<AgendaEntry> &events, QTreeWidgetItem *parent, const Fonts &fonts)
|
||||
{
|
||||
bool firstEntry = true;
|
||||
for (const CalendarEntry &event : events) {
|
||||
for (const AgendaEntry &event : events) {
|
||||
QTreeWidgetItem *entryItem = new QTreeWidgetItem();
|
||||
int diffStart = today.daysTo(event.spanStart);
|
||||
QString diffStr;
|
||||
@@ -899,16 +900,16 @@ AgendaView::AgendaView
|
||||
|
||||
activityTree = new ActivityTree();
|
||||
connect(activityTree, &ActivityTree::dayChanged, this, [this](const QDate &date) { emit dayChanged(date); });
|
||||
connect(activityTree, &ActivityTree::showInTrainMode, this, [this](const CalendarEntry &activity) { emit showInTrainMode(activity); });
|
||||
connect(activityTree, &ActivityTree::viewActivity, this, [this](const CalendarEntry &activity) { emit viewActivity(activity); });
|
||||
connect(activityTree, &ActivityTree::showInTrainMode, this, [this](const AgendaEntry &activity) { emit showInTrainMode(activity); });
|
||||
connect(activityTree, &ActivityTree::viewActivity, this, [this](const AgendaEntry &activity) { emit viewActivity(activity); });
|
||||
|
||||
phaseTree = new PhaseTree();
|
||||
connect(phaseTree, &PhaseTree::dayChanged, this, [this](const QDate &date) { emit dayChanged(date); });
|
||||
connect(phaseTree, &PhaseTree::editPhaseEntry, this, [this](const CalendarEntry &phase) { emit editPhaseEntry(phase); });
|
||||
connect(phaseTree, &PhaseTree::editPhaseEntry, this, [this](const AgendaEntry &phase) { emit editPhaseEntry(phase); });
|
||||
|
||||
eventTree = new EventTree();
|
||||
connect(eventTree, &EventTree::dayChanged, this, [this](const QDate &date) { emit dayChanged(date); });
|
||||
connect(eventTree, &EventTree::editEventEntry, this, [this](const CalendarEntry &event) { emit editEventEntry(event); });
|
||||
connect(eventTree, &EventTree::editEventEntry, this, [this](const AgendaEntry &event) { emit editEventEntry(event); });
|
||||
|
||||
QGridLayout* headLayout = new QGridLayout();
|
||||
headLayout->setColumnStretch(0, 1);
|
||||
@@ -965,7 +966,7 @@ AgendaView::setFutureDays
|
||||
|
||||
void
|
||||
AgendaView::fillEntries
|
||||
(const QHash<QDate, QList<CalendarEntry>> &activities, std::pair<QList<CalendarEntry>, QList<CalendarEntry>> &phases , const QHash<QDate, QList<CalendarEntry>> &events, const QString &seasonName, bool isFiltered)
|
||||
(const QHash<QDate, QList<AgendaEntry>> &activities, std::pair<QList<AgendaEntry>, QList<AgendaEntry>> &phases , const QHash<QDate, QList<AgendaEntry>> &events, const QString &seasonName, bool isFiltered)
|
||||
{
|
||||
if (! seasonName.isNull()) {
|
||||
seasonLabel->setText(tr("Season: %1").arg(seasonName));
|
||||
|
||||
@@ -92,13 +92,13 @@ public:
|
||||
|
||||
void setPastDays(int days);
|
||||
void setFutureDays(int days);
|
||||
void fillEntries(const QHash<QDate, QList<CalendarEntry>> &activities);
|
||||
void fillEntries(const QHash<QDate, QList<AgendaEntry>> &activities);
|
||||
QDate firstVisibleDay() const;
|
||||
QDate lastVisibleDay() const;
|
||||
|
||||
signals:
|
||||
void showInTrainMode(const CalendarEntry &activity);
|
||||
void viewActivity(const CalendarEntry &activity);
|
||||
void showInTrainMode(const AgendaEntry &activity);
|
||||
void viewActivity(const AgendaEntry &activity);
|
||||
|
||||
protected:
|
||||
QMenu *createContextMenu(const QModelIndex &index) override;
|
||||
@@ -107,7 +107,7 @@ private:
|
||||
int pastDays = 7;
|
||||
int futureDays = 7;
|
||||
|
||||
void addEntries(const QDate &today, const QDate &date, const QList<CalendarEntry> &activities, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
void addEntries(const QDate &today, const QDate &date, const QList<AgendaEntry> &activities, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
};
|
||||
|
||||
|
||||
@@ -115,16 +115,16 @@ class PhaseTree : public AgendaTree {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void fillEntries(const std::pair<QList<CalendarEntry>, QList<CalendarEntry>> &phases);
|
||||
void fillEntries(const std::pair<QList<AgendaEntry>, QList<AgendaEntry>> &phases);
|
||||
|
||||
signals:
|
||||
void editPhaseEntry(const CalendarEntry &entry);
|
||||
void editPhaseEntry(const AgendaEntry &entry);
|
||||
|
||||
protected:
|
||||
QMenu *createContextMenu(const QModelIndex &index) override;
|
||||
|
||||
private:
|
||||
void addEntries(const QDate &today, const QList<CalendarEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
void addEntries(const QDate &today, const QList<AgendaEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
};
|
||||
|
||||
|
||||
@@ -132,16 +132,16 @@ class EventTree : public AgendaTree {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void fillEntries(const QHash<QDate, QList<CalendarEntry>> &events);
|
||||
void fillEntries(const QHash<QDate, QList<AgendaEntry>> &events);
|
||||
|
||||
signals:
|
||||
void editEventEntry(const CalendarEntry &entry);
|
||||
void editEventEntry(const AgendaEntry &entry);
|
||||
|
||||
protected:
|
||||
virtual QMenu *createContextMenu(const QModelIndex &index);
|
||||
|
||||
private:
|
||||
void addEntries(const QDate &today, const QList<CalendarEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
void addEntries(const QDate &today, const QList<AgendaEntry> &phases, QTreeWidgetItem *parent, const Fonts &fonts);
|
||||
};
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
void setDateRange(const DateRange &dateRange);
|
||||
void setPastDays(int days);
|
||||
void setFutureDays(int days);
|
||||
void fillEntries(const QHash<QDate, QList<CalendarEntry>> &activities, std::pair<QList<CalendarEntry>, QList<CalendarEntry>> &phases, const QHash<QDate, QList<CalendarEntry>> &events, const QString &seasonName, bool isFiltered);
|
||||
void fillEntries(const QHash<QDate, QList<AgendaEntry>> &activities, std::pair<QList<AgendaEntry>, QList<AgendaEntry>> &phases, const QHash<QDate, QList<AgendaEntry>> &events, const QString &seasonName, bool isFiltered);
|
||||
|
||||
QDate firstVisibleDay() const;
|
||||
QDate lastVisibleDay() const;
|
||||
@@ -166,10 +166,10 @@ public slots:
|
||||
void setEventMaxTertiaryLines(int maxTertiaryLines);
|
||||
|
||||
signals:
|
||||
void showInTrainMode(const CalendarEntry &activity);
|
||||
void viewActivity(const CalendarEntry &activity);
|
||||
void editPhaseEntry(const CalendarEntry &entry);
|
||||
void editEventEntry(const CalendarEntry &entry);
|
||||
void showInTrainMode(const AgendaEntry &activity);
|
||||
void viewActivity(const AgendaEntry &activity);
|
||||
void editPhaseEntry(const AgendaEntry &entry);
|
||||
void editEventEntry(const AgendaEntry &entry);
|
||||
void dayChanged(const QDate &date);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -35,6 +35,22 @@
|
||||
#define ENTRY_TYPE_OTHER 99
|
||||
|
||||
|
||||
struct AgendaEntry {
|
||||
QString primary;
|
||||
QStringList secondaryValues;
|
||||
QStringList secondaryLabels;
|
||||
QString tertiary;
|
||||
QString iconFile;
|
||||
QColor color;
|
||||
QString reference;
|
||||
QTime start;
|
||||
int type = 0;
|
||||
bool hasTrainMode = false;
|
||||
QDate spanStart = QDate();
|
||||
QDate spanEnd = QDate();
|
||||
};
|
||||
|
||||
|
||||
struct CalendarEntry {
|
||||
QString primary;
|
||||
QString secondary;
|
||||
@@ -80,6 +96,7 @@ struct CalendarSummary {
|
||||
QList<std::pair<QString, QString>> keyValues;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AgendaEntry)
|
||||
Q_DECLARE_METATYPE(CalendarEntry)
|
||||
Q_DECLARE_METATYPE(CalendarEntryLayout)
|
||||
Q_DECLARE_METATYPE(CalendarDay)
|
||||
|
||||
@@ -36,7 +36,7 @@ static bool toolTipHeadlineEntry(const QPoint &pos, QAbstractItemView *view, con
|
||||
static bool toolTipDayEntry(const QPoint &pos, QAbstractItemView *view, const CalendarDay &day, int idx);
|
||||
static bool toolTipMore(const QPoint &pos, QAbstractItemView *view, const CalendarDay &day);
|
||||
static QRect paintHeadline(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index, HitTester &headlineTester, const QString &dateFormat, int pressedEntryIdx, int leftMargin, int rightMargin, int topMargin, int lineSpacing, int radius);
|
||||
static void paintMetric(QPainter *painter, const QRect &rect, const QFont::Weight &valueWeight, const QFont::Weight &labelWeight, const QString &value, const QString &label);
|
||||
static int paintMetric(QPainter *painter, const QRect &rect, const QFont::Weight &valueWeight, const QFont::Weight &labelWeight, const QString &value, const QString &label, bool first = true);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1318,7 +1318,7 @@ AgendaEntryDelegate::paint
|
||||
if (column < 0) {
|
||||
column = index.column();
|
||||
}
|
||||
CalendarEntry entry = index.data(EntryRole).value<CalendarEntry>();
|
||||
AgendaEntry entry = index.data(EntryRole).value<AgendaEntry>();
|
||||
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
@@ -1360,7 +1360,6 @@ AgendaEntryDelegate::paint
|
||||
QFontMetrics line1FM(line1Font);
|
||||
const int lineSpacing = attributes.lineSpacing * dpiYFactor;
|
||||
const int lineHeight = line1FM.height();
|
||||
// const int radius = 4 * dpiXFactor;
|
||||
const int iconInnerSpacing = 4 * dpiXFactor;
|
||||
const int iconTextSpacing = attributes.iconTextSpacing * dpiXFactor;
|
||||
const int iconWidth = 2 * lineHeight + lineSpacing;
|
||||
@@ -1396,9 +1395,16 @@ AgendaEntryDelegate::paint
|
||||
painter->setFont(line1Font);
|
||||
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip, primary);
|
||||
painter->restore();
|
||||
if (! entry.secondary.isEmpty()) {
|
||||
textRect.translate(0, lineHeight + lineSpacing);
|
||||
paintMetric(painter, textRect, secondaryWeight, secondaryMetricWeight, entry.secondary, entry.secondaryMetric);
|
||||
textRect.translate(0, lineHeight + lineSpacing);
|
||||
int advance = 0;
|
||||
for (int i = 0; i < entry.secondaryValues.count(); ++i) {
|
||||
QString value = entry.secondaryValues[i];
|
||||
QString label = entry.secondaryLabels.value(i, "");
|
||||
textRect.setLeft(textRect.left() + advance);
|
||||
if (textRect.width() <= 20 * dpiXFactor) {
|
||||
break;
|
||||
}
|
||||
advance = paintMetric(painter, textRect, secondaryWeight, secondaryMetricWeight, value, label, i == 0);
|
||||
}
|
||||
if (! entry.tertiary.isEmpty()) {
|
||||
painter->save();
|
||||
@@ -1447,7 +1453,7 @@ AgendaEntryDelegate::sizeHint
|
||||
if (! data.isNull()) {
|
||||
const int lineSpacing = attributes.lineSpacing * dpiYFactor;
|
||||
const int lineHeight = option.fontMetrics.height();
|
||||
CalendarEntry entry = data.value<CalendarEntry>();
|
||||
AgendaEntry entry = data.value<AgendaEntry>();
|
||||
int tertiaryHeight = 0;
|
||||
if (! entry.tertiary.isEmpty()) {
|
||||
const int iconWidth = 2 * lineHeight + lineSpacing;
|
||||
@@ -1485,7 +1491,7 @@ AgendaEntryDelegate::hasToolTip
|
||||
if (! index.isValid()) {
|
||||
return false;
|
||||
}
|
||||
CalendarEntry entry = index.data(EntryRole).value<CalendarEntry>();
|
||||
AgendaEntry entry = index.data(EntryRole).value<AgendaEntry>();
|
||||
QString text(entry.tertiary.trimmed());
|
||||
if (text.isEmpty()) {
|
||||
return false;
|
||||
@@ -1872,24 +1878,41 @@ paintHeadline
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static int
|
||||
paintMetric
|
||||
(QPainter *painter, const QRect &rect, const QFont::Weight &valueWeight, const QFont::Weight &labelWeight, const QString &value, const QString &label)
|
||||
(QPainter *painter, const QRect &rect, const QFont::Weight &valueWeight, const QFont::Weight &labelWeight, const QString &value, const QString &label, bool first)
|
||||
{
|
||||
int advance = 0;
|
||||
painter->save();
|
||||
QFont font = painter->font();
|
||||
font.setWeight(valueWeight);
|
||||
painter->setFont(font);
|
||||
QFontMetrics valueFM(font);
|
||||
int valueWidth = valueFM.horizontalAdvance(value);
|
||||
painter->drawText(rect, Qt::AlignLeft | Qt::AlignTop, value);
|
||||
QString fullValue(value);
|
||||
if (! first) {
|
||||
fullValue.prepend(" • ");
|
||||
}
|
||||
int valueWidth = valueFM.horizontalAdvance(fullValue);
|
||||
advance += valueWidth;
|
||||
painter->drawText(rect, Qt::AlignLeft | Qt::AlignTop, fullValue);
|
||||
if (! label.isEmpty()) {
|
||||
QRect labelRect(rect);
|
||||
labelRect.setX(rect.x() + valueWidth + valueFM.horizontalAdvance(" "));
|
||||
int spaceAdvance = valueFM.horizontalAdvance(" ");
|
||||
advance += spaceAdvance;
|
||||
labelRect.setX(rect.x() + valueWidth + spaceAdvance);
|
||||
font.setWeight(labelWeight);
|
||||
QFontMetrics labelFM(font);
|
||||
int labelWidth;
|
||||
painter->setFont(font);
|
||||
if (labelWeight <= QFont::Light) {
|
||||
QRect labelBounds = painter->boundingRect(labelRect, Qt::AlignLeft | Qt::AlignTop, label);
|
||||
labelWidth = labelBounds.width();
|
||||
} else {
|
||||
labelWidth = labelFM.horizontalAdvance(label);
|
||||
}
|
||||
painter->drawText(labelRect, Qt::AlignLeft | Qt::AlignTop, label);
|
||||
advance += labelWidth;
|
||||
}
|
||||
painter->restore();
|
||||
return advance;
|
||||
}
|
||||
|
||||
@@ -239,18 +239,18 @@ class AgendaEntryDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Roles {
|
||||
EntryRole = Qt::UserRole, // [CalendarEntry] Entry to be displayed
|
||||
EntryDateRole // [bool] Date of the CalendarEntry
|
||||
EntryRole = Qt::UserRole, // [AgendaEntry] Entry to be displayed
|
||||
EntryDateRole // [bool] Date of the AgendaEntry
|
||||
};
|
||||
|
||||
struct Attributes {
|
||||
QMargins padding; // Padding of the element
|
||||
QFont::Weight primaryWeight = QFont::Medium; // Primary row
|
||||
QFont::Weight primaryHoverWeight = QFont::DemiBold; // Primary row (hovered)
|
||||
QFont::Weight secondaryWeight = QFont::Light; // Secondary row
|
||||
QFont::Weight secondaryHoverWeight = QFont::DemiBold; // Secondary row (hovered)
|
||||
QFont::Weight primaryHoverWeight = QFont::Medium; // Primary row (hovered)
|
||||
QFont::Weight secondaryWeight = QFont::Medium; // Secondary row
|
||||
QFont::Weight secondaryHoverWeight = QFont::Medium; // Secondary row (hovered)
|
||||
QFont::Weight secondaryMetricWeight = QFont::ExtraLight; // Metric in the secondary row
|
||||
QFont::Weight secondaryMetricHoverWeight = QFont::Normal; // Metric in the secondary row (hovered)
|
||||
QFont::Weight secondaryMetricHoverWeight = QFont::ExtraLight; // Metric in the secondary row (hovered)
|
||||
int lineSpacing = 2; // Vertical spacing between primary and secondary row (dpiYFactor not applied)
|
||||
int iconTextSpacing = 10; // Horizontal spacing between icon and text (dpiXFactor not applied)
|
||||
float tertiaryDimLevel = 0.5; // Dimming amount for tertiary row
|
||||
|
||||
@@ -199,6 +199,7 @@ MultiMetricSelector::MultiMetricSelector
|
||||
: QWidget(parent)
|
||||
{
|
||||
filterEdit = new QLineEdit();
|
||||
filterEdit->setClearButtonEnabled(true);
|
||||
filterEdit->setPlaceholderText(tr("Filter..."));
|
||||
|
||||
availList = new QListWidget();
|
||||
|
||||
Reference in New Issue
Block a user