#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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // unique ptr #include #include // 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 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 &streams, TimelineModel *model, QObject *parent); private slots: void next(); signals: void signalDone(); private: QMap m_streams; TimelineModel *m_model; QMap::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(*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 &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 createItemsFromRows(const Rows &rows); std::vector 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 cnrStreams() { return m_cnrStreams;} QString tvcStream(int id) const { return m_tvcStreams.value(id); } QMap tvcStreams() { return m_tvcStreams;} /** * @brief getEventsByFilter NOTE: ignores filter's active state! * @param filters * @return */ std::vector getEventsByFilter(const QVector &filters) noexcept(false); // // :'( // std::vector getEventsBehindBlockItemBuildings(int tickId, const QVector &filters) noexcept(false); // HitBuilding only (for *Root*-Buildings-Track only!!!) // std::vector getEventsBehindBlockItemBuilding(int tickId, int mountingPointId, const QString &streamName, const QVector &filters) noexcept(false); // HitBuilding only (for specific Building's Track!!!) // std::vector getEventsBehindBlockItemTVC(int tickId, const QVector &filters) noexcept(false); // ROOT // std::vector getEventsBehindBlockItemTVC(int tickId, const QString &streamName, const QVector &filters) noexcept(false); // SPECIFIC // std::vector getEventsBehindBlockItemCNR(int tickId, const QVector &filters) noexcept(false); // ROOT // std::vector getEventsBehindBlockItemCNR(int tickId, const QString &streamName, const QVector &filters) noexcept(false); // SPECIFIC // std::vector getEventsBehindBlockItemBuildingsVideo(int tickId, const QVector &filters) noexcept(false); // the "Video" track // std::vector getEventsBehindBlockItemBuildingVideo(int tickId, int msei, const QVector &filters) noexcept(false); // the Building track // std::vector getEventsBehindBlockItemCameraVideo(int tickId, int mountingPointId, const QString &streamName, const QVector &filters) noexcept(false); // the Stream track // std::vector getEventsBehindBlockItemHitBuildingsRoot(int tickId, const QVector &filters) noexcept(false); // the "Buildings" track // std::vector getEventsBehindBlockItemHitBuilding(int tickId, int msei, const QVector &filters) noexcept(false); // the Building track // std::vector getEventsBehindBlockItemDefaultParty(int tickId, int partyId, const QVector &filters) noexcept(false); // the rest ... ROOT // std::vector getEventsBehindBlockItemDefault(int tickId, int participantId, const QVector &filters) noexcept(false); // the rest ... PARTICIPANT // // // std::vector getEventsBehindBlockItem(int itemId) noexcept(false); qint64 currentEventWidthTime() const { return m_zeroDurationItemWidthTime; } void test_getEventsByFilter(); void clearAlmostAllItems(); QHash &eventFactories() { return m_eventFactories; } AbstractEventFactory *eventFactory(EventType eventType) { return m_eventFactories.value(eventType, nullptr); } QHash &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 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 &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 inferiorIds; Participant() = default; Participant(int participantId, int equipmentNumber, int partyId, const QString &text, int trackId = 0, int superiorId = 0, const QVector &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 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 markerTimes; QHash participantTracks; QMap participants; QMap partys; int hitBuildingsRootTrackId { -1 }; int buildingRootTrackId { -1 }; QMap buildingTrackIds; //QMap, int /* trackId */> buildingStreamsTrackIds; // QMap, int /* trackId */> buildingStreamTracks; // int cnrRootTrackId { -1 }; // QMap cnrTrackIds; // int tvcRootTrackId { -1 }; // QMap tvcTrackIds; }; void updateFilterTable(); void addParticipantTrack(Participant &participant, int superiorTrackId); void getParticipantTracks(); //void getBuildingTracks(); void getRadioTracks(); QVector /* aka. Rows */ executeQuery(const QString &query, bool ignoreError = false) const noexcept(false); QVector /* 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 findItemIdsForDbId(int dbId) noexcept(false); EventItem &itemWithMarkerDbId(int dbId) noexcept(false); // because bad deduction by compiler template /*, typename = typename std::enable_if::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 m_mainStructureElements; QMap m_mountingPointsToMainStructureElementMapping; QVector m_buildingVideoStreams; QMap, int /* trackId */> m_buildingStreamsTracks; // offline videos QMap m_offlineVideoDisplayNames; QMap m_offlineVideoTracks; // Outdoor Cameras int m_outdoorCameraRootTrackId { -1 }; QMap m_outdoorCameraStreams; QMap m_outdoorCameraTracks; int m_videosRootTrackId { -1 }; QMap m_videoTracks; // CNR int m_cnrRootTrackId { -1 }; QMap m_cnrTrackIds; // yea, avs saves the display name to db, not the internal name ... :) QMap m_cnrChannelDisplayNames; //QMap m_cnrChannelDisplayNamesLookup; // TVC int m_tvcRootTrackId { -1 }; QMap m_tvcTrackIds; QMap m_tvcChannelDisplayNames; template static QString keyToString(const QPair &key) { return QStringLiteral("%1/%2").arg(key.first).arg(key.second); } template static QString keyToString(const Key &key) { return QStringLiteral("%1").arg(key); } template 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 m_ppmDtc { nullptr }; std::shared_ptr m_mrkDtc { nullptr }; std::shared_ptr m_ismDtc { nullptr }; std::shared_ptr m_eemForeign { nullptr }; std::shared_ptr m_avmDtc { nullptr }; std::shared_ptr m_avmIfc { nullptr }; QHash m_eventFactories; QHash m_filter; public: QHash m_tempFilter; QMutex m_mutex; private: QMultiMap> m_multiMapClipsForStream; QMap 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 m_cnrStreams; QMap m_tvcStreams; NGL::INGLLogger &m_logger; }; } // namespace Timeline