452 lines
17 KiB
C++
Executable File
452 lines
17 KiB
C++
Executable File
#pragma once
|
|
|
|
#include "tln_abstract_event_factory.h"
|
|
#include "tln_participant_track.h"
|
|
#include "tln_party_track.h"
|
|
#include "tln_timeline_delegate.h"
|
|
#include "EventTypes/Block/tln_block_item.h"
|
|
|
|
#include <LtsTimeline/item.h>
|
|
#include <LtsTimeline/timeline_model.h>
|
|
#include <LtsTimeline/timeline_utils.h>
|
|
#include <LtsTimeline/timeline_view.h>
|
|
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
|
#include <ParticipantManagement/ppm.hpp>
|
|
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
|
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
|
|
#include <AudioVideoManagement/Shared/stream_list_result.h>
|
|
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonParseError>
|
|
#include <QMutex>
|
|
#include <QPainter>
|
|
#include <QSqlDatabase>
|
|
#include <QStyleOptionViewItem>
|
|
#include <QUuid>
|
|
|
|
#include <memory> // unique ptr
|
|
#include <functional>
|
|
#include <type_traits> // std::enable_if => type
|
|
|
|
|
|
namespace LtsSession { class LtsSession; }
|
|
namespace ParticipantManagement { namespace Interface { class Dtc; } }
|
|
namespace MarkerManagement
|
|
{
|
|
namespace Interface { class Dtc; }
|
|
class Marker;
|
|
}
|
|
namespace InfrastructureManagement { namespace Interface { class Dtc; } }
|
|
namespace LtsTimeline { class TimelineView; }
|
|
namespace TimeLineManagement { class ForeignDataInterface; }
|
|
namespace ExerciseEventManagement { class Event; }
|
|
|
|
using Ticks = LtsTimeline::Ticks;
|
|
using namespace LtsTimeline;
|
|
|
|
typedef QVector<QVariantMap> Rows;
|
|
typedef QVariantMap Row;
|
|
|
|
|
|
namespace Timeline
|
|
{
|
|
class TimelineDialog;
|
|
class TimelineModelUpdate;
|
|
class TimelineProxyModel;
|
|
class BuildingHitsTrack;
|
|
class TimelineModel;
|
|
|
|
|
|
/*
|
|
class GetOfflineVideosProcess : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
GetOfflineVideosProcess(const QMap<QString, QString> &streams, TimelineModel *model, QObject *parent);
|
|
|
|
private slots:
|
|
void next();
|
|
|
|
signals:
|
|
void signalDone();
|
|
|
|
private:
|
|
QMap<QString, QString> m_streams;
|
|
TimelineModel *m_model;
|
|
QMap<QString, QString>::const_iterator m_streamsIt;
|
|
int m_open { 0 };
|
|
};
|
|
*/
|
|
class TimelineTableInfos
|
|
{
|
|
public:
|
|
static TimelineTableInfos *getInstance();
|
|
|
|
void insertTable(const QString &tableName)
|
|
{
|
|
m_tableNames += tableName;
|
|
}
|
|
|
|
void removeTable(const QString &tableName)
|
|
{
|
|
m_tableNames.removeAll(tableName);
|
|
}
|
|
|
|
const QStringList &tableNames() const { return m_tableNames; }
|
|
|
|
private:
|
|
friend struct TimelineTableInfosHandler;
|
|
|
|
QStringList m_tableNames;
|
|
};
|
|
|
|
class TimelineModel : public LtsTimeline::TimelineModel
|
|
{
|
|
Q_OBJECT
|
|
|
|
friend class TimelineModelUpdate;
|
|
friend class TimelineSelectHandler;
|
|
// friend class GetOfflineVideosProcess;
|
|
|
|
public:
|
|
static QString s_eemEventColumns;
|
|
static const int s_maxRows{1000};
|
|
|
|
static int getInt(const Row &row, const QString &column) noexcept(false);
|
|
static qint64 getLongLong(const Row &row, const QString &column) noexcept(false);
|
|
static QJsonObject getJsonObject(const Row &row, const QString &column, bool ignoreError = false) noexcept(false);
|
|
static double getJsonDouble(const Row &row, const QString &column) noexcept(false);
|
|
|
|
static const EventItem &getEventItem(const ItemPtrNCVRef &itemPtr) { return static_cast<const EventItem &>(*itemPtr.get()); }
|
|
static const EventItem &getEventItem(const EventItemPtr &eventItemPtr) { return *eventItemPtr; }
|
|
|
|
explicit TimelineModel(LtsSession::LtsSession *session, TimelineDialog *dialog, qint64 exerciseStart, qint64 exerciseEnd, QObject *parent = nullptr) noexcept(false);
|
|
~TimelineModel();
|
|
|
|
void initEventFactories(qint64 exerciseStart, qint64 exerciseEnd);
|
|
void clearUnusedTempTables();
|
|
|
|
bool canDropItem(const LtsTimeline::Item &item, int trackId, qint64 start) const override;
|
|
bool canMoveItem(const LtsTimeline::Item &item, qint64 start) const override;
|
|
bool canResizeItem(const LtsTimeline::Item &item, qint64 start, int duration) const override;
|
|
|
|
TrackType trackType(const LtsTimeline::Track &t) const;
|
|
TrackType trackType(int trackId) const;
|
|
|
|
bool isBlockItem(int itemId) const;
|
|
bool hasBlockItems(const QVector<int> &itemIds) const;
|
|
|
|
EventItemPtr createItem(int id, qint64 sampleTime, QJsonObject properties /* TODO: copy elision? */,
|
|
int eventTypeId, int participantId, int partyId, int eqId, double posX, double posY, double posZ) noexcept(false);
|
|
EventItemPtr createItemFromRow(const Row &row);
|
|
std::vector<EventItemPtr> createItemsFromRows(const Rows &rows);
|
|
std::vector<EventItemPtr> getMarkerItems(const Filters &filters, bool rangeOnly = false, int limit = s_maxRows) noexcept(false);
|
|
int findTrack(const AbstractEventItem &_eventItem);
|
|
int handleCopyCollision(const Track &t, const int copyItemId, const int itemId, const qint64 start, const qint64 duration) noexcept(false);
|
|
int handleCollision(Track &t, ItemPtr &&itemPtr, const int itemId, const qint64 start, const qint64 duration) noexcept(false);
|
|
void insertCopyItem(Track &t, const int copyItemId) noexcept(false);
|
|
void insertItem(Track &t, ItemPtr &&itemPtr) noexcept(false);
|
|
void insertItem(ItemPtr &&itemPtr);
|
|
void insertItems(EventItemPtrs &eventItemPtrs);
|
|
QString cnrStream(int id) const { return m_cnrStreams.value(id); }
|
|
QMap<int, QString> cnrStreams() { return m_cnrStreams;}
|
|
QString tvcStream(int id) const { return m_tvcStreams.value(id); }
|
|
QMap<int, QString> tvcStreams() { return m_tvcStreams;}
|
|
|
|
|
|
/**
|
|
* @brief getEventsByFilter NOTE: ignores filter's active state!
|
|
* @param filters
|
|
* @return
|
|
*/
|
|
std::vector<EventItemPtr> getEventsByFilter(const QVector<AbstractEventFilter *> &filters) noexcept(false);
|
|
|
|
// // :'(
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemBuildings(int tickId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // HitBuilding only (for *Root*-Buildings-Track only!!!)
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemBuilding(int tickId, int mountingPointId, const QString &streamName, const QVector<AbstractEventFilter *> &filters) noexcept(false); // HitBuilding only (for specific Building's Track!!!)
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemTVC(int tickId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // ROOT
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemTVC(int tickId, const QString &streamName, const QVector<AbstractEventFilter *> &filters) noexcept(false); // SPECIFIC
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemCNR(int tickId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // ROOT
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemCNR(int tickId, const QString &streamName, const QVector<AbstractEventFilter *> &filters) noexcept(false); // SPECIFIC
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemBuildingsVideo(int tickId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the "Video" track
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemBuildingVideo(int tickId, int msei, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the Building track
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemCameraVideo(int tickId, int mountingPointId, const QString &streamName, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the Stream track
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemHitBuildingsRoot(int tickId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the "Buildings" track
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemHitBuilding(int tickId, int msei, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the Building track
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemDefaultParty(int tickId, int partyId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the rest ... ROOT
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItemDefault(int tickId, int participantId, const QVector<AbstractEventFilter *> &filters) noexcept(false); // the rest ... PARTICIPANT
|
|
// // </ :'( >
|
|
|
|
// std::vector<EventItemPtr> getEventsBehindBlockItem(int itemId) noexcept(false);
|
|
|
|
qint64 currentEventWidthTime() const { return m_zeroDurationItemWidthTime; }
|
|
|
|
void test_getEventsByFilter();
|
|
|
|
void clearAlmostAllItems();
|
|
|
|
QHash<EventType, AbstractEventFactory *> &eventFactories() { return m_eventFactories; }
|
|
AbstractEventFactory *eventFactory(EventType eventType) { return m_eventFactories.value(eventType, nullptr); }
|
|
|
|
QHash<EventType, AbstractEventFilter *> &filters() { return m_filter; }
|
|
AbstractEventFilter *filter(EventType eventType) { return m_filter.value(eventType, nullptr); }
|
|
AbstractEventFilter *tempFilter(EventType eventType) { return m_tempFilter.value(eventType, nullptr); }
|
|
|
|
void update(bool fake = false);
|
|
const QVector<qint64> markerLines() const { return m_modelState.markerTimes; }
|
|
bool knownRange(qint64 &startOut, qint64 &endOut) const;
|
|
bool isCurrentlyUpdating() const { return m_isCurrentlyUpdating; }
|
|
void queueUpdate();
|
|
void setLive(bool live) { m_isLive = live; if (!live) m_forceRebuildFilter = true; }
|
|
bool isLive() const { return m_isLive; }
|
|
|
|
public slots:
|
|
void onRangeChanged(qint64 start, qint64 end);
|
|
void onCurrentTimeChanged(qint64 time);
|
|
void onZoomChanged(LtsTimeline::ZoomFactor zoom);
|
|
void onUpdate() { update(); }
|
|
void onFilterChanged();
|
|
|
|
signals:
|
|
void updateStatusChanged(bool running);
|
|
void errorCountExceeded();
|
|
void thingy(int i, bool result);
|
|
void initializationFinished(); // NOTE: emit queued, you will have enough time to connect to this signal
|
|
|
|
//#warning // TODO: private
|
|
/*private*/ public slots:
|
|
void onMarkerChanged(const MarkerManagement::Marker &marker, DataModification mod);
|
|
void onLiveEvent(const ExerciseEventManagement::Event &eemEvent);
|
|
private slots:
|
|
void onStreamListReceived(const QMap<QString, QString> &streamList);
|
|
private:
|
|
struct Party
|
|
{
|
|
int id;
|
|
int trackId;
|
|
Party(int id, int trackId) : id(id), trackId(trackId) {}
|
|
};
|
|
|
|
struct Participant
|
|
{
|
|
int participantId { 0 };
|
|
int trackId { 0 };
|
|
int superiorId { 0 };
|
|
int equipmentNumber { 0 };
|
|
int partyId { 0 };
|
|
QString text;
|
|
QVector<int> inferiorIds;
|
|
Participant() = default;
|
|
Participant(int participantId, int equipmentNumber, int partyId, const QString &text, int trackId = 0, int superiorId = 0, const QVector<int> &inferiorIds = {})
|
|
: participantId(participantId)
|
|
, trackId(trackId)
|
|
, superiorId(superiorId)
|
|
, equipmentNumber(equipmentNumber)
|
|
, partyId(partyId)
|
|
, text(text)
|
|
, inferiorIds(inferiorIds)
|
|
{}
|
|
};
|
|
|
|
struct Range
|
|
{
|
|
qint64 start { 0 };
|
|
qint64 end { 0 };
|
|
};
|
|
|
|
struct ModelState
|
|
{
|
|
QString publicTableName;
|
|
|
|
//#warning // TODO: ! publish to singleton thingy
|
|
QString dbUuid = QUuid::createUuid().toString(QUuid::Id128);
|
|
|
|
// the event view is a temporary database table holding filtered EEM-Event data
|
|
qint64 tempRangeStart { 0 };
|
|
qint64 tempRangeEnd { 0 };
|
|
|
|
// start and end correspond to what time interval can currently be seen on the timeline
|
|
qint64 start { 0 };
|
|
qint64 end { 0 };
|
|
|
|
// knownStart and knownEnd is the time interval for which data is inside the model
|
|
//QVector<Range> knownRanges;
|
|
qint64 knownStart { 0 };
|
|
qint64 knownEnd { 0 };
|
|
|
|
int markerTrackId { -1 }; // TODO: move me and others into a "ModelState" class, so I can be reset with only a recreation of the class !!
|
|
QVector<qint64> markerTimes;
|
|
QHash<int/*participantId*/, int/*trackId*/> participantTracks;
|
|
QMap<int/*participantId*/, Participant> participants;
|
|
QMap<int/*partyId*/, Party> partys;
|
|
int hitBuildingsRootTrackId { -1 };
|
|
|
|
|
|
|
|
|
|
int buildingRootTrackId { -1 };
|
|
QMap<int /* buildingId (MSEI) */, int /* trackId */> buildingTrackIds;
|
|
//QMap<QPair<int /* buildingId (MSEI) */, QString /* internal stream name */>, int /* trackId */> buildingStreamsTrackIds;
|
|
|
|
|
|
|
|
|
|
// QMap<QPair<int /* buildingId */, QString /* internalStreamName */>, int /* trackId */> buildingStreamTracks;
|
|
// int cnrRootTrackId { -1 };
|
|
// QMap<QString /* internalStreamName */, int /* trackId */> cnrTrackIds;
|
|
// int tvcRootTrackId { -1 };
|
|
// QMap<QString /* internalStreamName */, int /* trackId */> tvcTrackIds;
|
|
};
|
|
|
|
void updateFilterTable();
|
|
void addParticipantTrack(Participant &participant, int superiorTrackId);
|
|
void getParticipantTracks();
|
|
//void getBuildingTracks();
|
|
void getRadioTracks();
|
|
|
|
QVector<QVariantMap> /* aka. Rows */ executeQuery(const QString &query, bool ignoreError = false) const noexcept(false);
|
|
QVector<QVariantMap> /* aka. Rows */ executeQuery(const QString &query, const QSqlDatabase &db, bool ignoreError = false) const noexcept(false);
|
|
|
|
bool isCollision(qint64 startTime, qint64 previousStartTime, qint64 previousDuration);
|
|
void tryUpdate();
|
|
|
|
QJsonObject eventPropertiesFromMarker(const MarkerManagement::Marker &marker);
|
|
|
|
void reChannelSumEvents(int trackId, int onlyThisTick) noexcept(false);
|
|
void backwardsChannelSumEvents(const Track &t);
|
|
void channelSumEvents();
|
|
void sumEvents(Track &track);
|
|
|
|
//int megaParent(int trackId) noexcept(false);
|
|
//QModelIndex megaParentModelIndex(int trackId) noexcept(false);
|
|
QVector<int> findItemIdsForDbId(int dbId) noexcept(false);
|
|
EventItem &itemWithMarkerDbId(int dbId) noexcept(false);
|
|
|
|
// because bad deduction by compiler
|
|
template <typename ItemClass>/*, typename = typename std::enable_if<std::is_base_of<LtsTimelineItem, ItemClass>::value, ItemClass>::type>*/
|
|
int addItem(int parentTrackId, ItemClass &&item) noexcept(false)
|
|
{
|
|
return LtsTimeline::TimelineModel::addItem(parentTrackId, std::move(item));
|
|
}
|
|
|
|
void getMarkers() noexcept(false);
|
|
void getOfflineVideoTracks() ; //Same than the other but give back list of added streams
|
|
// void getOfflineVideos() noexcept(false);
|
|
// void addOfflineVideosToTimeline();
|
|
BuildingHitsTrack createBuildingHitsTrack();
|
|
void getBuildings();
|
|
void getBuildingVideoStreams();
|
|
|
|
QVector<int /* msei */> m_mainStructureElements;
|
|
QMap<int /* mpi */, int /* msei */> m_mountingPointsToMainStructureElementMapping;
|
|
QVector<int /* mpi */> m_buildingVideoStreams;
|
|
QMap<QPair<int /* buildingId (MSEI) */, QString /* internal stream name */>, int /* trackId */> m_buildingStreamsTracks;
|
|
// offline videos
|
|
QMap<QString, QString> m_offlineVideoDisplayNames;
|
|
QMap<QString /* internal stream name */, int> m_offlineVideoTracks;
|
|
// Outdoor Cameras
|
|
int m_outdoorCameraRootTrackId { -1 };
|
|
QMap<int/*mounting point id*/, QString/*human name*/> m_outdoorCameraStreams;
|
|
QMap<QString/*internal stream name*/, int/*track id*/> m_outdoorCameraTracks;
|
|
|
|
int m_videosRootTrackId { -1 };
|
|
QMap<QString /* stream name */, int /* track id */> m_videoTracks;
|
|
|
|
// CNR
|
|
int m_cnrRootTrackId { -1 };
|
|
QMap<QString /* __display__ stream name */, int /* trackId */> m_cnrTrackIds; // yea, avs saves the display name to db, not the internal name ... :)
|
|
QMap<int /* channel id */, QString /* display name */> m_cnrChannelDisplayNames;
|
|
//QMap<QString /* display name */, int /* channel id */> m_cnrChannelDisplayNamesLookup;
|
|
|
|
// TVC
|
|
int m_tvcRootTrackId { -1 };
|
|
QMap<QString /* internalStreamName */, int /* trackId */> m_tvcTrackIds;
|
|
QMap<int /* channel id */, QString /* display name */> m_tvcChannelDisplayNames;
|
|
|
|
|
|
template <typename First, typename Second>
|
|
static QString keyToString(const QPair<First, Second> &key)
|
|
{
|
|
return QStringLiteral("%1/%2").arg(key.first).arg(key.second);
|
|
}
|
|
|
|
template <typename Key>
|
|
static QString keyToString(const Key &key)
|
|
{
|
|
return QStringLiteral("%1").arg(key);
|
|
}
|
|
|
|
template <typename ReturnType, typename Container, typename Key>
|
|
static ReturnType constFinder(const Container &container, const Key &key) noexcept(false)
|
|
{
|
|
auto it = container.constFind(key);
|
|
|
|
if (it == container.constEnd())
|
|
throw QStringLiteral("constFinder: cannot find '%1' in container").arg(keyToString(key));
|
|
|
|
return it.value();
|
|
}
|
|
|
|
|
|
|
|
|
|
LtsSession::LtsSession *m_session { nullptr };
|
|
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc { nullptr };
|
|
std::shared_ptr<MarkerManagement::Interface::Dtc> m_mrkDtc { nullptr };
|
|
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc { nullptr };
|
|
std::shared_ptr<TimeLineManagement::ForeignDataInterface> m_eemForeign { nullptr };
|
|
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_avmDtc { nullptr };
|
|
std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> m_avmIfc { nullptr };
|
|
|
|
QHash<EventType, AbstractEventFactory *> m_eventFactories;
|
|
QHash<EventType, AbstractEventFilter *> m_filter;
|
|
public:
|
|
QHash<EventType, AbstractEventFilter *> m_tempFilter;
|
|
QMutex m_mutex;
|
|
private:
|
|
QMultiMap<QString, QPair<qint64, qint64>> m_multiMapClipsForStream;
|
|
QMap<QString, qint64> m_lastStartTimePerStream;
|
|
QString m_filterString;
|
|
|
|
QSqlDatabase m_db;
|
|
|
|
ModelState m_modelState;
|
|
QTimer *m_updateTimer { nullptr };
|
|
QTimer *m_offlineVideoTimer { nullptr };
|
|
bool m_updateMutex { false };
|
|
bool m_updateResult { true };
|
|
bool m_updateQueued { false };
|
|
bool m_queueItemDeletion { false }; // if e.g. zoom is changed, all events have to be refetched, but events should only be deleted if the update is actually executing, as queued updates are not guaranteed to be executed
|
|
|
|
int m_fakeId { 0 };
|
|
qint64 m_zeroDurationItemWidthTime { 0 };
|
|
static int s_minThreadCount;
|
|
static int s_maxThreadCount;
|
|
|
|
bool m_isCurrentlyUpdating { false };
|
|
int m_threads { 1 };
|
|
|
|
|
|
|
|
bool m_firstUpdate { true };
|
|
int *m_lockyMcLockLock { nullptr };
|
|
Rows **m_sharedThing { nullptr };
|
|
|
|
bool m_forceRebuildFilter { false };
|
|
TimelineDialog *m_dialog;
|
|
bool m_isLive { false };
|
|
bool m_trackFetchedInLiveDone { false };
|
|
QMap<int, QString> m_cnrStreams;
|
|
QMap<int, QString> m_tvcStreams;
|
|
NGL::INGLLogger &m_logger;
|
|
|
|
};
|
|
|
|
} // namespace Timeline
|