#include "TimelineWidget.h" #include "TimelineIndicator.h" #include "EventTools.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef LTS_DEBUG #endif #ifdef VERBOSE #define dbg_print(x) qWarning() << #x << x #else #define dbg_print(x) (void)x; #endif namespace LtsTimelineClassic { TimelineIndicator::TimelineIndicator(QWidget *parent) : QWidget(parent) , m_zoomFactorPoints(0) , m_pbZoom(new QPushButton(this)) , m_pbUnzoom(new QPushButton(this)) , m_cbZoomLevel(new QComboBox(this)) , m_currentTextHeight(0) , m_currentTextWidth(0) , m_sectionPos(0) , m_sectionSize(0) , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Timeline.Indicator")) { m_timeArray.reserve(11 + 11 + 7 + 10); m_timeArray << 1 << 2 << 3 << 4 << 5 << 6 << 12 << 15 << 20 << 30 << 60 << 1 * 60 << 2 * 60 << 3 * 60 << 4 * 60 << 5 * 60 << 6 * 60 << 12 * 60 << 15 * 60 << 20 * 60 << 30 * 60 << 60 * 60 << 1 * 60 * 60 << 2 * 60 * 60 << 4 * 60 * 60 << 6 * 60 * 60 << 8 * 60 * 60 << 12 * 60 * 60 << 24 * 60 * 60 << 1 * 60 * 60 << 2 * 60 * 60 << 4 * 60 * 60 << 6 * 60 * 60 << 8 * 60 * 60 << 10 * 60 * 60 << 14 * 60 * 60 << 18 * 60 * 60 << 22 * 60 * 60 << 26 * 60 * 60 << 30 * 60 * 60; QHBoxLayout *centralLayout = new QHBoxLayout(); centralLayout->setSpacing(0); setLayout(centralLayout); m_pbZoom->setText(QLatin1String("+")); m_pbZoom->setFixedSize(s_pbSize, s_pbSize); m_pbUnzoom->setText(QLatin1String("-")); m_pbUnzoom->setFixedSize(s_pbSize, s_pbSize); m_cbZoomLevel->addItem(tr("10 min"), 600); m_cbZoomLevel->addItem(tr("30 min"), 1800); m_cbZoomLevel->addItem(tr("1 h"), 3600); m_cbZoomLevel->addItem(tr("2 h"), 7200); m_cbZoomLevel->addItem(tr("4 h"), 14400); m_cbZoomLevel->addItem(tr("8 h"), 28800); m_cbZoomLevel->setCurrentIndex(0); m_cbZoomLevel->setFixedHeight(s_pbSize); m_zoomFactorPoints = m_cbZoomLevel->currentData().toLongLong(); connect(m_cbZoomLevel, &QComboBox::currentTextChanged, this, &TimelineIndicator::afterZoom); connect(m_pbZoom, &QPushButton::clicked, this, &TimelineIndicator::slotZoom); connect(m_pbUnzoom, &QPushButton::clicked, this, &TimelineIndicator::slotUnzoom); connect(this, &TimelineIndicator::signalAddLine, this, &TimelineIndicator::slotAddLine); connect(this, &TimelineIndicator::signalResetLineList, this, &TimelineIndicator::slotResetLineList); centralLayout->addWidget(m_pbZoom, 0, Qt::AlignLeft | Qt::AlignTop); centralLayout->addWidget(m_pbUnzoom, 0, Qt::AlignLeft | Qt::AlignTop); centralLayout->addWidget(m_cbZoomLevel, 1, Qt::AlignLeft | Qt::AlignTop); QFontMetrics fm(QApplication::font()); m_currentTextHeight = fm.height(); #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) m_currentTextWidth = fm.width(DTG::toString(QDateTime::currentDateTimeUtc(), DTG::Short)); #else m_currentTextWidth = fm.horizontalAdvance(DTG::toString(QDateTime::currentDateTimeUtc(), DTG::Short)); #endif dbg_print(m_currentTextWidth); } TimelineIndicator::~TimelineIndicator() { } void TimelineIndicator::afterZoom() { m_zoomFactorPoints = m_cbZoomLevel->currentData().toLongLong() * 1000; emit signalSetZoomFactor(m_zoomFactorPoints); update(); } void TimelineIndicator::slotZoom() { int pos = m_cbZoomLevel->currentIndex(); if (pos == 0) return; m_cbZoomLevel->setCurrentIndex(pos - 1); emit signalZoomChanged(); } void TimelineIndicator::slotUnzoom() { int count = m_cbZoomLevel->count(); int pos = m_cbZoomLevel->currentIndex(); if (pos >= count - 1) return; m_cbZoomLevel->setCurrentIndex(pos + 1); emit signalZoomChanged(); } enum highestUnit { HU_INVALID, HU_DAYS, HU_HOURS, HU_MINUTES, HU_SECONDS }; void TimelineIndicator::refreshData() { #ifdef VERBOSE qWarning() << ""; #endif emit signalResetLineList(); #ifdef VERBOSE qWarning() << "section x" << m_sectionPos << "length" << m_sectionSize; #endif double abstand = m_sectionPos + m_currentTextWidth + s_TimeTextDistanceTolerancePixels; dbg_print(abstand); qint64 eventTimeOfAbstand = EventTools::getEventTime(abstand); dbg_print(eventTimeOfAbstand); qint64 adjustedMin = EventTools::getAdjustedMin(); dbg_print(adjustedMin); qint64 textWidthTime = (eventTimeOfAbstand - adjustedMin); if (textWidthTime < 0) { qWarning() << "TimelineIndicator: paintEvent: textWidthTime invalid! (" << textWidthTime << ")"; return; } qint64 eventTime = EventTools::getEventTime(abstand); dbg_print(eventTime); QDateTime textWidthDt = QDateTime::fromMSecsSinceEpoch(textWidthTime); int days = textWidthDt.date().day() - 1; int hours = textWidthDt.time().hour() - 1; int minutes = textWidthDt.time().minute(); int seconds = textWidthDt.time().second() - 1; highestUnit unit = HU_INVALID; if (days == 0) if (hours == 0) if (minutes == 0) if (seconds == 0) { #ifdef VERBOSE qWarning() << "refreshData: no lower time unit available" ; #endif return; } else { unit = HU_SECONDS; } else { unit = HU_MINUTES; } else { unit = HU_HOURS; } else { unit = HU_DAYS; } if (unit == HU_INVALID) { #ifdef VERBOSE qWarning() << "unit == HU_INVALID"; #endif return; } int higherValue = 0; for (int i = 0; i < m_timeArray.size(); i++) { qint64 time = (m_timeArray[i] * 1000); if (time >= textWidthTime) { higherValue = time; break; } else { continue; } #ifdef VERBOSE qWarning() << "refreshData: no fitting highest unit found !" ; #endif return; } if (higherValue < 1) { return; } QDateTime minDt = QDateTime::fromMSecsSinceEpoch(adjustedMin); dbg_print(minDt); dbg_print(unit); switch (unit) { case HU_SECONDS: { minDt = minDt.addSecs(-(minDt.time().second())); #ifdef VERBOSE qCritical() << "HU_SECONDS"; #endif break; } case HU_MINUTES: { minDt = minDt.addSecs(-(minDt.time().second())); minDt = minDt.addSecs(-(minDt.time().minute() * 60)); #ifdef VERBOSE qCritical() << "HU_MINUTES"; #endif break; } case HU_HOURS: { minDt = minDt.addSecs(-(minDt.time().second())); minDt = minDt.addSecs(-(minDt.time().minute() * 60)); minDt = minDt.addSecs(-(minDt.time().hour() * 60 * 60)); #ifdef VERBOSE qCritical() << "HU_HOURS"; #endif break; } case HU_DAYS: { minDt = minDt.addSecs(-(minDt.time().second())); minDt = minDt.addSecs(-(minDt.time().minute() * 60)); minDt = minDt.addSecs(-(minDt.time().hour() * 60 * 60)); minDt = minDt.addDays(-(minDt.date().day())); #ifdef VERBOSE qCritical() << "HU_DAYS"; #endif break; } default: { #ifdef VERBOSE qWarning() << "unit / scaling is off da charz !"; #endif return; } } dbg_print(minDt); minDt = minDt.addMSecs(-higherValue); dbg_print(minDt); qint64 maxTimelineView = EventTools::getAdjustedMax() + (higherValue ); qint64 additional = textWidthTime / 2; maxTimelineView += additional; qint64 minTimeline = minDt.toMSecsSinceEpoch(); dbg_print(minTimeline); dbg_print(maxTimelineView); dbg_print(higherValue); qint64 steps = (maxTimelineView - minTimeline) / higherValue; if (steps < 0) steps = steps * (-1); if (steps > 60000 || steps < 1) { ERROR_LOG(m_logger) << "More than 60000 ("< 60000) break; currentStep++; int pos = EventTools::getEventPosition(indicatorTime); dbg_print(indicatorTime); if (pos + (m_currentTextWidth / 4) + 1 < m_sectionPos) { #ifdef VERBOSE qCritical() << "Indicator: pos" << pos << "invisible #1"; #endif continue; } else if (pos - (m_currentTextWidth ) > (m_sectionPos + m_sectionSize)) { #ifdef VERBOSE qCritical() << "Indicator: pos" << pos << "invisible #2"; #endif continue; } else { #ifdef VERBOSE qCritical() << "Indicator: OKAY!! pos" << pos << "visible"; #endif } emit signalAddLine(pos, indicatorTime); } dbg_print(currentStep); QFontMetrics fm(QApplication::font()); m_currentTextHeight = fm.height(); update(); } void TimelineIndicator::paintEvent(QPaintEvent *) { QPainter painter(this); painter.save(); painter.setClipping(true); painter.setClipRect(QRect(x() - 8 + m_sectionPos, 0, m_sectionSize, height())); #ifdef VERBOSE int textY = (height() - m_currentTextHeight - 5); #endif int h = height(); for (auto i = m_lineMap.constBegin(); i != m_lineMap.constEnd(); ++i) { int pos = i.key(); painter.setPen(QPen(QColor("black"), 1.0)); painter.drawLine(pos, m_currentTextHeight, pos, h); int centeredPos = pos - (m_currentTextWidth / 2); qint64 time = (*i); painter.drawText(centeredPos, (m_currentTextHeight / 2) + 4, DTG::toStringMSec(time, DTG::Short)); #ifdef VERBOSE WARNING_LOG(m_logger) << "paintEvent: actual drawing position: x=" << centeredPos << " y=" << textY; #endif } painter.restore(); } void TimelineIndicator::slotSectionResized(int logicalIndex, int oldSize, int newSize) { (void)oldSize; QHeaderView *header = qobject_cast(QObject::sender()); if (!header) return; if (logicalIndex == 1) { m_sectionPos = header->sectionPosition(1); m_sectionSize = newSize; } update(); } void TimelineIndicator::slotAddLine(double posX, qint64 time) { #ifdef VERBOSE qCritical() << "slotAddLine: posX" << posX << "time" << time; #endif m_lineMap.insert(posX, time); } void TimelineIndicator::slotResetLineList() { m_lineMap.clear(); } }