Add TimelineMonthRow and TimelineMonthModel

These are a lot like TimelineDayRow and TimelineDayModel, and are
supposed to go in the timeline’s header too, but instead of showing the
day number, they show the month name.

I still need to know the with of each day, because the month must be as
wide as all shown days, that may not be all the days in that month, in
the first and last months, at least.

Usually i will show two or three months, so i thing is is fair to keep a
list of all the months and their days, rather than compute them each
time the name or the day count, two times per month, are requested.
This commit is contained in:
jordi fita mas 2025-01-13 18:32:02 +01:00
parent 94b5faa9d8
commit 66e12d5019
5 changed files with 254 additions and 4 deletions

View File

@ -14,6 +14,7 @@ qt_add_qml_module(${PROJECT_NAME}
timelinedaymodel.cpp timelinedaymodel.h
timelinelistmodel.cpp timelinelistmodel.h
timelinemodel.cpp timelinemodel.h
timelinemonthmodel.cpp timelinemonthmodel.h
timelineview.cpp timelineview.h
QML_FILES
ErrorNotification.qml
@ -25,6 +26,7 @@ qt_add_qml_module(${PROJECT_NAME}
ReservationsPage.qml
SelectableLabel.qml
TimelineDayRow.qml
TimelineMonthRow.qml
)
set_target_properties(${PROJECT_NAME} PROPERTIES

View File

@ -40,6 +40,7 @@ Page {
text: name
}
header: Pane {
height: timelineList.headerItem.height
z: 2
Label {
@ -89,10 +90,18 @@ Page {
rightPadding: 0
z: 2
TimelineDayRow {
dayWidth: page.dayWidth
fromDate: page.fromDate
toDate: page.toDate
Column {
TimelineMonthRow {
dayWidth: page.dayWidth
fromDate: page.fromDate
toDate: page.toDate
}
TimelineDayRow {
dayWidth: page.dayWidth
fromDate: page.fromDate
toDate: page.toDate
}
}
}
}

38
src/TimelineMonthRow.qml Normal file
View File

@ -0,0 +1,38 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
Control {
id: control
property real dayWidth: 24
property alias fromDate: model.fromDate
property alias toDate: model.toDate
contentItem: Row {
Repeater {
model: model
delegate: Label {
required property int dayCount
required property string display
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: display
width: control.dayWidth * dayCount
background: Rectangle {
border.color: "red"
border.width: 1
color: "lightgreen"
}
}
}
}
TimelineMonthModel {
id: model
}
}

141
src/timelinemonthmodel.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "timelinemonthmodel.h"
#include <QVariant>
#include <algorithm>
using namespace Qt::Literals::StringLiterals;
namespace {
void advanceMonth(QCalendar::YearMonthDay &ymd)
{
if (ymd.month == 12) {
ymd.month = 1;
ymd.year++;
} else {
ymd.month++;
}
}
} // namespace
TimelineMonthModel::TimelineMonthModel(QObject *parent)
: QAbstractListModel(parent)
, m_fromDate()
, m_toDate()
, m_locale()
, m_months()
{}
int TimelineMonthModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_months.length();
}
QVariant TimelineMonthModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= rowCount()) {
return {};
}
Month month = m_months.at(index.row());
switch (role) {
case Qt::DisplayRole:
return m_locale.standaloneMonthName(month.number);
case DayCount:
return month.days;
}
return {};
}
QHash<int, QByteArray> TimelineMonthModel::roleNames() const
{
QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
roles[DayCount] = "dayCount"_ba;
return roles;
}
QDate TimelineMonthModel::fromDate() const
{
return m_fromDate;
}
void TimelineMonthModel::setFromDate(QDate date)
{
if (date == m_fromDate) {
return;
}
m_fromDate = date;
emit fromDateChanged(m_fromDate);
updateMonths();
}
QDate TimelineMonthModel::toDate() const
{
return m_toDate;
}
void TimelineMonthModel::setToDate(QDate date)
{
if (date == m_toDate) {
return;
}
m_toDate = date;
emit toDateChanged(m_toDate);
updateMonths();
}
QLocale TimelineMonthModel::locale() const
{
return m_locale;
}
void TimelineMonthModel::setLocale(const QLocale &locale)
{
if (locale == m_locale) {
return;
}
m_locale = locale;
emit localeChanged(m_locale);
if (m_months.isEmpty()) {
return;
}
emit dataChanged(index(0), index(rowCount() - 1), {Qt::DisplayRole});
}
void TimelineMonthModel::updateMonths()
{
QCalendar gregorian;
QCalendar::YearMonthDay fromYMD = gregorian.partsFromDate(std::min(m_fromDate, m_toDate));
QCalendar::YearMonthDay toYMD = gregorian.partsFromDate(std::max(m_fromDate, m_toDate));
if (!fromYMD.isValid() || !toYMD.isValid()) {
if (m_months.isEmpty()) {
return;
}
beginResetModel();
m_months.clear();
endResetModel();
return;
}
beginResetModel();
m_months.clear();
if (fromYMD.year == toYMD.year && fromYMD.month == toYMD.month) {
m_months.push_back({fromYMD.month, toYMD.day - fromYMD.day + 1});
} else {
m_months.push_back(
{fromYMD.month, gregorian.daysInMonth(fromYMD.month, fromYMD.year) - fromYMD.day + 1});
advanceMonth(fromYMD);
for (; fromYMD.month != toYMD.month || fromYMD.year != toYMD.year; advanceMonth(fromYMD)) {
m_months.push_back({fromYMD.month, gregorian.daysInMonth(fromYMD.month, fromYMD.year)});
}
m_months.push_back({toYMD.month, toYMD.day});
}
endResetModel();
}
#include "moc_timelinemonthmodel.cpp"

60
src/timelinemonthmodel.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef TIMELINEMONTHMODEL_H
#define TIMELINEMONTHMODEL_H
#include <QAbstractListModel>
#include <QList>
#include <QLocale>
#include <QtQmlIntegration>
class TimelineMonthModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QDate fromDate READ fromDate WRITE setFromDate NOTIFY fromDateChanged)
Q_PROPERTY(QDate toDate READ toDate WRITE setToDate NOTIFY toDateChanged)
Q_PROPERTY(QLocale locale READ locale WRITE setLocale NOTIFY localeChanged)
public:
enum {
DayCount = Qt::UserRole,
};
explicit TimelineMonthModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
QDate fromDate() const;
void setFromDate(QDate date);
QDate toDate() const;
void setToDate(QDate date);
QLocale locale() const;
void setLocale(const QLocale &locale);
signals:
void fromDateChanged(QDate date);
void toDateChanged(QDate date);
void localeChanged(const QLocale &locale);
private:
Q_DISABLE_COPY_MOVE(TimelineMonthModel)
struct Month
{
int number;
int days;
};
void updateMonths();
QDate m_fromDate;
QDate m_toDate;
QLocale m_locale;
QList<Month> m_months;
};
#endif // TIMELINEMONTHMODEL_H