diff --git a/src/Reservation.qml b/src/Reservation.qml index 603c94b..753817d 100644 --- a/src/Reservation.qml +++ b/src/Reservation.qml @@ -7,6 +7,8 @@ Label { required property Item dragParent required property string holder + required property int nights + required property int reservationId required property string reservationStatus Drag.active: dragHandler.active diff --git a/src/ReservationsTimeline.qml b/src/ReservationsTimeline.qml index 2d8f69a..9f4f927 100644 --- a/src/ReservationsTimeline.qml +++ b/src/ReservationsTimeline.qml @@ -189,13 +189,48 @@ Control { } DropArea { + property int prevDay + property int prevLodging + + function addDays(date, days) { + var newDate = new Date(date); + newDate.setDate(date.getDate() + days); + return newDate; + } + + function findDayAndLodging(drag: DragEvent): list { + const pos = timelineList.contentItem.mapFromItem(this, drag.x, drag.y); + const day = Math.floor(pos.x / control.dayWidth); + const lodging = Math.floor(pos.y / control.rowHeight); + return [day, lodging]; + } + + function isSpotAvailable(day: int, lodging: int, reservation: Reservation): bool { + const view = timelineList.itemAtIndex(lodging); + if (!view) { + return false; + } + + return view.timeline.areDatesAvailable(addDays(control.fromDate, day), addDays(control.fromDate, day + reservation.nights), reservation.reservationId); + } + anchors.fill: timelineList anchors.leftMargin: -30 * control.dayWidth + onEntered: function (drag) { + [prevDay, prevLodging] = findDayAndLodging(drag); + } onPositionChanged: function (drag) { - const pos = timelineList.contentItem.mapFromItem(this, drag.x, drag.y); - drag.source.y = (Math.floor(pos.y / control.rowHeight)) * control.rowHeight; - drag.source.x = (Math.floor(pos.x / control.dayWidth) + .5) * control.dayWidth; + let [day, lodging] = findDayAndLodging(drag); + if ((day != prevDay || lodging != prevLodging) && isSpotAvailable(day, lodging, drag.source)) { + prevDay = day; + prevLodging = lodging; + } else { + day = prevDay; + lodging = prevLodging; + } + drag.source.y = lodging * control.rowHeight; + drag.source.x = (day + .5) * control.dayWidth; } } } diff --git a/src/timelinemodel.cpp b/src/timelinemodel.cpp index 3c395c2..77a49d8 100644 --- a/src/timelinemodel.cpp +++ b/src/timelinemodel.cpp @@ -16,6 +16,31 @@ void TimelineModel::update(const QList &items) m_items.assign(items.begin(), items.end()); } +bool TimelineModel::areDatesAvailable(QDate arrival, QDate departure, int excludedId) const +{ + auto [begin, end] = indexesOf(arrival, departure); + if (begin == end) { + return true; + } + const Item *first = m_items.at(begin); + if (first->id == excludedId) { + begin++; + if (begin == end) { + return true; + } + first = m_items.at(begin); + } + const Item *last = m_items.at(end - 1); + if (last->id == excludedId) { + --end; + if (begin == end) { + return true; + } + last = m_items.at(end - 1); + } + return arrival >= last->departure() || departure <= first->arrival; +} + std::pair TimelineModel::indexesOf(QDate from, QDate to) const { qsizetype begin = searchIndex(from); @@ -31,6 +56,10 @@ std::pair TimelineModel::indexesOf(QDate from, QDate to) c } } + if (begin == 0 && m_items.at(begin)->arrival >= to) { + return std::make_pair(begin, begin); + } + for (qsizetype end = begin + 1; end < m_items.count(); end++) { if (m_items.at(end)->arrival >= to) { return std::make_pair(begin, end); diff --git a/src/timelinemodel.h b/src/timelinemodel.h index b21148b..d66eab3 100644 --- a/src/timelinemodel.h +++ b/src/timelinemodel.h @@ -31,6 +31,7 @@ public: void update(const QList &items); + Q_INVOKABLE bool areDatesAvailable(QDate arrival, QDate departure, int excludeId) const; std::pair indexesOf(QDate from, QDate to) const; const Item *at(qsizetype index) const; diff --git a/src/timelineview.cpp b/src/timelineview.cpp index a0f051a..7913ed7 100644 --- a/src/timelineview.cpp +++ b/src/timelineview.cpp @@ -174,6 +174,8 @@ TimelineView::Item *TimelineView::createItem(qint64 day, const TimelineModel::It if (m_reusableItems.isEmpty()) { QVariantMap initialProperties{ {"holder", modelItem.holder}, + {"nights", modelItem.nights}, + {"reservationId", modelItem.id}, {"reservationStatus", modelItem.status}, }; item = qobject_cast( @@ -186,6 +188,8 @@ TimelineView::Item *TimelineView::createItem(qint64 day, const TimelineModel::It } else { item = m_reusableItems.takeLast(); item->setProperty("holder", modelItem.holder); + item->setProperty("nights", modelItem.nights); + item->setProperty("reservationId", modelItem.id); item->setProperty("reservationStatus", modelItem.status); } auto *viewItem = new TimelineView::Item(day, modelItem.nights, *item, *this);