Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Common/LtsTimeline/timeline_view_drag_handler.cpp
T
torstenandCopilot 7a6be7474e Qt6 migration: Fix BUILD_RTI=OFF build errors in TrainingAreaBase
- training_area_telegrams.cpp: Fixed QJsonObject initializer syntax (Qt6 requires {{}} not ({}))
- training_area_telegrams.cpp: Fixed fromJson() methods to access m_* members directly
- training_area_telegrams.cpp: Fixed brace mismatches in multiple toJson() methods
- training_area_telegrams.h: Changed Header struct to public members for consistency
- tx_mixin.cpp: Fixed getEquipmentNumber() template for direct member access
- lts_coordinate.cpp: Added missing #include <iomanip>
- MIGRATION_STATUS.md: Added migration progress tracking document

C++17 constraint enforced due to RTI Connext DDS 7.7.0 incompatibility with C++20+

Build status: BUILD_RTI=OFF successful (0 errors, warnings only)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-23 20:49:23 +02:00

516 lines
15 KiB
C++

#include "timeline_view_drag_handler.h"
#include "item.h"
#include "track.h"
#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#include <QDrag>
#include <QMimeData>
#include <QtGui/QMouseEvent>
#include <utility>
namespace LtsTimeline
{
TimelineViewDragHandler::TimelineViewDragHandler(TimelineView* view) : m_view(view) {}
TimelineViewDragHandler::~TimelineViewDragHandler()
{
m_view = nullptr;
}
void TimelineViewDragHandler::dragEnterEvent(QDragEnterEvent* e)
{
if (!m_view->timelineModel()->isEditable() || e->source() != m_view || m_dragItemIds.isEmpty() ||
!m_dragStartIndex.isValid())
{
e->ignore();
return;
}
if (e->mimeData()->hasFormat(Item::mimetype))
e->acceptProposedAction();
else
e->ignore();
}
void TimelineViewDragHandler::dragMoveEvent(QDragMoveEvent* e)
{
if (!m_view->timelineModel()->isEditable() || e->source() != m_view || m_dragItemIds.isEmpty() ||
!m_dragStartIndex.isValid())
{
e->ignore();
return;
}
if (!e->mimeData()->hasFormat(Item::mimetype))
return;
m_dragPos = e->pos();
m_view->m_header->setHoverPosition(m_dragPos.x());
e->setAccepted(canDragItemsTo(e->pos()));
m_view->viewport()->update();
}
void TimelineViewDragHandler::dragLeaveEvent(QDragLeaveEvent* e)
{
Q_UNUSED(e);
m_dragPos = {};
}
void TimelineViewDragHandler::dropEvent(QDropEvent* e)
{
if (!m_view->timelineModel()->isEditable() || e->source() != m_view || m_dragItemIds.isEmpty())
{
e->ignore();
return;
}
if (!e->mimeData()->hasFormat(Item::mimetype))
return;
if (!canDragItemsTo(e->pos()))
{
clear();
e->acceptProposedAction();
return;
}
qint64 dt = deltaTime();
try
{
for (const int& itemId : std::as_const(m_dragItemIds))
{
const Item& item = m_view->timelineModel()->item(itemId);
m_view->timelineModel()->moveItemToTrack(itemId, dragItemTrackId(item), item.startTime() + dt);
}
}
catch (const QString& str)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " " << str;
}
catch (...)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed";
}
clear();
e->acceptProposedAction();
}
void TimelineViewDragHandler::mouseMoveEvent(QMouseEvent* e)
{
if (!m_view->timelineModel()->isEditable())
return;
if (e->buttons() != Qt::LeftButton)
{
clear();
return;
}
if (m_dragItemIds.isEmpty() || !m_dragStartIndex.isValid())
return;
if ((e->pos() - m_dragStartPos).manhattanLength() < QApplication::startDragDistance())
return;
const QModelIndex index = m_view->indexAt(e->pos());
if (!index.isValid() || index.column() == Section::eActuator)
{
m_view->setCursor(QCursor(Qt::ForbiddenCursor));
return;
}
m_dragPos = e->pos();
m_view->setCursor(QCursor(canDragItemsTo(m_dragPos) ? Qt::ClosedHandCursor : Qt::ForbiddenCursor));
if (index.data().toInt() == m_dragStartIndex.data().toInt())
return;
QMimeData* mimeData = new QMimeData();
mimeData->setData(Item::mimetype, {});
QDrag* drag = new QDrag(m_view);
drag->setMimeData(mimeData);
if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
{
}
else
{
}
}
void TimelineViewDragHandler::mousePressEvent(QMouseEvent* e)
{
if (!m_view->timelineModel()->isEditable())
return;
if (e->button() != Qt::LeftButton)
return;
const QModelIndex index = m_view->indexAt(e->pos());
if (!index.isValid() || index.column() == Section::eActuator)
return;
try
{
Track& track = m_view->timelineModel()->track(index.data().toInt());
Item& item = track.itemAt(m_view->toTime(e->pos().x()));
m_dragItemIds = m_view->m_selectedItemIds;
if (!m_dragItemIds.contains(item.id()))
m_dragItemIds = {item.id()};
for (const int& itemId : m_dragItemIds)
if (!m_view->timelineModel()->item(itemId).isEditable())
return;
m_dragStartIndex = index;
m_dragStartTime = m_view->toTime(e->pos().x());
m_dragStartPos = e->pos();
m_dragPos = m_dragStartPos;
m_view->setCursor(QCursor(Qt::ClosedHandCursor));
}
catch (const QString& str)
{
DEBUG_LOG(m_view->m_logger) << LOGFUNCTION << " " << str;
}
catch (...)
{
}
}
void TimelineViewDragHandler::mouseReleaseEvent(QMouseEvent* e)
{
if (!m_view->timelineModel()->isEditable())
return;
if (e->button() != Qt::LeftButton)
return;
if (m_dragItemIds.isEmpty() || !m_dragStartIndex.isValid())
return;
const QModelIndex index = m_view->indexAt(e->pos());
if (!index.isValid() || index.column() == Section::eActuator)
return;
if (index.data().toInt() != m_dragStartIndex.data().toInt())
return;
m_dragPos = e->pos();
if (m_dragPos.x() == m_dragStartPos.x())
{
clear();
return;
}
if (!canMoveItemsTo(m_dragPos))
{
clear();
return;
}
emit m_view->currentItemTimeChanged();
qint64 dt = deltaTime();
for (const int& itemId : m_dragItemIds)
{
Item& item = m_view->timelineModel()->item(itemId);
m_view->timelineModel()->setItemStartTime(item, item.startTime() + dt);
}
clear();
}
void TimelineViewDragHandler::keyPressEvent(QKeyEvent* e)
{
if (!m_view->timelineModel()->isEditable())
return;
if (m_view->m_selectedItemIds.isEmpty())
return;
if (e->key() == Qt::Key_Escape)
{
clear();
return;
}
if (e->key() != Qt::Key_Left && e->key() != Qt::Key_Right)
return;
int dt = m_view->timelineModel()->snapStep();
if (e->key() == Qt::Key_Left)
moveItemsLeft(m_view->selectedItemIds(),
QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) ? -dt : -10 * dt);
else
moveItemsRight(m_view->selectedItemIds(),
QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) ? dt : 10 * dt);
}
bool TimelineViewDragHandler::isActive() const
{
return !m_dragItemIds.isEmpty() &&
(m_dragPos - m_dragStartPos).manhattanLength() >= QApplication::startDragDistance();
}
int TimelineViewDragHandler::deltaX() const
{
if (!m_view->timelineModel()->isSnapEnabled())
return m_dragPos.x() - m_dragStartPos.x();
return m_view->toPixel(m_dragStartTime + deltaTime()) - m_view->toPixel(m_dragStartTime);
}
int TimelineViewDragHandler::deltaY() const
{
const QModelIndex dragIndex = m_view->indexAt(m_dragPos);
if (!dragIndex.isValid())
return m_dragPos.y() - m_dragStartPos.y();
return m_view->visualRect(dragIndex).top() - m_view->visualRect(m_dragStartIndex).top();
}
qint64 TimelineViewDragHandler::deltaTime() const
{
if (!m_view->timelineModel()->isSnapEnabled())
return m_view->toTime(m_dragPos.x()) - m_view->toTime(m_dragStartPos.x());
qint64 dt = ((m_view->toTime(m_dragPos.x()) - m_dragStartTime) / m_view->timelineModel()->snapStep()) *
m_view->timelineModel()->snapStep();
int dtAbsMin = 2 * m_view->timelineModel()->snapTolerance();
int eps = m_view->timelineModel()->snapTolerance();
for (const int& dragItemId : m_dragItemIds)
{
const Item& dragItem = m_view->timelineModel()->item(dragItemId);
qint64 start = dragItem.startTime() + dt;
qint64 end = start + dragItem.duration();
for (int itemId : m_view->timelineModel()->itemIds())
{
if (m_dragItemIds.contains(itemId))
continue;
const Item& item = m_view->timelineModel()->item(itemId);
if (start - eps < item.startTime() + item.duration() && item.startTime() + item.duration() < start + eps)
{
qint64 dtCurrent = item.startTime() + item.duration() - dragItem.startTime();
qint64 dtAbsCurrent = std::abs(dtCurrent);
if (dtAbsCurrent < dtAbsMin)
{
dtAbsMin = dtAbsCurrent;
dt = dtCurrent;
}
}
else if (end - eps < item.startTime() && item.startTime() < end + eps)
{
qint64 dtCurrent = item.startTime() - (dragItem.startTime() + dragItem.duration());
qint64 dtAbsCurrent = std::abs(dtCurrent);
if (dtAbsCurrent < dtAbsMin)
{
dtAbsMin = dtAbsCurrent;
dt = dtCurrent;
}
}
}
}
return dt;
}
bool TimelineViewDragHandler::canDragItemsTo(const QPoint& point) const
{
if (!m_view->timelineModel()->isEditable())
return false;
if (m_dragItemIds.isEmpty() || !m_dragStartIndex.isValid())
return false;
const QModelIndex index = m_view->indexAt(point);
if (!index.isValid() || index.column() == Section::eActuator)
return false;
if (index.data().toInt() == m_dragStartIndex.data().toInt())
return canMoveItemsTo(point);
else
{
try
{
qint64 dt = deltaTime();
for (const int& itemId : m_dragItemIds)
{
const Item& item = m_view->timelineModel()->item(itemId);
int trackId = dragItemTrackId(item);
if (trackId == 0)
return false;
const Track& track = m_view->timelineModel()->track(trackId);
qint64 startNew = item.startTime() + dt;
if (!m_view->timelineModel()->canDropItem(item, track.id(), startNew))
return false;
if (track.isItemsBetween(startNew, startNew + item.duration(), m_dragItemIds, true))
return false;
}
}
catch (...)
{
return true;
}
}
return true;
}
bool TimelineViewDragHandler::canMoveItemsTo(const QPoint& point) const
{
if (!m_view->timelineModel()->isEditable())
return false;
if (m_dragItemIds.isEmpty() || !m_dragStartIndex.isValid())
return false;
const QModelIndex index = m_view->indexAt(point);
if (!index.isValid() || index.column() == Section::eActuator ||
index.data().toInt() != m_dragStartIndex.data().toInt())
return false;
qint64 dt = deltaTime();
for (const int& itemId : m_dragItemIds)
{
const Item& item = m_view->timelineModel()->item(itemId);
qint64 startNew = item.startTime() + dt;
if (!m_view->timelineModel()->canMoveItem(item, startNew))
return false;
const Track& track = m_view->timelineModel()->track(item.parentTrackId());
if (track.isItemsBetween(startNew, startNew + item.duration(), m_dragItemIds, true))
return false;
}
return true;
}
void TimelineViewDragHandler::moveItemsLeft(const QVector<int>& itemIds, int dt)
{
Q_ASSERT(dt < 0);
try
{
for (int itemId : itemIds)
{
const Item& item = m_view->timelineModel()->item(itemId);
const Track& track = m_view->timelineModel()->track(item.parentTrackId());
if (track.isItemsBetween(item.startTime() + dt, item.startTime() + item.duration() + dt, itemIds, true))
{
if (dt < -m_view->timelineModel()->snapStep())
moveItemsLeft(itemIds, dt + m_view->timelineModel()->snapStep());
return;
}
if (!m_view->timelineModel()->canMoveItem(item, item.startTime() + dt))
{
if (dt < -m_view->timelineModel()->snapStep())
moveItemsLeft(itemIds, dt + m_view->timelineModel()->snapStep());
return;
}
}
}
catch (const QString& errMsg)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed: " << errMsg;
return;
}
catch (...)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed";
return;
}
try
{
for (int itemId : itemIds)
{
Item& item = m_view->timelineModel()->item(itemId);
m_view->timelineModel()->setItemStartTime(item, item.startTime() + dt);
}
}
catch (const QString& str)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " " << str;
}
catch (...)
{
}
}
void TimelineViewDragHandler::moveItemsRight(const QVector<int>& itemIds, int dt)
{
Q_ASSERT(dt > 0);
try
{
for (int itemId : itemIds)
{
const Item& item = m_view->timelineModel()->item(itemId);
const Track& track = m_view->timelineModel()->track(item.parentTrackId());
if (track.isItemsBetween(item.startTime() + dt, item.startTime() + item.duration() + dt, itemIds, true))
{
if (dt > m_view->timelineModel()->snapStep())
moveItemsRight(itemIds, dt - m_view->timelineModel()->snapStep());
return;
}
if (!m_view->timelineModel()->canMoveItem(item, item.startTime() + dt))
{
if (dt > m_view->timelineModel()->snapStep())
moveItemsRight(itemIds, dt - m_view->timelineModel()->snapStep());
return;
}
}
}
catch (const QString& errMsg)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed: " << errMsg;
return;
}
catch (...)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed";
return;
}
try
{
for (int itemId : itemIds)
{
Item& item = m_view->timelineModel()->item(itemId);
m_view->timelineModel()->setItemStartTime(item, item.startTime() + dt);
}
}
catch (const QString& errMsg)
{
ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " " << errMsg;
}
catch (...)
{
}
}
int TimelineViewDragHandler::dragItemTrackId(const Item& item) const
{
int dy = deltaY();
const QModelIndex index = m_view->indexAt(m_dragStartPos + QPoint(0, dy));
if (index.data().toInt() == m_dragStartIndex.data().toInt())
return item.parentTrackId();
try
{
const QModelIndex originalIndex = m_view->timelineModel()->indexOfTrack(item.parentTrackId());
const QModelIndex newIndex = m_view->indexAt(m_view->visualRect(originalIndex).center() + QPoint(0, dy));
return newIndex.data().toInt();
}
catch (...)
{
return 0;
}
}
void TimelineViewDragHandler::clear()
{
m_dragStartIndex = {};
m_dragStartTime = -1;
m_dragStartPos = {};
m_dragPos = {};
m_dragItemIds.clear();
m_view->setCursor(QCursor(Qt::ArrowCursor));
m_view->viewport()->update();
}
} // namespace LtsTimeline