Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+629
@@ -0,0 +1,629 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_audio_video_widget.h"
|
||||
#include "thp_audio_video_widget_p.h"
|
||||
#include "ui_thp_audio_video_widget.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QMutex>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QGuiApplication>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vlc/libvlc_version.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
static const float s_speedArray[] =
|
||||
{
|
||||
1. / 8.,
|
||||
1. / 4.,
|
||||
1. / 2.,
|
||||
1.,
|
||||
2.,
|
||||
4.,
|
||||
8.
|
||||
};
|
||||
|
||||
/**
|
||||
* AudioVideoWidget::Private
|
||||
*/
|
||||
AudioVideoWidget::Private::Private(QFrame *parent)
|
||||
: m_vlcinstance(nullptr)
|
||||
, m_mPlayer(nullptr)
|
||||
, m_mListPlayer(nullptr)
|
||||
, m_mediaList(nullptr)
|
||||
, currentSpeedIdx(3)
|
||||
, m_parent(parent)
|
||||
, m_timer(new QTimer)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("THP.AudioVideoWidget"))
|
||||
{
|
||||
init();
|
||||
|
||||
connect(ui->btnSlower, &QToolButton::clicked, this, &AudioVideoWidget::Private::onSlower);
|
||||
connect(ui->btnFaster, &QToolButton::clicked, this, &AudioVideoWidget::Private::onFaster);
|
||||
connect(ui->btn100pct, &QToolButton::clicked, this, &AudioVideoWidget::Private::on100pct);
|
||||
connect(ui->btnPlay, &QToolButton::clicked, this, &AudioVideoWidget::Private::onPlay);
|
||||
connect(ui->btnStop, &QToolButton::clicked, this, &AudioVideoWidget::Private::onStop);
|
||||
connect(ui->sldPosition, &QSlider::sliderMoved, this, &AudioVideoWidget::Private::onPositionChanged);
|
||||
connect(ui->sldVolume, &QSlider::sliderMoved, this, &AudioVideoWidget::Private::onVolumeChanged);
|
||||
connect(m_timer, &QTimer::timeout, this, &AudioVideoWidget::Private::onUpdateGUI);
|
||||
|
||||
m_initThread = new AudioVideoInitThread(this);
|
||||
connect(m_initThread, &AudioVideoInitThread::finished, this, &AudioVideoWidget::Private::onVLCInstanceInitializd);
|
||||
m_initThread->start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
AudioVideoWidget::Private::~Private()
|
||||
{
|
||||
uninitVLCPlayer();
|
||||
uninitVLCInstance();
|
||||
delete ui;
|
||||
delete m_timer;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::init()
|
||||
{
|
||||
if (!m_parent)
|
||||
return false;
|
||||
ui = new Ui::audioVideoWidget();
|
||||
ui->setupUi(m_parent);
|
||||
|
||||
QPixmap pm(10, 10);
|
||||
pm.fill(Qt::black);
|
||||
ui->outputWidget->setPixmap(pm);
|
||||
ui->outputWidget->setScaledContents(true);
|
||||
|
||||
ui->sldPosition->setMaximum(1000);
|
||||
ui->sldVolume->setMaximum(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onVLCInstanceInitializd()
|
||||
{
|
||||
m_initThread->deleteLater();
|
||||
m_initThread = nullptr;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::setAV(bool isAudio)
|
||||
{
|
||||
if (isAudio)
|
||||
{
|
||||
delete ui->btn100pct;
|
||||
delete ui->btnFaster;
|
||||
delete ui->btnSlower;
|
||||
delete ui->outputWidget;
|
||||
ui->outputWidget = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// delete ui->verticalSpacer; ui->verticalSpacer = 0;
|
||||
delete ui->lblAudio;
|
||||
}
|
||||
}
|
||||
|
||||
static QMutex *serializeVLCInit()
|
||||
{
|
||||
static QMutex s_serializeVLCInit;
|
||||
return &s_serializeVLCInit;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::initVLCInstance(bool bInInitThread)
|
||||
{
|
||||
QMutexLocker l(serializeVLCInit());
|
||||
|
||||
if (!bInInitThread && m_initThread != nullptr)
|
||||
{
|
||||
QLabel myLabel;
|
||||
myLabel.setWindowTitle(tr("Loading VLC player..."));
|
||||
myLabel.setText(tr("Waiting until VLC player is loaded"));
|
||||
QRect r = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
myLabel.show();
|
||||
myLabel.move(r.width() / 2 - myLabel.width() / 2, r.height() / 2 - myLabel.height() / 2);
|
||||
myLabel.setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde.ico")));
|
||||
|
||||
while (m_initThread)
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
if (m_vlcinstance != nullptr)
|
||||
return true;
|
||||
|
||||
//preparation of the vlc command
|
||||
const char *vlc_argv[20];
|
||||
int iCount = 0;
|
||||
vlc_argv[iCount++] = "-I";
|
||||
vlc_argv[iCount++] = "dummy"; // Don't use any interface
|
||||
// vlc_argv[iCount++] = "--ignore-config"; // Don't use VLC's config
|
||||
#ifdef LTS_DEBUG
|
||||
vlc_argv[iCount++] = "--extraintf=logger"; // log anything
|
||||
vlc_argv[iCount++] = "--verbose=2"; // be much more verbose then normal for debugging purpose
|
||||
#else
|
||||
vlc_argv[iCount++] = "--quiet";
|
||||
#endif
|
||||
if (bInInitThread)
|
||||
vlc_argv[iCount++] = "--no-media-library";
|
||||
vlc_argv[iCount++] = "--";
|
||||
vlc_argv[iCount] = nullptr;
|
||||
|
||||
//Initialize an instance of vlc
|
||||
//create a new libvlc instance
|
||||
m_vlcinstance = libvlc_new(iCount, vlc_argv); //tricky calculation of the char space used
|
||||
if (!m_vlcinstance)
|
||||
ERROR_LOG(m_logger) << "Error initializing libVLC - unable to play audio or video";
|
||||
|
||||
return (m_vlcinstance != nullptr);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::uninitVLCInstance()
|
||||
{
|
||||
QMutexLocker l(serializeVLCInit());
|
||||
|
||||
if (!uninitVLCPlayer())
|
||||
return false;
|
||||
|
||||
if (m_vlcinstance)
|
||||
{
|
||||
libvlc_release(m_vlcinstance);
|
||||
m_vlcinstance = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::initVLCPlayer()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Initializing libVLC";
|
||||
if (m_mPlayer)
|
||||
{
|
||||
if (!ui)
|
||||
return false;
|
||||
ui->sldVolume->setValue(libvlc_audio_get_volume(m_mPlayer));
|
||||
return true;
|
||||
}
|
||||
|
||||
initVLCInstance();
|
||||
|
||||
//Initialize an instance of vlc
|
||||
//Create a media player playing environement
|
||||
m_mPlayer = libvlc_media_player_new(m_vlcinstance);
|
||||
m_mListPlayer = libvlc_media_list_player_new(m_vlcinstance);
|
||||
m_mediaList = libvlc_media_list_new(m_vlcinstance);
|
||||
|
||||
libvlc_media_list_player_set_media_player(m_mListPlayer, m_mPlayer);
|
||||
libvlc_media_list_player_set_media_list(m_mListPlayer, m_mediaList);
|
||||
|
||||
ui->sldVolume->setValue(libvlc_audio_get_volume(m_mPlayer));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::uninitVLCPlayer()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uninitializing libVLC";
|
||||
|
||||
if (m_mListPlayer)
|
||||
{
|
||||
/* Stop playing */
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
/* Free the media_player */
|
||||
libvlc_media_list_player_release(m_mListPlayer);
|
||||
m_mListPlayer = nullptr;
|
||||
}
|
||||
if (m_mediaList)
|
||||
{
|
||||
clearMediaList();
|
||||
libvlc_media_list_release(m_mediaList);
|
||||
m_mediaList = nullptr;
|
||||
}
|
||||
if (m_mPlayer)
|
||||
{
|
||||
/* Stop playing */
|
||||
libvlc_media_player_stop(m_mPlayer);
|
||||
/* Free the media_player */
|
||||
libvlc_media_player_release(m_mPlayer);
|
||||
|
||||
m_mPlayer = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::clearMediaList()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Clearing current playlist";
|
||||
|
||||
if (!m_mediaList)
|
||||
return;
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
for (int i = cnt - 1; i >= 0; --i)
|
||||
libvlc_media_list_remove_index(m_mediaList, i);
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::playVLC(const QUrl &url)
|
||||
{
|
||||
if (!ui)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Try to play " << url.toString();
|
||||
|
||||
const QString path = url.toLocalFile();
|
||||
if (path.isEmpty())
|
||||
return false;
|
||||
|
||||
clearMediaList();
|
||||
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
QFileInfo fi(path);
|
||||
DEBUG_LOG(m_logger) << "path: " << path << " isFile: " << fi.isFile();
|
||||
if (fi.isFile() && path.endsWith(QLatin1String(".pls")))
|
||||
{
|
||||
// pls parsing scheint nicht mehr richtig zu funktionieren - selbst machen
|
||||
DEBUG_LOG(m_logger) << "Parse Playlist";
|
||||
QFile f(path);
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Parse Playlist2 " << f.canReadLine();
|
||||
QMap<int, QByteArray> fileMap;
|
||||
QByteArray baAll = f.readAll();
|
||||
const QList<QByteArray> lines = baAll.split('\n');
|
||||
for (const QByteArray &line : lines)
|
||||
{
|
||||
QByteArray ba = line.trimmed();
|
||||
DEBUG_LOG(m_logger) << "ba: " << ba;
|
||||
if (!ba.startsWith("File "))
|
||||
continue;
|
||||
ba = ba.mid(qstrlen("File "));
|
||||
int idx = ba.indexOf('=');
|
||||
DEBUG_LOG(m_logger) << "idx: " << idx;
|
||||
if (idx < 0)
|
||||
continue;
|
||||
bool bOk;
|
||||
int id = ba.left(idx).toInt(&bOk);
|
||||
DEBUG_LOG(m_logger) << "id: " << id << " bOk: " << bOk << " str: " << ba.left(idx);
|
||||
if (!bOk)
|
||||
continue;
|
||||
QByteArray filename = ba.mid(idx + 1);
|
||||
DEBUG_LOG(m_logger) << "filename: " << filename;
|
||||
fileMap.insertMulti(id, fi.absolutePath().toLocal8Bit() + '/' + filename);
|
||||
}
|
||||
for (const QByteArray &fn : fileMap)
|
||||
{
|
||||
const QByteArray pNative = QDir::toNativeSeparators(QString::fromLocal8Bit(fn)).toLocal8Bit();
|
||||
DEBUG_LOG(m_logger) << "pNative: " << pNative;
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to " << pNative;
|
||||
return false;
|
||||
}
|
||||
//add option to disable hardware acceleration
|
||||
libvlc_media_add_option(media, ":avcodec-hw=none");
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
#if LIBVLC_VERSION_MAJOR > 2
|
||||
libvlc_media_parse_with_options(media, libvlc_media_parse_local, 0);
|
||||
#else
|
||||
libvlc_media_parse(media);
|
||||
#endif
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fi.isFile())
|
||||
{
|
||||
const QByteArray pNative = QDir::toNativeSeparators(path).toLocal8Bit();
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to '" << pNative << "'";
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
else if (fi.isDir())
|
||||
{
|
||||
QDirIterator dirIt(fi.absoluteFilePath());
|
||||
while (dirIt.hasNext())
|
||||
{
|
||||
const QString fn = dirIt.next();
|
||||
fi.setFile(fn);
|
||||
if (!fi.isFile())
|
||||
continue;
|
||||
const QByteArray pNative = QDir::toNativeSeparators(fn).toLocal8Bit();
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to " << pNative;
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
#if LIBVLC_VERSION_MAJOR > 2
|
||||
libvlc_media_parse_with_options(media, libvlc_media_parse_local, 0);
|
||||
#else
|
||||
libvlc_media_parse(media);
|
||||
#endif
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Unknown media given: " << path;
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
|
||||
if (ui->outputWidget)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
libvlc_media_player_set_hwnd(m_mPlayer, (HWND)ui->outputWidget->winId());
|
||||
#elif defined(Q_OS_MAC)
|
||||
libvlc_media_player_set_agl(m_mPlayer, ui->outputWidget->winId()) ;
|
||||
#else //Linux
|
||||
libvlc_media_player_set_xwindow(m_mPlayer, ui->outputWidget->winId());
|
||||
#endif
|
||||
}
|
||||
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
ui->btnPlay->setEnabled(true);
|
||||
ui->sldPosition->setEnabled(false);
|
||||
ui->btnStop->setEnabled(true);
|
||||
|
||||
currentSpeedIdx = 3;
|
||||
|
||||
QTimer::singleShot(0, this, &AudioVideoWidget::Private::onPlay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::stopVLC()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Stop playing";
|
||||
|
||||
QTimer::singleShot(0, this, &AudioVideoWidget::Private::onStop);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::setRate()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Setting speed to " << s_speedArray[currentSpeedIdx];
|
||||
|
||||
libvlc_state_t state = getState();
|
||||
if (state == libvlc_Playing || state == libvlc_Paused)
|
||||
libvlc_media_player_set_rate(m_mPlayer, s_speedArray[currentSpeedIdx]);
|
||||
}
|
||||
|
||||
libvlc_state_t AudioVideoWidget::Private::getState() const
|
||||
{
|
||||
libvlc_state_t s = libvlc_media_list_player_get_state(m_mListPlayer);
|
||||
static libvlc_state_t lastState = libvlc_NothingSpecial;
|
||||
if (s == lastState)
|
||||
return s;
|
||||
lastState = s;
|
||||
if (s == libvlc_Error)
|
||||
ERROR_LOG(m_logger) << "libVLC error: " << libvlc_errmsg();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void AudioVideoWidget::Private::onSlower()
|
||||
{
|
||||
if (currentSpeedIdx == 0)
|
||||
return;
|
||||
--currentSpeedIdx;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onFaster()
|
||||
{
|
||||
if (currentSpeedIdx == 6)
|
||||
return;
|
||||
++currentSpeedIdx;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::on100pct()
|
||||
{
|
||||
currentSpeedIdx = 3;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onPlay()
|
||||
{
|
||||
if (libvlc_media_list_player_is_playing(m_mListPlayer))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Pause playing";
|
||||
libvlc_media_list_player_pause(m_mListPlayer);
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_timer->stop();
|
||||
onUpdateGUIWithState(libvlc_Paused);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Start playing";
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-pause.png")));
|
||||
ui->sldPosition->setEnabled(true);
|
||||
|
||||
libvlc_media_list_player_play(m_mListPlayer);
|
||||
setRate();
|
||||
|
||||
m_timer->start(100);
|
||||
onUpdateGUIWithState(libvlc_Playing);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onStop()
|
||||
{
|
||||
if (!m_mListPlayer)
|
||||
return;
|
||||
|
||||
libvlc_state_t state = getState();
|
||||
|
||||
if (state == libvlc_Stopped)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Stop playing";
|
||||
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onPositionChanged(int newPosition)
|
||||
{
|
||||
libvlc_state_t state = getState();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Slider changed - going to new position";
|
||||
|
||||
if (state != libvlc_Playing && state != libvlc_Paused)
|
||||
return;
|
||||
|
||||
// Position geht von 0..1, Slider hat 1000 Steps
|
||||
libvlc_media_player_set_position(m_mPlayer, newPosition / 1000.);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onVolumeChanged(int newVol)
|
||||
{
|
||||
libvlc_audio_set_volume(m_mPlayer, newVol);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onUpdateGUI()
|
||||
{
|
||||
onUpdateGUIWithState(libvlc_NothingSpecial);
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onUpdateGUIWithState(libvlc_state_t overwrite_state)
|
||||
{
|
||||
libvlc_state_t state = overwrite_state;
|
||||
if (state == libvlc_NothingSpecial)
|
||||
state = getState();
|
||||
DEBUG_LOG(m_logger) << "onUpdateGUI for state " << state;
|
||||
|
||||
if (state == libvlc_Playing || state == libvlc_Paused)
|
||||
{
|
||||
double maxTime = libvlc_media_player_get_length(m_mPlayer) / 1000.;
|
||||
if (maxTime > 0.1)
|
||||
{
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
for (int i = cnt - 1; i >= 0; --i)
|
||||
{
|
||||
libvlc_media_t *media = libvlc_media_list_item_at_index(m_mediaList, i);
|
||||
DEBUG_LOG(m_logger) << "Duration: " << libvlc_media_get_duration(media);
|
||||
libvlc_media_release(media);
|
||||
}
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
|
||||
}
|
||||
double curTime = libvlc_media_player_get_time(m_mPlayer) / 1000.;
|
||||
auto curPos = libvlc_media_player_get_position(m_mPlayer);
|
||||
// Slider ist in 1000 Schritte eingeteilt
|
||||
ui->sldPosition->setValue(qRound(curPos * 1000));
|
||||
|
||||
const int minutesCur = floor(curTime / 60.);
|
||||
const int secondsCur = curTime - 60 * minutesCur;
|
||||
const int minutesAbs = floor(maxTime / 60.);
|
||||
const int secondsAbs = maxTime - 60 * minutesAbs;
|
||||
char timeStr[64];
|
||||
snprintf(timeStr, sizeof(timeStr), "%02d:%02d / %02d:%02d", minutesCur, secondsCur, minutesAbs, secondsAbs);
|
||||
ui->lblPosition->setText(QString::fromLatin1(timeStr));
|
||||
|
||||
}
|
||||
else if (state == libvlc_Stopped || state == libvlc_Ended)
|
||||
{
|
||||
// wir können nicht onStop() aufrufen -> rekursion!
|
||||
bool bStop = true;
|
||||
if (state == libvlc_Ended)
|
||||
{
|
||||
// Timer und VLC *nicht* stoppen da der aktuelle State ggf. genau zwischen den einzelnen
|
||||
// Video-Schnipseln einer Playlist abgefragt wurde
|
||||
// --> prüfen, ob es das letzte Video der Playlist war
|
||||
libvlc_media_t *media = libvlc_media_player_get_media(m_mPlayer);
|
||||
if (media != nullptr)
|
||||
{
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
if (cnt > 0)
|
||||
{
|
||||
libvlc_media_t *media2 = libvlc_media_list_item_at_index(m_mediaList, cnt - 1);
|
||||
bStop = (media2 == media);
|
||||
libvlc_media_release(media2);
|
||||
}
|
||||
libvlc_media_release(media);
|
||||
}
|
||||
if (bStop)
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
}
|
||||
if (bStop)
|
||||
{
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
ui->sldPosition->setEnabled(false);
|
||||
m_timer->stop();
|
||||
ui->sldPosition->setValue(0);
|
||||
ui->lblPosition->setText(QLatin1String("--:-- / --:--"));
|
||||
}
|
||||
}
|
||||
|
||||
QString speedStr = QStringLiteral("%1x").arg(s_speedArray[currentSpeedIdx], 4, 'f', 2);
|
||||
ui->lblSpeed->setText(speedStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* AudioVideoInitThread
|
||||
*/
|
||||
AudioVideoInitThread::AudioVideoInitThread(AudioVideoWidget::Private *p)
|
||||
: m_private(p)
|
||||
{}
|
||||
|
||||
void AudioVideoInitThread::run()
|
||||
{
|
||||
m_private->initVLCInstance(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* AudioVideoWidget
|
||||
*/
|
||||
AudioVideoWidget::AudioVideoWidget(QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, d(new Private(this))
|
||||
{}
|
||||
|
||||
AudioVideoWidget::~AudioVideoWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::play(const QUrl &file)
|
||||
{
|
||||
d->initVLCPlayer();
|
||||
return d->playVLC(file);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::stop()
|
||||
{
|
||||
return d->stopVLC();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::setAV(bool isAudio)
|
||||
{
|
||||
d->setAV(isAudio);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class AudioVideoWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioVideoWidget(QWidget *parent = nullptr);
|
||||
~AudioVideoWidget();
|
||||
|
||||
bool play(const QUrl &file);
|
||||
bool stop();
|
||||
void setAV(bool isAudio = false);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
friend class AudioVideoInitThread;
|
||||
};
|
||||
} // namespace THP
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>audioVideoWidget</class>
|
||||
<widget class="QFrame" name="audioVideoWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>911</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="outputWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAudio">
|
||||
<property name="text">
|
||||
<string>Audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldPosition">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPosition">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">55:55 / 55:55</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-playback-start.png</normaloff>:icons/16x16/media-playback-start.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-playback-stop.png</normaloff>:icons/16x16/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnSlower">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-slower.png</normaloff>:icons/16x16/media-play-slower.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn100pct">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-normal.png</normaloff>:icons/16x16/media-play-normal.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFaster">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-faster.png</normaloff>:icons/16x16/media-play-faster.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSpeed">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">100 %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Volume:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldVolume">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../Z/src/nglwidgets/nglresources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc, private data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// no ssize_t with msdn...
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#include <vlc/vlc.h>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "thp_audio_video_widget.h"
|
||||
|
||||
class QUrl;
|
||||
class QFrame;
|
||||
class QTimer;
|
||||
namespace Ui
|
||||
{
|
||||
class audioVideoWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class AudioVideoInitThread;
|
||||
class AudioVideoWidget::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Private(QFrame *parent);
|
||||
~Private();
|
||||
|
||||
bool initVLCInstance(bool bInInitThread = false);
|
||||
bool uninitVLCInstance();
|
||||
bool initVLCPlayer();
|
||||
bool uninitVLCPlayer();
|
||||
bool playVLC(const QUrl &url);
|
||||
bool stopVLC();
|
||||
void setAV(bool isAudio);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onSlower();
|
||||
void onFaster();
|
||||
void on100pct();
|
||||
void onPlay();
|
||||
void onStop();
|
||||
void onPositionChanged(int);
|
||||
void onVolumeChanged(int);
|
||||
void onUpdateGUI();
|
||||
void onVLCInstanceInitializd();
|
||||
|
||||
protected:
|
||||
void clearMediaList();
|
||||
void playVLCInternal();
|
||||
void onUpdateGUIWithState(libvlc_state_t overwrite_state);
|
||||
bool init();
|
||||
void setRate();
|
||||
libvlc_state_t getState() const;
|
||||
|
||||
libvlc_instance_t *m_vlcinstance;
|
||||
libvlc_media_player_t *m_mPlayer;
|
||||
libvlc_media_list_player_t *m_mListPlayer;
|
||||
libvlc_media_list_t *m_mediaList;
|
||||
|
||||
int currentSpeedIdx;
|
||||
|
||||
QFrame *m_parent;
|
||||
QTimer *m_timer;
|
||||
AudioVideoInitThread *m_initThread;
|
||||
|
||||
Ui::audioVideoWidget *ui;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
class AudioVideoInitThread final : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioVideoInitThread(AudioVideoWidget::Private *p);
|
||||
protected:
|
||||
void run() override;
|
||||
protected:
|
||||
AudioVideoWidget::Private *m_private;
|
||||
};
|
||||
} // namespace THP
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for MeteoDataManagement - Meteo Data Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-10-05
|
||||
*/
|
||||
|
||||
#include "thp_building_settings.h"
|
||||
#include "ui_thp_building_settings.h"
|
||||
#include <Common/bdv_controller.h>
|
||||
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
static QVariant getSetting(const QString &key, const QVariant &def)
|
||||
{
|
||||
return LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("BgViewer"), key, def);
|
||||
}
|
||||
|
||||
static void setSetting(const QString &key, const QVariant &val)
|
||||
{
|
||||
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("BgViewer"), key, val);
|
||||
}
|
||||
|
||||
BgViewerSettingsView::BgViewerSettingsView(BuildingViewer::BgViewerController *pBgvController,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::BgViewerSettingsUI)
|
||||
, m_pBgvController(pBgvController)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->m_pCheckBoxGlobalIsoMode, &QCheckBox::clicked, this, &BgViewerSettingsView::onViewModeChanged);
|
||||
connect(m_ui->m_pCheckBoxUseDotsMode, &QCheckBox::clicked, this, &BgViewerSettingsView::onPlayerDisplayModeChanged);
|
||||
connect(m_ui->m_pSliderGlobalTransparency, &QSlider::valueChanged, this, &BgViewerSettingsView::onTransparencyChanged);
|
||||
connect(m_ui->m_pSliderPlayerSymbolSize, &QSlider::valueChanged, this, &BgViewerSettingsView::onSymbolSizeChanged);
|
||||
connect(m_ui->m_slider_SymbolFlashing, &QSlider::valueChanged, this, &BgViewerSettingsView::onSymbolFireEventFlashingChanged);
|
||||
connect(m_ui->m_slider_HitlineDuration, &QSlider::valueChanged, this, &BgViewerSettingsView::onHitLineDisplayLengthChanged);
|
||||
|
||||
resetValues();
|
||||
onSymbolFireEventFlashingChanged(m_ui->m_slider_HitlineDuration->value());
|
||||
onHitLineDisplayLengthChanged(m_ui->m_slider_SymbolFlashing->value());
|
||||
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &BgViewerSettingsView::accept);
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &BgViewerSettingsView::reject);
|
||||
}
|
||||
|
||||
|
||||
BgViewerSettingsView::~BgViewerSettingsView()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void BgViewerSettingsView::accept()
|
||||
{
|
||||
setSetting(QStringLiteral("GlobalTransparency"), m_ui->m_pSliderGlobalTransparency->value());
|
||||
setSetting(QStringLiteral("UseIsoMode"), m_ui->m_pCheckBoxGlobalIsoMode->isChecked());
|
||||
setSetting(QStringLiteral("UseDotsMode"), m_ui->m_pCheckBoxUseDotsMode->isChecked());
|
||||
setSetting(QStringLiteral("PlayerSymbolSize"), m_ui->m_pSliderPlayerSymbolSize->value());
|
||||
setSetting(QStringLiteral("maxHitlineDurationTime_s"), m_ui->m_slider_HitlineDuration->value());
|
||||
setSetting(QStringLiteral("GearFlashTime_s"), m_ui->m_slider_SymbolFlashing->value());
|
||||
setSetting(QStringLiteral("maxGearFlashTime_s"), m_ui->m_slider_SymbolFlashing->maximum());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::reject()
|
||||
{
|
||||
resetValues();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::resetValues()
|
||||
{
|
||||
m_ui->m_pSliderGlobalTransparency->setValue(getSetting(QStringLiteral("GlobalTransparency"), 75).toInt());
|
||||
m_ui->m_pCheckBoxGlobalIsoMode->setChecked(getSetting(QStringLiteral("UseIsoMode"), false).toBool());
|
||||
m_ui->m_pCheckBoxUseDotsMode->setChecked(getSetting(QStringLiteral("UseDotsMode"), false).toBool()) ;
|
||||
m_ui->m_pSliderPlayerSymbolSize->setValue(getSetting(QStringLiteral("PlayerSymbolSize"), 20).toInt());
|
||||
m_ui->m_slider_HitlineDuration->setValue(getSetting(QStringLiteral("maxHitlineDurationTime_s"), 10).toInt());
|
||||
m_ui->m_slider_SymbolFlashing->setValue(getSetting(QStringLiteral("GearFlashTime_s"), 10).toInt());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onViewModeChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalViewMode(m_ui->m_pCheckBoxGlobalIsoMode->isChecked());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onPlayerDisplayModeChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalDotsMode(m_ui->m_pCheckBoxUseDotsMode->isChecked());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onSymbolSizeChanged()
|
||||
{
|
||||
m_pBgvController->updatePlayerSymbols(m_ui->m_pSliderPlayerSymbolSize->value());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onTransparencyChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalTransparency(m_ui->m_pSliderGlobalTransparency->value());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onSymbolFireEventFlashingChanged(int val)
|
||||
{
|
||||
// only modified per config setting...
|
||||
m_ui->m_label_durationSymbolFlashing->setText(tr("%1 sec").arg(val));
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onHitLineDisplayLengthChanged(int val)
|
||||
{
|
||||
m_pBgvController->excSetHitlineDuration(val);
|
||||
m_ui->m_label_HitlineDuration->setText(tr("%1 sec").arg(val));
|
||||
}
|
||||
|
||||
} // namespace BuildingViewer
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for MeteoDataManagement - Meteo Data Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-10-05
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class BgViewerSettingsUI;
|
||||
}
|
||||
|
||||
namespace BuildingViewer
|
||||
{
|
||||
class BgViewerController;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class BgViewerSettingsView final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BgViewerSettingsView(BuildingViewer::BgViewerController *pBgvController,
|
||||
QWidget *parent = nullptr);
|
||||
~BgViewerSettingsView();
|
||||
|
||||
private slots:
|
||||
void onViewModeChanged();
|
||||
void onPlayerDisplayModeChanged();
|
||||
void onTransparencyChanged();
|
||||
void onSymbolSizeChanged();
|
||||
void onSymbolFireEventFlashingChanged(int val);
|
||||
void onHitLineDisplayLengthChanged(int val);
|
||||
|
||||
private:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
void resetValues();
|
||||
|
||||
Ui::BgViewerSettingsUI *m_ui;
|
||||
BuildingViewer::BgViewerController *m_pBgvController;
|
||||
};
|
||||
|
||||
} // namespace BuildingViewer
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BgViewerSettingsUI</class>
|
||||
<widget class="QWidget" name="BgViewerSettingsUI">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">General Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="2">
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="m_pSliderGlobalTransparency">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>75</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="m_pCheckBoxGlobalIsoMode">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use orthographic view mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Player symbol size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="m_label_durationSymbolFlashing">
|
||||
<property name="text">
|
||||
<string>%1 sec</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="m_label_HitlineDuration">
|
||||
<property name="text">
|
||||
<string>%1 sec</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Symbol fire event flashing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSlider" name="m_pSliderPlayerSymbolSize">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>45</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Transparency value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Hit line display length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSlider" name="m_slider_HitlineDuration">
|
||||
<property name="maximum">
|
||||
<number>120</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="m_pCheckBoxUseDotsMode">
|
||||
<property name="text">
|
||||
<string>Use dots mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSlider" name="m_slider_SymbolFlashing">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>120</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle bulding display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_building_widget.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
#include "thp_building_settings.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
#include <BuildingViewer/Common/bdv_controller.h>
|
||||
#include <BuildingViewer/Common/bdv_plugin_provider.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsWidgets/lts_dialog_helper.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
using namespace SituationReplay;
|
||||
|
||||
BuildingWidget::BuildingWidget(QWidget *parent)
|
||||
: SituationBuildingBase("THP.BuildingWidget", parent)
|
||||
{
|
||||
QMenu *m = new QMenu(m_ui->btnFilter);
|
||||
m->addAction(tr("Global Settings"), this, &BuildingWidget::onGlobalSettings);
|
||||
m_ui->btnFilter->setMenu(m);
|
||||
}
|
||||
|
||||
BuildingWidget::~BuildingWidget()
|
||||
{
|
||||
delete m_bgvController;
|
||||
}
|
||||
|
||||
bool BuildingWidget::init(SituationReplay::MainHandlerSqlite *mhs, BuildingPluginProvider *pp, const QString &homePath)
|
||||
{
|
||||
if (!SituationBuildingBase::init(mhs))
|
||||
return false;
|
||||
m_replayHandler = mhs;
|
||||
m_pluginProvider = pp;
|
||||
|
||||
// parse json, create xml, init buildingviewer
|
||||
delete m_bgvController;
|
||||
m_bgvController = new BuildingViewer::BgViewerController(this);
|
||||
if (!m_bgvController->init(m_pluginProvider, true, homePath + QStringLiteral("/BuildingModels/")))
|
||||
return false;
|
||||
|
||||
auto w = m_bgvController->getBgViewerWidget();
|
||||
w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildingWidget::showSituationInternal()
|
||||
{
|
||||
m_bgvController->excRestoreViewState(m_attributes[QStringLiteral("arrBuildingStates")]);
|
||||
if (!SituationBuildingBase::showSituationInternal())
|
||||
return false;
|
||||
onInitDone();
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildingWidget::emitPartitionTimeChanged(qint64 curTime)
|
||||
{
|
||||
m_pluginProvider->emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void BuildingWidget::onGlobalSettings()
|
||||
{
|
||||
if (!m_globalSettingsDialog)
|
||||
m_globalSettingsDialog = new BgViewerSettingsView(m_bgvController, this);
|
||||
m_globalSettingsDialog->show();
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle bulding display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
#include "thp_situation_building_base.h"
|
||||
|
||||
namespace BuildingViewer
|
||||
{
|
||||
class BgViewerController;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class BuildingWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class BuildingPluginProvider;
|
||||
class BgViewerSettingsView;
|
||||
class BuildingWidget : public SituationBuildingBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BuildingWidget(QWidget *parent = nullptr);
|
||||
~BuildingWidget();
|
||||
|
||||
bool init(SituationReplay::MainHandlerSqlite *mhs,
|
||||
BuildingPluginProvider *pp,
|
||||
const QString &homePath);
|
||||
|
||||
protected:
|
||||
bool showSituationInternal() override;
|
||||
void emitPartitionTimeChanged(qint64 curTime) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onGlobalSettings();
|
||||
virtual void applyCurentFilter(const SituationReplay::FilterInformation &) override {}
|
||||
virtual void applyNewOverlay(int) override {}
|
||||
virtual void removeOverlay(int) override {}
|
||||
private:
|
||||
BuildingPluginProvider *m_pluginProvider = nullptr;
|
||||
BuildingViewer::BgViewerController *m_bgvController = nullptr;
|
||||
BgViewerSettingsView *m_globalSettingsDialog = nullptr;
|
||||
};
|
||||
} // namespace THP
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle HTML output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_html_widget.h"
|
||||
#include "ui_thp_html_widget.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QWebEnginePage>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
class MyQWebEnginePage : public QWebEnginePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyQWebEnginePage(NGL::INGLLogger &logger, QObject *parent = nullptr)
|
||||
: QWebEnginePage(parent)
|
||||
, m_logger(logger)
|
||||
{}
|
||||
MyQWebEnginePage(NGL::INGLLogger &logger, QWebEngineProfile *profile, QObject *parent = nullptr)
|
||||
: QWebEnginePage(profile, parent)
|
||||
, m_logger(logger)
|
||||
{}
|
||||
|
||||
bool needsToBeOpenedExternally(const QUrl &url)
|
||||
{
|
||||
const QString lpath = url.toString();
|
||||
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
|
||||
const QStringRef ext2Chars = ext.left(2);
|
||||
if (ext == QLatin1String("html") &&
|
||||
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
return true;
|
||||
// PDF
|
||||
if (ext == QLatin1String("pdf"))
|
||||
return true;
|
||||
// A/V playlist
|
||||
if (ext == QLatin1String("pls"))
|
||||
return true;
|
||||
// Situation
|
||||
if (ext == QLatin1String("json"))
|
||||
return true;
|
||||
// Word/Excel/PowerPoint
|
||||
if (ext2Chars == QLatin1String("do") ||
|
||||
ext2Chars == QLatin1String("xl") ||
|
||||
ext2Chars == QLatin1String("pp"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool acceptNavigationRequest(const QUrl &url,
|
||||
QWebEnginePage::NavigationType type,
|
||||
bool isMainFrame) override
|
||||
{
|
||||
Q_UNUSED(isMainFrame)
|
||||
if (type == QWebEnginePage::NavigationTypeLinkClicked)
|
||||
{
|
||||
if (needsToBeOpenedExternally(url))
|
||||
{
|
||||
emit linkClicked(url);
|
||||
DEBUG_LOG(m_logger) << "acceptNavigationRequest denied for " << url.toString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "acceptNavigationRequest allowed for " << url.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void linkClicked(const QUrl &url);
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
HtmlWidget::HtmlWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::HtmlWidget)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("THP.HtmlWidget"))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto webEnginePage = new MyQWebEnginePage(m_logger, this);
|
||||
ui->html->setPage(webEnginePage);
|
||||
connect(webEnginePage, &MyQWebEnginePage::linkClicked, this, &HtmlWidget::linkClicked);
|
||||
connect(ui->html, &QWebEngineView::loadFinished, this, &HtmlWidget::loadFinished);
|
||||
connect(ui->html, &QWebEngineView::urlChanged, this, &HtmlWidget::urlChanged);
|
||||
connect(ui->html, &QWebEngineView::titleChanged, this, &HtmlWidget::titleChanged);
|
||||
}
|
||||
|
||||
HtmlWidget::~HtmlWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void HtmlWidget::back()
|
||||
{
|
||||
ui->html->back();
|
||||
}
|
||||
|
||||
QString HtmlWidget::title() const
|
||||
{
|
||||
return ui->html->title();
|
||||
}
|
||||
|
||||
QUrl HtmlWidget::url() const
|
||||
{
|
||||
return ui->html->url();
|
||||
}
|
||||
|
||||
bool HtmlWidget::showHTML(const QUrl &url)
|
||||
{
|
||||
if (!url.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Invalid url: " << url.toString();
|
||||
return false;
|
||||
}
|
||||
ui->html->load(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HtmlWidget::setZoomFactor(double newZoomFactor)
|
||||
{
|
||||
ui->html->setZoomFactor(newZoomFactor);
|
||||
}
|
||||
|
||||
void HtmlWidget::print(QPrinter *printer) const
|
||||
{
|
||||
ui->html->page()->print(printer, [](bool) {});
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
#include "thp_html_widget.moc"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle HTML output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
class QUrl;
|
||||
class QPrinter;
|
||||
namespace Ui
|
||||
{
|
||||
class HtmlWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class HtmlWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HtmlWidget(QWidget *parent = nullptr);
|
||||
~HtmlWidget();
|
||||
|
||||
void back();
|
||||
void print(QPrinter *printer) const;
|
||||
void setZoomFactor(double newZoomFactor);
|
||||
QString title() const;
|
||||
QUrl url() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool showHTML(const QUrl &url);
|
||||
|
||||
Q_SIGNALS:
|
||||
void linkClicked(const QUrl &link);
|
||||
void loadFinished(bool);
|
||||
void urlChanged(const QUrl &url);
|
||||
void titleChanged(const QString &title);
|
||||
protected:
|
||||
Ui::HtmlWidget *ui;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace THP
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>HtmlWidget</class>
|
||||
<widget class="QWidget" name="HtmlWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>719</width>
|
||||
<height>540</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWebEngineView" name="html">
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle PDF output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_pdf_widget.h"
|
||||
#include "ui_thp_pdf_widget.h"
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
PdfWidget::PdfWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PdfWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->previousPage, &QToolButton::clicked, this, &PdfWidget::onPreviousPage);
|
||||
connect(ui->nextPage, &QToolButton::clicked, this, &PdfWidget::onNextPage);
|
||||
connect(ui->pdfDocument, &NGL::PDFDocument::currentPageChanged, this, &PdfWidget::pageChanged);
|
||||
}
|
||||
|
||||
PdfWidget::~PdfWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool PdfWidget::showPDF(const QUrl &pdf)
|
||||
{
|
||||
return ui->pdfDocument->showPDF(pdf);
|
||||
}
|
||||
|
||||
void PdfWidget::setZoomFactor(double newZoomFactor)
|
||||
{
|
||||
ui->pdfDocument->setZoomFactor(newZoomFactor);
|
||||
}
|
||||
|
||||
void PdfWidget::onPreviousPage()
|
||||
{
|
||||
ui->pdfDocument->previousPage();
|
||||
}
|
||||
|
||||
void PdfWidget::onNextPage()
|
||||
{
|
||||
ui->pdfDocument->nextPage();
|
||||
}
|
||||
|
||||
QVector<QImage> PdfWidget::getPrintableImages(int resolution)
|
||||
{
|
||||
return ui->pdfDocument->getPrintableImages(resolution);
|
||||
}
|
||||
|
||||
void PdfWidget::resizePdfToWidth()
|
||||
{
|
||||
ui->pdfDocument->resizePdfToWidth();
|
||||
}
|
||||
|
||||
void PdfWidget::pageChanged(int cur, int max)
|
||||
{
|
||||
ui->pageLabel->setText(tr("Page %1 of %2").arg(cur).arg(max));
|
||||
ui->nextPage->setEnabled(cur < max);
|
||||
ui->previousPage->setEnabled(cur > 1);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle PDF output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class QUrl;
|
||||
namespace Ui
|
||||
{
|
||||
class PdfWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class PdfWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PdfWidget(QWidget *parent = nullptr);
|
||||
~PdfWidget();
|
||||
|
||||
bool showPDF(const QUrl &pdf);
|
||||
void setZoomFactor(double newZoomFactor);
|
||||
QVector<QImage> getPrintableImages(int resolution = 300);
|
||||
void resizePdfToWidth();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPreviousPage();
|
||||
void onNextPage();
|
||||
void pageChanged(int cur, int max);
|
||||
protected:
|
||||
|
||||
Ui::PdfWidget *ui;
|
||||
};
|
||||
} // namespace THP
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PdfWidget</class>
|
||||
<widget class="QWidget" name="PdfWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>580</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="NGL::PDFDocument" name="pdfDocument" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>202</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QToolButton" name="previousPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-previous.png</normaloff>:icons/16x16/go-previous.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pageLabel">
|
||||
<property name="text">
|
||||
<string>page %1 of %2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="nextPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-next.png</normaloff>:icons/16x16/go-next.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>201</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NGL::PDFDocument</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">nglwidgets/nglpdfdocument.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_building_base.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
#include "thp_situation_filter_types.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QTimer>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
#include <PlanOverlays/Gui/plan_overlay_model.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
using namespace SituationReplay;
|
||||
|
||||
SituationBuildingBase::SituationBuildingBase(const char *loggerName,
|
||||
QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, m_playTimer(new QTimer(this))
|
||||
, m_ui(new Ui::SituationBuildingBase)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->zoomSlider->hide();
|
||||
m_ui->sldPosition->setMinimum(0);
|
||||
m_ui->sldPosition->setMaximum(s_sliderMax);
|
||||
|
||||
m_playTimer->setSingleShot(true);
|
||||
connect(m_playTimer, &QTimer::timeout, this, &SituationBuildingBase::onPlay);
|
||||
|
||||
connect(m_ui->btnSlower, &QToolButton::clicked, this, &SituationBuildingBase::onSlower);
|
||||
connect(m_ui->btnFaster, &QToolButton::clicked, this, &SituationBuildingBase::onFaster);
|
||||
connect(m_ui->btn100pct, &QToolButton::clicked, this, &SituationBuildingBase::on100pct);
|
||||
connect(m_ui->btnPlay, &QToolButton::clicked, this, &SituationBuildingBase::onPlay);
|
||||
connect(m_ui->btnStop, &QToolButton::clicked, this, &SituationBuildingBase::onStop);
|
||||
|
||||
connect(m_ui->sldPosition, &QSlider::sliderPressed, this, &SituationBuildingBase::onSliderPressed);
|
||||
connect(m_ui->sldPosition, &QSlider::sliderMoved, this, &SituationBuildingBase::onSliderPositionChanged);
|
||||
connect(m_ui->sldPosition, &QSlider::sliderReleased, this, &SituationBuildingBase::onSliderReleased);
|
||||
|
||||
connect(m_ui->cbPlaybackParts, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &SituationBuildingBase::onCbPlaybackPartsChanged);
|
||||
}
|
||||
|
||||
SituationBuildingBase::~SituationBuildingBase()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::init(SituationReplay::MainHandlerSqlite *replayHandler)
|
||||
{
|
||||
if (m_replayHandler)
|
||||
m_replayHandler->disconnect(this);
|
||||
m_replayHandler = replayHandler;
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::initialReplaySpeed,
|
||||
this, &SituationBuildingBase::setSpeed);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::applyCurentFilter,
|
||||
this, &SituationBuildingBase::applyCurentFilter);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::applyNewOverlay,
|
||||
this, &SituationBuildingBase::applyNewOverlay);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::removeOverlay,
|
||||
this, &SituationBuildingBase::removeOverlay);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::fileContentAvailable,
|
||||
this, &SituationBuildingBase::onFileContentAvailable);
|
||||
updatePositionLabel(LtsUtils::QPoint3D(), false);
|
||||
updateSpeedLabel();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::showSituation(const QString &sitReplayDescription,
|
||||
const QString &basePath)
|
||||
{
|
||||
// read ReplayInformation from sitmap.json (key 'replays')
|
||||
|
||||
QFile f(sitReplayDescription); // ...Exercise_123//n/m/sitmap.json
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open file '" << sitReplayDescription << "': " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi(f);
|
||||
m_scriptPath = fi.absolutePath();
|
||||
|
||||
QJsonParseError jError;
|
||||
const QByteArray ba = f.readAll();
|
||||
QJsonDocument doc(QJsonDocument::fromJson(ba, &jError));
|
||||
if (jError.error)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: " << jError.errorString();
|
||||
return false;
|
||||
}
|
||||
const QJsonObject rootObj = doc.object();
|
||||
const QJsonArray arrReplays(rootObj[QStringLiteral("replays")].toArray());
|
||||
QVector<ReplayInformation> replayInformation;
|
||||
replayInformation.reserve(arrReplays.size());
|
||||
for (const auto &val : arrReplays)
|
||||
{
|
||||
const QJsonObject obj = val.toObject();
|
||||
const QJsonObject objPb = obj[QStringLiteral("playbackTime")].toObject();
|
||||
const QJsonObject objSqlite = obj[QStringLiteral("replayInformation")].toObject();
|
||||
const QJsonObject objTip = objSqlite[QStringLiteral("timeInPresentation")].toObject();
|
||||
ReplayInformation info;
|
||||
info.id = obj[QStringLiteral("id")].toInt();
|
||||
info.timeSpan = TimeSpan::fromJson(objPb);
|
||||
info.relativeTimeSpan = TimeSpan::fromJson(objTip);
|
||||
const int sqliteFolderId = objSqlite[QStringLiteral("id")].toInt();
|
||||
info.databaseFilePath = QStringLiteral("%1/%2/sitreplay.sqlite").arg(basePath).arg(sqliteFolderId);
|
||||
info.replayConfigPath = QStringLiteral("%1/%2/sitreplay.json").arg(basePath).arg(sqliteFolderId);
|
||||
if (info.relativeTimeSpan.begin < 0 ||
|
||||
info.relativeTimeSpan.end <= info.relativeTimeSpan.begin ||
|
||||
sqliteFolderId == 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
replayInformation.push_back(std::move(info));
|
||||
}
|
||||
const QJsonObject attributes(rootObj[QStringLiteral("attributes")].toObject());
|
||||
const QJsonArray arrFilters1(attributes[QStringLiteral("Filters")].toArray());
|
||||
QVector<FilterInformation> filterInformation;
|
||||
QVector<FilterInformation> overlayInformation;
|
||||
|
||||
for (const auto &arrVal : arrFilters1)
|
||||
{
|
||||
// const QJsonArray arrFilters2(arrVal.toArray());
|
||||
// for (const auto &val : arrFilters2)
|
||||
// {
|
||||
FilterInformation filter;
|
||||
const QJsonObject obj = arrVal.toObject();
|
||||
LtsScriptTimeline::TrackEntry te;
|
||||
te.fromJson(obj);
|
||||
if (te.m_topicId <= 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not load filter information from '" << QJsonDocument(obj).toJson() << "'";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (te.m_type != LtsScriptTimeline::TrackEntryType::SituationMapFilter &&
|
||||
te.m_type != LtsScriptTimeline::TrackEntryType::TacticalPlan)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Unknown Filter type " << te.m_type << " - ignoring: " << QJsonDocument(obj).toJson() << "'";
|
||||
continue;
|
||||
}
|
||||
|
||||
filter.id = te.m_topicId;
|
||||
filter.relativeTimeSpan.begin = te.m_startTime * 1000LL;
|
||||
filter.relativeTimeSpan.end = te.m_length * 1000LL + filter.relativeTimeSpan.begin;
|
||||
const QJsonObject details = obj[QStringLiteral("detailData")].toObject();
|
||||
if (te.m_type == LtsScriptTimeline::TrackEntryType::SituationMapFilter)
|
||||
{
|
||||
const QJsonObject filters = te.m_detailData[QStringLiteral("filters")].toObject();
|
||||
filter.aesFilters = filters[QStringLiteral("AesFilterJson")].toObject();
|
||||
filter.symbolSettings = filters[QStringLiteral("SymbolAppearanceJson")].toObject();
|
||||
filter.buildingComponentSettings = filters[QStringLiteral("BuildingComponentSettingsJson")].toObject();
|
||||
filter.mapSettings = details[QStringLiteral("settings")].toObject();
|
||||
|
||||
if (filter.relativeTimeSpan.begin < 0 || filter.aesFilters.isEmpty() || filter.symbolSettings.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
if (filter.buildingComponentSettings.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data 'BuildingComponentSettingsJson', json= " << QJsonDocument(obj).toJson();
|
||||
// return false; // support older thps with this thpViewer
|
||||
}
|
||||
|
||||
|
||||
filterInformation.push_back(std::move(filter));
|
||||
}
|
||||
else if (te.m_type == LtsScriptTimeline::TrackEntryType::TacticalPlan)
|
||||
{
|
||||
if (filter.relativeTimeSpan.begin < 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
|
||||
// old version (before 2020/02)
|
||||
filter.overlayId = details[QStringLiteral("FileId")].toInt(-1);
|
||||
if (filter.overlayId >= 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Add overlay with id " << filter.overlayId;
|
||||
overlayInformation.push_back(std::move(filter));
|
||||
continue;
|
||||
}
|
||||
const QJsonArray arr = details[QStringLiteral("PlanItems")].toArray();
|
||||
if (arr.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No PlanItems given - " << QJsonDocument(details).toJson();
|
||||
}
|
||||
for (const auto &ele : arr)
|
||||
{
|
||||
const auto pi = PlanOverlaysPlugin::PlanOverlayModel::PlanItem::fromJson(ele.toObject());
|
||||
if (!pi.isValid() || pi.m_fileId <= 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(ele.toObject()).toJson();
|
||||
return false;
|
||||
}
|
||||
filter.overlayId = pi.m_fileId;
|
||||
DEBUG_LOG(m_logger) << "Add overlay with id " << filter.overlayId;
|
||||
overlayInformation.push_back(filter);
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
m_replayInformation = replayInformation;
|
||||
m_filterInformation = filterInformation;
|
||||
m_overlayInformation = overlayInformation;
|
||||
m_attributes = rootObj[QStringLiteral("attributes")].toObject();
|
||||
return showSituationInternal();
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::showSituationInternal()
|
||||
{
|
||||
m_ui->cbPlaybackParts->setVisible(m_replayInformation.size() > 1);
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString sqliteDb = m_replayInformation.first().databaseFilePath;
|
||||
if (sqliteDb.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No database given...";
|
||||
return false;
|
||||
}
|
||||
QFileInfo fi(sqliteDb);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
WARNING_LOG(m_logger) << "Can not access sqlite database '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ui->cbPlaybackParts->clear();
|
||||
m_ui->cbPlaybackParts->blockSignals(true);
|
||||
for (int i = 0; i < m_replayInformation.size(); ++i)
|
||||
{
|
||||
const ReplayInformation &info = m_replayInformation.at(i);
|
||||
m_ui->cbPlaybackParts->addItem(QStringLiteral("%1: %2 - %3").arg(i+1).arg(DTG::toStringMSec(info.timeSpan.begin, DTG::Long),
|
||||
DTG::toStringMSec(info.timeSpan.end, DTG::Long)), i);
|
||||
}
|
||||
m_ui->cbPlaybackParts->setCurrentIndex(0);
|
||||
m_ui->cbPlaybackParts->blockSignals(false);
|
||||
onCbPlaybackPartsChanged(); // creates replayHandler for correct db etc.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::setSpeed(double newSpeed)
|
||||
{
|
||||
m_speedVal = qBound(0.0, newSpeed, 16.0);
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPaceChangeRequest(m_speedVal);
|
||||
|
||||
updateSpeedLabel();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSlower()
|
||||
{
|
||||
// cur speed = 9 -> new speed = 7
|
||||
// cur speed = 4 -> new speed = 3
|
||||
int diff = lrint(sqrt(m_speedVal) - 1);
|
||||
if (diff < 1)
|
||||
diff = 1;
|
||||
setSpeed(m_speedVal - diff);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onFaster()
|
||||
{
|
||||
int diff = lrint(sqrt(m_speedVal) - 1);
|
||||
if (diff < 1)
|
||||
diff = 1;
|
||||
setSpeed(m_speedVal + diff);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::on100pct()
|
||||
{
|
||||
setSpeed(1.0);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onPlay()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "OnPlay " << int(m_state);
|
||||
switch (m_state)
|
||||
{
|
||||
case State::PS_STOP:
|
||||
m_state = State::PS_PLAY;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStartReplayRequest(m_speedVal);
|
||||
break;
|
||||
case State::PS_PAUSE:
|
||||
m_state = State::PS_PLAY;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onResumeReplayRequest();
|
||||
break;
|
||||
case State::PS_PLAY:
|
||||
m_state = State::PS_PAUSE;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPauseReplayRequest();
|
||||
break;
|
||||
case State::PS_UNDEFINED:
|
||||
// dürfte nicht vorkommen
|
||||
break;
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onStop()
|
||||
{
|
||||
auto srp = m_replayHandler->handlerSrp();
|
||||
if (srp)
|
||||
{
|
||||
srp->onStopReplayRequest();
|
||||
onUpdateTimeSlider(srp->beginTime());
|
||||
}
|
||||
m_state = State::PS_STOP;
|
||||
updateButtons();
|
||||
m_ui->sldPosition->setValue(0);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderPressed()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPauseReplayRequest();
|
||||
m_state = State::PS_PAUSE;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderPositionChanged(int newPosition)
|
||||
{
|
||||
if (!m_replayHandler->handlerSrp())
|
||||
return;
|
||||
auto srp = m_replayHandler->handlerSrp();
|
||||
const double len = (srp->endTime() - srp->beginTime());
|
||||
const double ofs = newPosition * len / s_sliderMax;
|
||||
m_sliderMoveTime = qRound64(srp->beginTime() + ofs);
|
||||
|
||||
m_currentTimeDTGString = DTG::toStringMSec(m_sliderMoveTime, DTG::Long);
|
||||
m_ui->lblPosition->setText(m_currentTimeDTGString);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderReleased()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStartReplayRequest(m_sliderMoveTime,
|
||||
m_replayHandler->handlerSrp()->endTime(),
|
||||
m_speedVal);
|
||||
m_state = State::PS_PLAY;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onUpdateTimeSlider(qint64 curTime)
|
||||
{
|
||||
if (!m_replayHandler->handlerSrp() || m_state == State::PS_STOP)
|
||||
return;
|
||||
const auto srp = m_replayHandler->handlerSrp();
|
||||
const double len = (srp->endTime() - srp->beginTime());
|
||||
const double ofs = (curTime - srp->beginTime());
|
||||
double pos = ofs / len * s_sliderMax;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
if (pos >= s_sliderMax)
|
||||
{
|
||||
onStop();
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "onUpdateTimeSlider: " << curTime << ", pos: " << pos;
|
||||
m_ui->sldPosition->setValue(qRound(pos));
|
||||
|
||||
m_currentTimeDTGString = DTG::toStringMSec(curTime, DTG::Long);
|
||||
m_ui->lblPosition->setText(m_currentTimeDTGString);
|
||||
emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onCbPlaybackPartsChanged()
|
||||
{
|
||||
onStop();
|
||||
int idx = m_ui->cbPlaybackParts->currentData().toInt();
|
||||
if (idx < 0 || idx >= m_replayInformation.size())
|
||||
return;
|
||||
const ReplayInformation &info = m_replayInformation.at(idx);
|
||||
if (!m_replayHandler->initDb(info, m_filterInformation, m_overlayInformation))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not initialize replay handler (" << info.databaseFilePath << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
// currently after initDb since there handlerSrp is (re)created
|
||||
connect(m_replayHandler->handlerSrp().get(), &SituationReplay::HandlerSituationReplaySqlite::replayTimeChanged,
|
||||
this, &SituationBuildingBase::onUpdateTimeSlider, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updateSpeedLabel()
|
||||
{
|
||||
QString speedStr = QStringLiteral("%1x").arg(m_speedVal, 4, 'f', 2);
|
||||
m_ui->lblSpeed->setText(speedStr);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updatePositionLabel(const LtsUtils::QPoint3D &geoPos, bool isValid)
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.x(), geoPos.y()));
|
||||
m_ui->lblCursorPos->setText(coord.mgrs());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->lblCursorPos->setText(QString());
|
||||
}
|
||||
}
|
||||
|
||||
QString SituationBuildingBase::currentDTGTime() const
|
||||
{
|
||||
return m_currentTimeDTGString;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updateButtons()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case State::PS_UNDEFINED:
|
||||
m_ui->btnStop->setEnabled(false);
|
||||
m_ui->btnPlay->setEnabled(false);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(false);
|
||||
break;
|
||||
case State::PS_STOP:
|
||||
m_ui->btnStop->setEnabled(false);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
case State::PS_PLAY:
|
||||
m_ui->btnStop->setEnabled(true);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-pause.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
case State::PS_PAUSE:
|
||||
m_ui->btnStop->setEnabled(true);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::stop()
|
||||
{
|
||||
onStop();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onInitDone()
|
||||
{
|
||||
m_state = State::PS_STOP;
|
||||
m_playTimer->start();
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation / building display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
|
||||
namespace FileManagement
|
||||
{
|
||||
namespace Database
|
||||
{
|
||||
struct FlmFileContent;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SituationReplay
|
||||
{
|
||||
class MainHandlerSqlite;
|
||||
}
|
||||
namespace LtsUtils
|
||||
{
|
||||
class QPoint3D;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SituationBuildingBase;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
enum class State
|
||||
{
|
||||
PS_UNDEFINED = 0,
|
||||
PS_STOP = 1,
|
||||
PS_PLAY = 2,
|
||||
PS_PAUSE = 3
|
||||
};
|
||||
constexpr int s_sliderMax = 1000; // 0 .. 1000
|
||||
|
||||
class SituationBuildingBase : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationBuildingBase(const char *loggerName,
|
||||
QWidget *parent = nullptr);
|
||||
~SituationBuildingBase();
|
||||
|
||||
bool init(SituationReplay::MainHandlerSqlite *replayHandler);
|
||||
bool showSituation(const QString &sitReplayDescription, const QString &basePath);
|
||||
|
||||
void updateButtons();
|
||||
bool stop();
|
||||
QString currentDTGTime() const;
|
||||
|
||||
protected:
|
||||
virtual bool showSituationInternal();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void setSpeed(double newSpeed);
|
||||
virtual void applyCurentFilter(const SituationReplay::FilterInformation &filter) = 0;
|
||||
virtual void applyNewOverlay(int overlayId) = 0;
|
||||
virtual void removeOverlay(int overlayId) = 0;
|
||||
void onSlower();
|
||||
void onFaster();
|
||||
void on100pct();
|
||||
void onPlay();
|
||||
void onStop();
|
||||
|
||||
void onSliderPressed();
|
||||
void onSliderPositionChanged(int newPosition);
|
||||
void onSliderReleased();
|
||||
void updateSpeedLabel();
|
||||
void onUpdateTimeSlider(qint64 curTime);
|
||||
void onCbPlaybackPartsChanged();
|
||||
void updatePositionLabel(const LtsUtils::QPoint3D &geoPos, bool isValid);
|
||||
virtual void updateZoomSlider() {}
|
||||
|
||||
virtual void onInitDone();
|
||||
virtual void emitPartitionTimeChanged(qint64 curTime) = 0;
|
||||
|
||||
virtual void onFileContentAvailable(const FileManagement::Database::FlmFileContent &) {}
|
||||
protected:
|
||||
QVector<SituationReplay::ReplayInformation> m_replayInformation;
|
||||
QVector<SituationReplay::FilterInformation> m_filterInformation;
|
||||
QVector<SituationReplay::FilterInformation> m_overlayInformation;
|
||||
QJsonObject m_attributes;
|
||||
QString m_scriptPath; // sitmap.json
|
||||
double m_speedVal = 1;
|
||||
State m_state = State::PS_STOP;
|
||||
QTimer *m_playTimer = nullptr;
|
||||
SituationReplay::MainHandlerSqlite *m_replayHandler = nullptr;
|
||||
|
||||
QString m_currentTimeDTGString;
|
||||
qint64 m_sliderMoveTime = 0;
|
||||
|
||||
Ui::SituationBuildingBase *m_ui;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SituationBuildingBase</class>
|
||||
<widget class="QFrame" name="SituationBuildingBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>911</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="vLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="THP::ZoomSlider" name="zoomSlider" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldPosition">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPosition">
|
||||
<property name="text">
|
||||
<string notr="true">--:-- / --:--</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-playback-start.png</normaloff>:icons/16x16/media-playback-start.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-playback-stop.png</normaloff>:icons/16x16/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnSlower">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-slower.png</normaloff>:icons/16x16/media-play-slower.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn100pct">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-normal.png</normaloff>:icons/16x16/media-play-normal.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFaster">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-faster.png</normaloff>:icons/16x16/media-play-faster.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSpeed">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">100 %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbPlaybackParts">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCursorPos">
|
||||
<property name="text">
|
||||
<string notr="true">MGRS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFilter">
|
||||
<property name="text">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>THP::ZoomSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>thpwidgets/thp_zoom_slider.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Aes/flt_aes_filter_widget.h>
|
||||
#include <ProjectDataManagement/Gui/PdmComboBox/pdm_combobox_foreign_gui_interface_impl.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterAes::SituatationFilterAes(const std::shared_ptr<FilterManagement::AesDisplayFilter> &aesFilter,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::AesFilterWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Area Effect Simulation filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::AesFilterWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterAes::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterAes::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::ForeignGuiInterfaceImpl>
|
||||
ifcPdmCbx(std::make_shared<ProjectDataManagement::ForeignGuiInterfaceImpl>());
|
||||
ifcPdmCbx->init(pluginProvider->pdmDtc());
|
||||
|
||||
m_filterWidget->init(ifcPpmCbx, ifcPdmCbx, aesFilter);
|
||||
// make sure to update ui when filter changes
|
||||
connect(m_filterWidget, &FilterManagement::AesFilterWidget::unknownChangesRecognized,
|
||||
m_filterWidget, &FilterManagement::AesFilterWidget::updateGuiToFilter);
|
||||
}
|
||||
|
||||
void SituatationFilterAes::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterAes::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class AesFilterWidget;
|
||||
class AesDisplayFilter;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterAes final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterAes(const std::shared_ptr<FilterManagement::AesDisplayFilter> &aesFilter,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::AesFilterWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_building_components.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/BuildingComponents/flt_building_component_settings_widget.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituationFilterBuildingComponent::SituationFilterBuildingComponent(const std::shared_ptr<FilterManagement::BuildingComponentSettings> &bcs,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::BuildingComponentSettingsWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Building / Component filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::BuildingComponentSettingsWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituationFilterBuildingComponent::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituationFilterBuildingComponent::reject);
|
||||
|
||||
m_filterWidget->init(bcs, pluginProvider->ismDtc());
|
||||
}
|
||||
|
||||
void SituationFilterBuildingComponent::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituationFilterBuildingComponent::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class BuildingComponentSettings;
|
||||
class BuildingComponentSettingsWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituationFilterBuildingComponent final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationFilterBuildingComponent(const std::shared_ptr<FilterManagement::BuildingComponentSettings> &bcs,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::BuildingComponentSettingsWidget *m_filterWidget{nullptr};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <AdvancedSymbology/Data/asb_foreign_interface_impl.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_collapse_expand_participants_widget.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterCollapseExpand::SituatationFilterCollapseExpand(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::CollapseExpandParticipantWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Collapse/Expand Participant filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::CollapseExpandParticipantWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterCollapseExpand::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterCollapseExpand::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
std::shared_ptr<AdvancedSymbology::ForeignInterfaceImpl>
|
||||
ifcAsb(std::make_shared<AdvancedSymbology::ForeignInterfaceImpl>(pluginProvider->ppmDtc(),
|
||||
pluginProvider->aesDtc(),
|
||||
pluginProvider->gimDtc()));
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc(),
|
||||
ifcPpmCbx,
|
||||
ifcAsb,
|
||||
// pluginProvider->fltParticipantIfc(),
|
||||
sas);
|
||||
}
|
||||
|
||||
void SituatationFilterCollapseExpand::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterCollapseExpand::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Collapse/Expand filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class CollapseExpandParticipantWidget;
|
||||
class SymbolAppearanceSettings;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterCollapseExpand final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterCollapseExpand(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::CollapseExpandParticipantWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_symbol_appearance_widget.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterSymbolAppearance::SituatationFilterSymbolAppearance(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::SymbolAppearanceWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Symbol Appearance filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::SymbolAppearanceWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterSymbolAppearance::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterSymbolAppearance::reject);
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc()->partys(), sas);
|
||||
}
|
||||
|
||||
void SituatationFilterSymbolAppearance::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterSymbolAppearance::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Symbol Appearance filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class SymbolAppearanceSettings;
|
||||
class SymbolAppearanceWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterSymbolAppearance final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterSymbolAppearance(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::SymbolAppearanceWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_types.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_type_filter_widget.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterTypes::SituatationFilterTypes(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::TypeFilterWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Type filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::TypeFilterWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterTypes::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterTypes::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc(),
|
||||
ifcPpmCbx,
|
||||
sas);
|
||||
}
|
||||
|
||||
void SituatationFilterTypes::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterTypes::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class SymbolAppearanceSettings;
|
||||
class TypeFilterWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterTypes final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterTypes(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::TypeFilterWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
+650
@@ -0,0 +1,650 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_widget.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
#include "thp_situation_filter_types.h"
|
||||
#include "thp_situation_filter_building_components.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <FileManagement/flm_db_structs.h>
|
||||
#include <FilterManagement/flt_participant_plugin_interface.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||||
#include <FilterManagement/flt_building_cmpnt_settings.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/aes_display_filter_impl.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/symbol_appearance_settings_impl.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
|
||||
#include <SituationMap/situation_map_init.h>
|
||||
#include <SituationMap/Utils/movement_track_manager.h>
|
||||
#include <SituationMap/Map/grid.h>
|
||||
#include <SituationMap/Map/point3D.h>
|
||||
#include <SituationMap/Map/map_initializer.h>
|
||||
#include <SituationMap/Map/map_notifier.h>
|
||||
#include <SituationMap/Map/operator_map_settings.h>
|
||||
#include <SituationMap/Map/overlay_handler.h>
|
||||
#include <SituationMap/Symbology/sidc_codec.h>
|
||||
#include <PlanOverlays/Gui/plan_overlay_model.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
class MySitMapIinit final : public SituationMap::SituationMapInit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using SituationMap::SituationMapInit::SituationMapInit;
|
||||
|
||||
bool trainingAreaExists() const override { return true; }
|
||||
SituationMap::MapSettingsJson getMapSettingsFromService() const override { return m_mapSettingsJson; }
|
||||
void setMapSettingsJson(const SituationMap::MapSettingsJson &settings) { m_mapSettingsJson = settings; }
|
||||
const SituationMap::MapSettingsJson & getMapSettingsJson() const { return m_mapSettingsJson; }
|
||||
|
||||
private:
|
||||
SituationMap::MapSettingsJson m_mapSettingsJson;
|
||||
};
|
||||
|
||||
using namespace SituationReplay;
|
||||
|
||||
SituationWidget::SituationWidget(QWidget *parent)
|
||||
: SituationBuildingBase("THP.SituationWidget", parent)
|
||||
, m_pluginProvider(new SitMapPluginProvider)
|
||||
, m_situationMapInit(new MySitMapIinit(nullptr))
|
||||
{
|
||||
QMenu *m = new QMenu(m_ui->btnFilter);
|
||||
m->addAction(tr("AES Filter"), this, &SituationWidget::onFilterAes);
|
||||
// 29.09.2022, Norbert Thoden
|
||||
// SWPÄ 2:22 GUEZE-1477 Kartenfilter für Komponenten:
|
||||
// Es wurde der Komponenten Filter eingeführt.
|
||||
// in der LiveLage werden allerdings nur MountingPoints angezeigt, die auch eine
|
||||
// zugeordnetes Asset haben. Die Zuordnug befindet sich in der Tabelle ism.sim_mounting_point_asset.
|
||||
// ism.sim_mounting_point_asset wird derzeit nicht in die sitreplay.sqlite
|
||||
// überführt. Es koennen also keine Komponenten angezeigt / gefiltert werden...
|
||||
// FilterDialog nicht anzeigen:
|
||||
// m->addAction(tr("Building / Component"), this, &SituationWidget::onFilterBuildingComponent);
|
||||
|
||||
m->addAction(tr("Symbol Appearance"), this, &SituationWidget::onFilterSymbolAppearance);
|
||||
m->addAction(tr("Collpase/Expand"), this, &SituationWidget::onFilterCollapseExpand);
|
||||
m->addAction(tr("Type filter"), this, &SituationWidget::onFilterTypes);
|
||||
m_ui->btnFilter->setMenu(m);
|
||||
}
|
||||
|
||||
SituationWidget::~SituationWidget()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStopReplayRequest();
|
||||
delete m_situationMapInit;
|
||||
delete m_pluginProvider;
|
||||
delete m_replayHandler;
|
||||
}
|
||||
|
||||
bool SituationWidget::init(const QString &homePath, int exerciseId)
|
||||
{
|
||||
m_pluginProvider->setExerciseId(exerciseId);
|
||||
delete m_replayHandler;
|
||||
m_replayHandler = new SituationReplay::MainHandlerSqlite;
|
||||
|
||||
if (!SituationBuildingBase::init(m_replayHandler))
|
||||
return false;
|
||||
|
||||
loadLayerMappings(homePath);
|
||||
|
||||
SituationReplay::ConnectionParams connParams;
|
||||
connParams.domainId = 1;
|
||||
connParams.partitionId = 1;
|
||||
if (!m_replayHandler->initDds(connParams))
|
||||
return false;
|
||||
|
||||
if (!m_pluginProvider->init(m_replayHandler->ddsReplay()))
|
||||
return false;
|
||||
if (!m_situationMapInit->initPluginProvider(m_pluginProvider))
|
||||
return false;
|
||||
|
||||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||||
|
||||
FATAL_LOG(m_logger) << LOGFUNCTION << " XXXX initMap....";
|
||||
|
||||
if (!m_situationMapInit->initMap(false, SituationMap::Mode::Mode_2D))
|
||||
return false;
|
||||
|
||||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||||
return false;
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||||
this, &SituationWidget::updatePositionLabel,
|
||||
Qt::UniqueConnection);
|
||||
connect(map, &SituationMap::Map::extentChanged,
|
||||
this, &SituationWidget::updateZoomSlider);
|
||||
|
||||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, map);
|
||||
|
||||
m_aesDisplayFilter = m_pluginProvider->fltAesIfc()->aesFilterForOperator(0, QString());
|
||||
m_symbolAppaearanceSettings = m_pluginProvider->fltParticipantIfc()->symbolAppearanceForOperator(0, QString());
|
||||
m_buildingComponentSettings = m_pluginProvider->fltBuildingComponentIfc()->buildingComponentSettingsForOperator(0, QString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationWidget::showSituationInternal()
|
||||
{
|
||||
// cleanup 'old' map:
|
||||
// remove old overlays from former session:
|
||||
{
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map)
|
||||
map->overlayHandler().removeAllOverlays();
|
||||
}
|
||||
|
||||
|
||||
m_ui->cbPlaybackParts->setVisible(m_replayInformation.size() > 1);
|
||||
|
||||
// MAYBE there are filter to be applied:
|
||||
applyFilterFromReplayConfigFile();
|
||||
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString sqliteDb = m_replayInformation.first().databaseFilePath;
|
||||
if (sqliteDb.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No database given...";
|
||||
return false;
|
||||
}
|
||||
QFileInfo fi(sqliteDb);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
WARNING_LOG(m_logger) << "Can not access sqlite database '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ui->cbPlaybackParts->clear();
|
||||
m_ui->cbPlaybackParts->blockSignals(true);
|
||||
for (int i = 0; i < m_replayInformation.size(); ++i)
|
||||
{
|
||||
const ReplayInformation &info = m_replayInformation.at(i);
|
||||
m_ui->cbPlaybackParts->addItem(QStringLiteral("%1: %2 - %3").arg(i+1).arg(DTG::toStringMSec(info.timeSpan.begin, DTG::Long),
|
||||
DTG::toStringMSec(info.timeSpan.end, DTG::Long)), i);
|
||||
}
|
||||
m_ui->cbPlaybackParts->setCurrentIndex(0);
|
||||
m_ui->cbPlaybackParts->blockSignals(false);
|
||||
onCbPlaybackPartsChanged(); // creates replayHandler for correct db etc.
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map->isReady())
|
||||
QTimer::singleShot(0, this, &SituationWidget::onInitDone);
|
||||
else
|
||||
connect(map, &SituationMap::Map::mapReady,
|
||||
this, &SituationWidget::onInitDone, Qt::QueuedConnection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationWidget::applyFilterFromReplayConfigFile()
|
||||
{
|
||||
// Maybe the Situation topic has own Filter (AesFilter, SymbolAppearance; OperatorMapSettings)
|
||||
// Read and apply them:
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString replayConfigFile = m_replayInformation.first().replayConfigPath; // sitreplay.json
|
||||
if (replayConfigFile.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replayConfigFile given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi(replayConfigFile);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not access replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile f(replayConfigFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open replayConfigFile '" << fi.absoluteFilePath() << "': " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonParseError jError;
|
||||
const QByteArray ba = f.readAll();
|
||||
QJsonDocument doc(QJsonDocument::fromJson(ba, &jError));
|
||||
if (jError.error)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: "
|
||||
<< ", replayConfigFile '" << fi.absoluteFilePath() << "'"
|
||||
<< ", errorString= " << jError.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
const QJsonObject &rootObj = doc.object();
|
||||
const QJsonObject &filters = rootObj[QStringLiteral("filters")].toObject(); // optional!!!
|
||||
|
||||
if (filters.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "no 'filters' provided at "
|
||||
<< " replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " XXXX replayConfigFile='" << fi.absoluteFilePath() << "'"
|
||||
<< " doc.toJson = " << doc.toJson();
|
||||
|
||||
// fine, put together
|
||||
FilterInformation filterInfo;
|
||||
filterInfo.aesFilters = filters[QStringLiteral("AesFilterJson")].toObject();
|
||||
filterInfo.symbolSettings = filters[QStringLiteral("SymbolAppearanceJson")].toObject();
|
||||
filterInfo.buildingComponentSettings = filters[QStringLiteral("BuildingComponentSettingsJson")].toObject();
|
||||
|
||||
filterInfo.mapSettings = rootObj[QStringLiteral("settings")].toObject();
|
||||
|
||||
applyCurentFilter(filterInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationWidget::applyCurentFilter(const SituationReplay::FilterInformation &filter)
|
||||
{
|
||||
m_aesDisplayFilter->setFilterFromData(filter.aesFilters);
|
||||
m_symbolAppaearanceSettings->setSettings(filter.symbolSettings, FilterManagement::SymbolAppearanceSettings::Part::All);
|
||||
m_buildingComponentSettings->setBldCmpSettings(filter.buildingComponentSettings);
|
||||
|
||||
SituationMap::OperatorMapSettings oms;
|
||||
oms.fromJsonObject(filter.mapSettings);
|
||||
if (oms.isEmpty() || oms.mode == SituationMap::Mode::Undefined)
|
||||
return;
|
||||
|
||||
|
||||
if (oms.mode != m_situationMapInit->getWidget()->mode())
|
||||
{
|
||||
INFO_LOG(m_logger) << " Switching to new mode : " << oms.mode;
|
||||
|
||||
SituationMap::MapSettingsJson savedMapSettingsJson;
|
||||
if (m_situationMapInit)
|
||||
{
|
||||
savedMapSettingsJson = m_situationMapInit->getMapSettingsJson(); // containing path from layerMappping.json
|
||||
m_situationMapInit->stopDisplay();
|
||||
m_situationMapInit->clearObjects();
|
||||
}
|
||||
delete m_situationMapInit;
|
||||
m_situationMapInit = new MySitMapIinit(nullptr);
|
||||
m_situationMapInit->setMapSettingsJson(savedMapSettingsJson);
|
||||
m_situationMapInit->initPluginProvider(m_pluginProvider);
|
||||
|
||||
m_situationMapInit->initMap(false, oms.mode);
|
||||
|
||||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||||
return;
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map)
|
||||
{
|
||||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||||
this, &SituationWidget::updatePositionLabel,
|
||||
Qt::UniqueConnection);
|
||||
connect(map, &SituationMap::Map::extentChanged,
|
||||
this, &SituationWidget::updateZoomSlider);
|
||||
|
||||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, map);
|
||||
|
||||
|
||||
static bool s_waitFlag = true;
|
||||
|
||||
QPointer<SituationMap::MapNotifier> mapNotifier = map->createMapNotifier();
|
||||
if (mapNotifier)
|
||||
{
|
||||
connect(mapNotifier.data(), &SituationMap::MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this, oms]()
|
||||
{
|
||||
s_waitFlag = false;
|
||||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||||
|
||||
});
|
||||
mapNotifier->run();
|
||||
|
||||
// snyc wait :-(
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC BEGIN";
|
||||
int i=0;
|
||||
while(i<100 && s_waitFlag) // 100 * 50ms = 5000ms
|
||||
{
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers, 50);
|
||||
QThread::msleep(50);
|
||||
++i;
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC ..., i=" << i;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC ...DONE, i=" << i;
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC, m_situationMapInit->getWidget()->mode()" << m_situationMapInit->getWidget()->mode();
|
||||
m_situationMapInit->startDisplay();
|
||||
}
|
||||
} // if (mapNotifier)
|
||||
}
|
||||
} else {
|
||||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||||
}
|
||||
}
|
||||
|
||||
bool SituationWidget::restoreOperatorMapSettingsOverlays(const SituationMap::OperatorMapSettings &oms)
|
||||
{
|
||||
if (!m_situationMapInit || !m_situationMapInit->getWidget() || oms.isEmpty())
|
||||
return false;
|
||||
|
||||
if (!m_situationMapInit->getWidget()->restoreOperatorMapSettings(oms))
|
||||
WARNING_LOG(m_logger) << LOGFUNCTION << " restoreOperatorMapSettings failed";
|
||||
|
||||
// continue!!! maybe just LayerOrder failed.... ToDo
|
||||
|
||||
// 2. handle Overlays :
|
||||
// SituationMap can`t restore the overlays on it´s own:
|
||||
// So we have to do it here:
|
||||
const QList<int> &orderedOverlayIds = oms.orderedOverlays;
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " restore OverlayIds...";
|
||||
for (auto overlayId : qAsConst(orderedOverlayIds))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " applyNewOverlay , overlayId=" << overlayId;
|
||||
applyNewOverlay(overlayId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationWidget::applyNewOverlay(int overlayId)
|
||||
{
|
||||
const QString filename = QStringLiteral("%1/%2.TacticalPlan").arg(m_scriptPath).arg(overlayId);
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open tactical plan '" << filename << "': " << f.errorString();
|
||||
return;
|
||||
}
|
||||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||||
if (!overlayHandler.setOverlay(overlayId, tr("Plan '%1'").arg(overlayId), f.readAll(), false))
|
||||
WARNING_LOG(m_logger) << "can not display overlay " << filename;
|
||||
|
||||
}
|
||||
|
||||
void SituationWidget::removeOverlay(int overlayId)
|
||||
{
|
||||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||||
overlayHandler.removeOverlay(overlayId);
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterAes()
|
||||
{
|
||||
if (!m_filterAesDialog)
|
||||
m_filterAesDialog = new SituatationFilterAes(m_aesDisplayFilter,
|
||||
m_pluginProvider, this);
|
||||
m_filterAesDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterSymbolAppearance()
|
||||
{
|
||||
if (!m_filterSymbolAppearanceDialog)
|
||||
m_filterSymbolAppearanceDialog = new SituatationFilterSymbolAppearance(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterSymbolAppearanceDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterCollapseExpand()
|
||||
{
|
||||
if (!m_filterCollapseExpandDialog)
|
||||
m_filterCollapseExpandDialog = new SituatationFilterCollapseExpand(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterCollapseExpandDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterTypes()
|
||||
{
|
||||
if (!m_filterTypesDialog)
|
||||
m_filterTypesDialog = new SituatationFilterTypes(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterTypesDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterBuildingComponent()
|
||||
{
|
||||
if (!m_filterBuildingComponentDialog)
|
||||
m_filterBuildingComponentDialog = new SituationFilterBuildingComponent(m_buildingComponentSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterBuildingComponentDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::emitPartitionTimeChanged(qint64 curTime)
|
||||
{
|
||||
m_pluginProvider->emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void SituationWidget::updateZoomSlider()
|
||||
{
|
||||
// this is not really what we want to display... but currently we hide the slider anyway
|
||||
m_ui->zoomSlider->setZoomValue(m_situationMapInit->getWidget()->scale() / 1000);
|
||||
}
|
||||
|
||||
|
||||
QString SituationWidget::centerPointString() const
|
||||
{
|
||||
const QPointF center = m_situationMapInit->getWidget()->centerPoint();
|
||||
LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(center.x(), center.y()));
|
||||
return coord.mgrs();
|
||||
}
|
||||
|
||||
QRectF SituationWidget::extentMgrs() const
|
||||
{
|
||||
const QRectF r = m_situationMapInit->getWidget()->extent();
|
||||
LtsCoordTrans::UtmCoordinate topLeft(LtsCoordTrans::UtmCoordinate::fromGeographic(r.left(), r.top()));
|
||||
LtsCoordTrans::UtmCoordinate bottomRight(LtsCoordTrans::UtmCoordinate::fromGeographic(r.right(), r.bottom(), topLeft.zone));
|
||||
return QRectF(QPointF(topLeft.x, topLeft.y), QPointF(bottomRight.x, bottomRight.y));
|
||||
}
|
||||
|
||||
QImage SituationWidget::grabFrameBuffer() const
|
||||
{
|
||||
return m_situationMapInit->getWidget()->grab().toImage();
|
||||
}
|
||||
|
||||
void SituationWidget::onInitDone()
|
||||
{
|
||||
SituationBuildingBase::onInitDone();
|
||||
m_situationMapInit->startDisplay();
|
||||
}
|
||||
|
||||
void SituationWidget::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_F10:
|
||||
onMgrsGrid();
|
||||
break;
|
||||
case Qt::Key_PageUp:
|
||||
onRotate(10);
|
||||
break;
|
||||
case Qt::Key_PageDown:
|
||||
onRotate(-10);
|
||||
break;
|
||||
default:
|
||||
QFrame::keyPressEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SituationWidget::onMgrsGrid()
|
||||
{
|
||||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||||
m->grid().setVisible(!m->grid().isVisible());
|
||||
}
|
||||
|
||||
void SituationWidget::onRotate(int degrees)
|
||||
{
|
||||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||||
m->setRotation(m->rotation() + degrees);
|
||||
}
|
||||
|
||||
void SituationWidget::onFileContentAvailable(const FileManagement::Database::FlmFileContent &data)
|
||||
{
|
||||
if (data.fileTypeId != FileManagement::FileType::OperatorDefinedSymbol ||
|
||||
data.fileStatusId != FileManagement::FileStatus::Valid ||
|
||||
data.content.size() == 0)
|
||||
return;
|
||||
|
||||
QColor colorToBeReplaced;
|
||||
bool bIsXml = false;
|
||||
|
||||
if (!data.properties.isEmpty())
|
||||
{
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument jDoc(QJsonDocument::fromJson(data.properties.toUtf8(), &parseError));
|
||||
const QJsonObject obj(jDoc.object());
|
||||
const QLatin1String imageFormatKey("imageFormat");
|
||||
bIsXml = obj.value(imageFormatKey).toString() == QLatin1String("xml");
|
||||
if (!bIsXml)
|
||||
{
|
||||
// partyColor
|
||||
const QLatin1String partyColorStr("partyColor");
|
||||
if (obj.contains(partyColorStr))
|
||||
{
|
||||
const QJsonObject partyColor = obj[partyColorStr].toObject();
|
||||
if (partyColor.size() == 3) // r, g, b
|
||||
{
|
||||
// update map:
|
||||
colorToBeReplaced.setRgb(
|
||||
partyColor[QLatin1String("r")].toInt(),
|
||||
partyColor[QLatin1String("g")].toInt(),
|
||||
partyColor[QLatin1String("b")].toInt());
|
||||
} // if (partyColor.size() == 3)
|
||||
} // if (obj.contains(partyColorStr))
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedSymbology::SymbologyType symType = AdvancedSymbology::SymbolDictionary::defaultSymbologyType();
|
||||
AdvancedSymbology::SymbolDictionary &dict =
|
||||
AdvancedSymbology::SymbolDictionary::dictionary(symType);
|
||||
if (bIsXml)
|
||||
{
|
||||
dict.setXmlSymbol(data.id, data.name, QStringLiteral("OperatorName"), 0, QString::fromUtf8(data.content), AdvancedSymbology::SymbolProperties());
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage image;
|
||||
QSvgRenderer svgRenderer;
|
||||
if (!svgRenderer.load(data.content))
|
||||
return;
|
||||
|
||||
// prepare Image:
|
||||
constexpr int size = 200; // pixel
|
||||
QImage imageOut(size, size, QImage::Format_ARGB32);
|
||||
imageOut.fill(Qt::transparent);
|
||||
|
||||
// render
|
||||
QPainter painter(&imageOut);
|
||||
svgRenderer.render(&painter);
|
||||
painter.end();
|
||||
|
||||
AdvancedSymbology::SymbolProperties symProps;
|
||||
symProps.setKey(data.name);
|
||||
symProps.setSidc(AdvancedSymbology::SidcCodec::encodeCivilEts(data.name));
|
||||
symProps.setName(data.name);
|
||||
symProps.setSymbolClass(QLatin1String("3")); // 18.10.2016, N.Thoden: 3 == PointSymbol (mil2525d.stylx - QuartzRelease)
|
||||
symProps.setGeometryType(AdvancedSymbology::GeometryType::Point); // ETS-Symbols are always Points
|
||||
symProps.setTags({data.name});
|
||||
symProps.setColorToBeReplaced(colorToBeReplaced);
|
||||
|
||||
dict.setEtsSymbol(data.id, data.name, symProps, image);
|
||||
}
|
||||
}
|
||||
|
||||
void SituationWidget::loadLayerMappings(const QString &homePath)
|
||||
{
|
||||
const QString mappingsFile = homePath + QStringLiteral("/layerMapping.json");
|
||||
|
||||
QFile f(mappingsFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
fprintf(stderr, "Could not load layer mappings from '%s' - %s\n", mappingsFile.toStdString().c_str(), f.errorString().toStdString().c_str());
|
||||
WARNING_LOG(m_logger) << "Could not load layer mappings from " << mappingsFile << ": " << f.errorString();
|
||||
return;
|
||||
}
|
||||
m_layerMapping.clear();
|
||||
const QJsonObject obj = QJsonDocument::fromJson(f.readAll()).object();
|
||||
|
||||
SituationMap::MapSettingsJson settings;
|
||||
if (!settings.fromJsonObject(obj))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not parse layer mappings from " << mappingsFile;
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setMapUrls(fixupUrls(settings.getMapUrls(), homePath));
|
||||
settings.setSceneUrls(fixupUrls(settings.getSceneUrls(), homePath));
|
||||
settings.setSceneObjectUrls(fixupUrls(settings.getSceneObjectUrls(), homePath));
|
||||
settings.setElevationUrls(fixupUrls(settings.getElevationUrls(), homePath));
|
||||
|
||||
m_situationMapInit->setMapSettingsJson(settings);
|
||||
}
|
||||
|
||||
QVector<SituationMap::BaseUrl> SituationWidget::fixupUrls(const QVector<SituationMap::BaseUrl> &in,
|
||||
const QString &homePath)
|
||||
{
|
||||
QVector<SituationMap::BaseUrl> out;
|
||||
for (auto url : in)
|
||||
{
|
||||
const QString fn = QStringLiteral("%1/Maps/%2").arg(homePath, url.url());
|
||||
if (!QFile::exists(fn))
|
||||
{
|
||||
fprintf(stderr, "Can not find map data file '%s'\n", fn.toStdString().c_str());
|
||||
QMessageBox::warning(this, tr("Can not find map data"),
|
||||
tr("Can not find map data file '%1' - can't start application").arg(fn));
|
||||
QCoreApplication::quit();
|
||||
return out;
|
||||
}
|
||||
url.setUrl(QUrl::fromLocalFile(fn).toString());
|
||||
out.push_back(std::move(url));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
#include "thp_situation_widget.moc"
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
#include "thp_situation_building_base.h"
|
||||
|
||||
namespace SituationReplay
|
||||
{
|
||||
class HandlerSituationReplaySqlite;
|
||||
}
|
||||
namespace SituationMap
|
||||
{
|
||||
class BaseUrl;
|
||||
struct OperatorMapSettings;
|
||||
}
|
||||
namespace FilterManagement
|
||||
{
|
||||
class AesDisplayFilter;
|
||||
class SymbolAppearanceSettings;
|
||||
class BuildingComponentSettings;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SituationWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterAes;
|
||||
class SituatationFilterSymbolAppearance;
|
||||
class SituatationFilterCollapseExpand;
|
||||
class SituatationFilterTypes;
|
||||
class SituationFilterBuildingComponent;
|
||||
class MySitMapIinit;
|
||||
|
||||
class SituationWidget : public SituationBuildingBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationWidget(QWidget *parent = nullptr);
|
||||
~SituationWidget();
|
||||
|
||||
bool init(const QString &homePath, int exerciseId);
|
||||
|
||||
SituationReplay::MainHandlerSqlite *replayHandler() { return m_replayHandler; }
|
||||
SitMapPluginProvider *pluginProvider() { return m_pluginProvider; }
|
||||
|
||||
|
||||
QImage grabFrameBuffer() const;
|
||||
QString centerPointString() const;
|
||||
QRectF extentMgrs() const; // mgrs
|
||||
|
||||
protected:
|
||||
bool showSituationInternal() override;
|
||||
bool applyFilterFromReplayConfigFile();
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void loadLayerMappings(const QString &homePath);
|
||||
QVector<SituationMap::BaseUrl> fixupUrls(const QVector<SituationMap::BaseUrl> &in,
|
||||
const QString &homePath);
|
||||
|
||||
bool restoreOperatorMapSettingsOverlays(const SituationMap::OperatorMapSettings &oms);
|
||||
|
||||
private Q_SLOTS:
|
||||
void applyCurentFilter(const SituationReplay::FilterInformation &filter) override;
|
||||
void applyNewOverlay(int overlayId) override;
|
||||
void removeOverlay(int overlayId) override;
|
||||
|
||||
void onFilterAes();
|
||||
void onFilterSymbolAppearance();
|
||||
void onFilterCollapseExpand();
|
||||
void onFilterTypes();
|
||||
void onFilterBuildingComponent();
|
||||
|
||||
void updateZoomSlider() override;
|
||||
|
||||
void onInitDone() override;
|
||||
void emitPartitionTimeChanged(qint64 curTime) override;
|
||||
void onMgrsGrid();
|
||||
void onRotate(int degrees);
|
||||
|
||||
void onFileContentAvailable(const FileManagement::Database::FlmFileContent &data) override;
|
||||
private:
|
||||
QVector<QPair<QString, QString>> m_layerMapping;
|
||||
|
||||
SitMapPluginProvider *m_pluginProvider{nullptr};
|
||||
MySitMapIinit *m_situationMapInit{nullptr};
|
||||
SituatationFilterAes *m_filterAesDialog{nullptr};
|
||||
SituatationFilterSymbolAppearance *m_filterSymbolAppearanceDialog{nullptr};
|
||||
SituatationFilterCollapseExpand *m_filterCollapseExpandDialog{nullptr};
|
||||
SituatationFilterTypes *m_filterTypesDialog{nullptr};
|
||||
SituationFilterBuildingComponent *m_filterBuildingComponentDialog{nullptr};
|
||||
|
||||
std::shared_ptr<FilterManagement::AesDisplayFilter> m_aesDisplayFilter;
|
||||
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> m_symbolAppaearanceSettings;
|
||||
std::shared_ptr<FilterManagement::BuildingComponentSettings> m_buildingComponentSettings;
|
||||
|
||||
};
|
||||
} // namespace THP
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* A special slider for zooming
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_zoom_slider.h"
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
ZoomSlider::ZoomSlider(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_InternalMin(0.1)
|
||||
, m_InternalMax(100)
|
||||
, m_LowerThreshold(1)
|
||||
, m_UpperThreshold(10)
|
||||
, m_MinRange(0)
|
||||
, m_MaxRange(280)
|
||||
, m_Slider(nullptr)
|
||||
, m_lbl(nullptr)
|
||||
, m_text(nullptr)
|
||||
, m_ZoomValue(-1)
|
||||
, m_curSliderVal(-1)
|
||||
{
|
||||
setShowDescriptionLabel(true);
|
||||
setShowValueLabel(true);
|
||||
m_Slider = new QSlider(this);
|
||||
|
||||
connect(m_Slider, &QSlider::valueChanged, this, &ZoomSlider::calcZoomFromSlider);
|
||||
connect(this, &ZoomSlider::valueChanged, this, &ZoomSlider::updateLabel);
|
||||
|
||||
m_Slider->setRange(m_MinRange, m_MaxRange);
|
||||
m_Slider->setSingleStep(1);
|
||||
m_Slider->setPageStep(1);
|
||||
|
||||
setOrientation(Qt::Horizontal);
|
||||
//Initial calculation
|
||||
calcZoomFromSlider(m_Slider->value());
|
||||
|
||||
}
|
||||
|
||||
void ZoomSlider::setZoomValue(double zoomValue)
|
||||
{
|
||||
if (qFuzzyCompare(m_ZoomValue, zoomValue))
|
||||
return;
|
||||
//ignore values outside Min/Max boundaries.
|
||||
if (zoomValue < m_InternalMin || zoomValue > m_InternalMax)
|
||||
return;
|
||||
m_ZoomValue = zoomValue;
|
||||
|
||||
if (zoomValue < m_LowerThreshold)
|
||||
{
|
||||
//Range is 0..50%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 2;
|
||||
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_LowerThreshold - m_InternalMin) * (zoomValue - m_InternalMin);
|
||||
//qDebug() << "Value1 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
else if (zoomValue < m_UpperThreshold)
|
||||
{
|
||||
//Range is 50%..75%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_UpperThreshold - m_LowerThreshold) * (zoomValue - m_LowerThreshold);
|
||||
l_ValToSet += l_Range * 2;
|
||||
//qDebug() << "Value2 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Range is 75%..100%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_InternalMax - m_UpperThreshold) * (zoomValue - m_UpperThreshold);
|
||||
l_ValToSet += l_Range * 3;
|
||||
//qDebug() << "Value3 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
m_Slider->setValue(m_curSliderVal);
|
||||
updateLabel(m_ZoomValue);
|
||||
}
|
||||
|
||||
double ZoomSlider::getZoomValue() const
|
||||
{
|
||||
return m_ZoomValue;
|
||||
}
|
||||
|
||||
void ZoomSlider::setOrientation(Qt::Orientation a_orientation)
|
||||
{
|
||||
if (!m_Slider)
|
||||
return;
|
||||
|
||||
m_Slider->setOrientation(a_orientation);
|
||||
QBoxLayout *l_Layout;
|
||||
if (a_orientation == Qt::Horizontal)
|
||||
{
|
||||
m_Slider->setMinimumWidth(40);
|
||||
m_Slider->setMinimumHeight(0);
|
||||
l_Layout = new QHBoxLayout;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Slider->setMinimumWidth(0);
|
||||
m_Slider->setMinimumHeight(40);
|
||||
l_Layout = new QVBoxLayout;
|
||||
}
|
||||
l_Layout->setContentsMargins(0, 0, 0, 0);
|
||||
if (m_text)
|
||||
l_Layout->addWidget(m_text);
|
||||
if (m_Slider)
|
||||
l_Layout->addWidget(m_Slider);
|
||||
if (m_lbl)
|
||||
l_Layout->addWidget(m_lbl);
|
||||
delete layout();
|
||||
setLayout(l_Layout);
|
||||
}
|
||||
|
||||
Qt::Orientation ZoomSlider::getOrientation() const
|
||||
{
|
||||
if (m_Slider)
|
||||
return m_Slider->orientation();
|
||||
return Qt::Horizontal;
|
||||
}
|
||||
|
||||
bool ZoomSlider::getShowDescriptionLabel() const
|
||||
{
|
||||
return (m_text != nullptr);
|
||||
}
|
||||
|
||||
void ZoomSlider::setShowDescriptionLabel(bool bVisible)
|
||||
{
|
||||
if (getShowDescriptionLabel() == bVisible)
|
||||
return;
|
||||
if (bVisible)
|
||||
{
|
||||
m_text = new QLabel(this);
|
||||
m_text->setText(tr("Zoom:"));
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_text;
|
||||
m_text = nullptr;
|
||||
}
|
||||
setOrientation(getOrientation());
|
||||
}
|
||||
|
||||
bool ZoomSlider::getShowValueLabel() const
|
||||
{
|
||||
return (m_lbl != nullptr);
|
||||
}
|
||||
|
||||
void ZoomSlider::setShowValueLabel(bool bVisible)
|
||||
{
|
||||
if (getShowValueLabel() == bVisible)
|
||||
return;
|
||||
if (bVisible)
|
||||
m_lbl = new QLabel(this);
|
||||
else
|
||||
{
|
||||
delete m_lbl;
|
||||
m_lbl = nullptr;
|
||||
}
|
||||
setOrientation(getOrientation());
|
||||
updateLabel(m_ZoomValue);
|
||||
}
|
||||
|
||||
|
||||
void ZoomSlider::calcZoomFromSlider(int a_value)
|
||||
{
|
||||
if (m_curSliderVal == a_value)
|
||||
return;
|
||||
m_curSliderVal = a_value;
|
||||
|
||||
if (a_value < (m_MaxRange - m_MinRange) / 2)
|
||||
{
|
||||
//Range 0% - 50%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 2;
|
||||
double l_R2 = (m_LowerThreshold - m_InternalMin);
|
||||
double l_ValToSet = l_R2 / l_R1 * a_value;
|
||||
l_ValToSet += m_InternalMin;
|
||||
//qDebug() << "Value4 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
else if (a_value < 3 * (m_MaxRange - m_MinRange) / 4)
|
||||
{
|
||||
//Range 50% - 75%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_R2 = (m_UpperThreshold - m_LowerThreshold);
|
||||
double l_SliderVal = a_value - (m_MaxRange - m_MinRange) / 2;
|
||||
double l_ValToSet = l_R2 / l_R1 * l_SliderVal;
|
||||
l_ValToSet += static_cast<double>(m_LowerThreshold);
|
||||
//qDebug() << "Value5 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Range 75% - 100%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_R2 = (m_InternalMax - m_UpperThreshold);
|
||||
double l_SliderVal = a_value - (m_MaxRange - m_MinRange) / 4 * 3;
|
||||
double l_ValToSet = l_R2 / l_R1 * l_SliderVal;
|
||||
|
||||
l_ValToSet += static_cast<double>(m_UpperThreshold);
|
||||
//qDebug() << "Value6 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
emit valueChanged(m_ZoomValue);
|
||||
}
|
||||
|
||||
void ZoomSlider::updateLabel(double newValue)
|
||||
{
|
||||
if (!m_lbl)
|
||||
return;
|
||||
m_lbl->setText(formatValue(newValue));
|
||||
}
|
||||
|
||||
QString ZoomSlider::formatValue(double value) const
|
||||
{
|
||||
if (value < m_LowerThreshold)
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 2);
|
||||
if (value < m_UpperThreshold)
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 1);
|
||||
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 0);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* A special slider for zooming
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QSlider;
|
||||
|
||||
namespace THP
|
||||
{
|
||||
/**
|
||||
* An specialized QSlider
|
||||
* This slider has a special, fixed range from 0.1 - 100 which is mapped to
|
||||
* suitable map scales used in the GUEZ.
|
||||
* The scale is not linear - instead it has a model behind. in smaller scales -
|
||||
* slider's going to 0.1 - it's resolution is finer than on larger scales -
|
||||
* slider's going to 100.
|
||||
* The slider accpets only values within the range 0.1....100. Other values are ignored.
|
||||
*/
|
||||
class ZoomSlider : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Qt::Orientation Orientation READ getOrientation WRITE setOrientation)
|
||||
Q_PROPERTY(bool showDescriptionLabel READ getShowDescriptionLabel WRITE setShowDescriptionLabel)
|
||||
Q_PROPERTY(bool showValueLabel READ getShowValueLabel WRITE setShowValueLabel)
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
explicit ZoomSlider(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* get the actual Zoom value.
|
||||
* @return float with the zoom value
|
||||
*/
|
||||
double getZoomValue() const;
|
||||
|
||||
/**
|
||||
* Sets the Orientation.
|
||||
* @param a_orientation The slider's orientation.
|
||||
*/
|
||||
void setOrientation(Qt::Orientation a_orientation);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Qt::Orientation getOrientation() const;
|
||||
|
||||
bool getShowDescriptionLabel() const;
|
||||
void setShowDescriptionLabel(bool bVisible);
|
||||
|
||||
bool getShowValueLabel() const;
|
||||
void setShowValueLabel(bool bVisible);
|
||||
|
||||
/**
|
||||
* format the given value as it would be shown in the zoom label
|
||||
*/
|
||||
QString formatValue(double value) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* set the slider's actual zoom value. This is a QT-Slot.
|
||||
* The slider accpet only values within it's range 0.1...100.
|
||||
* Other values are ignored.
|
||||
* @param a_zoomValue the new zoom value.
|
||||
*/
|
||||
void setZoomValue(double zoomValue);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A QT-Signal which is emitted whenever the slider's value has changed.
|
||||
* The newly set zoom value is delivered as argument.
|
||||
*/
|
||||
void valueChanged(double a_value);
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* Update the label text
|
||||
*/
|
||||
void updateLabel(double newValue);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Contains the slider's minimum zoom value
|
||||
*/
|
||||
const double m_InternalMin;
|
||||
/**
|
||||
* Contains the slider's maximum zoom value
|
||||
*/
|
||||
const double m_InternalMax;
|
||||
/**
|
||||
* Contains the slider's lower threshold value.
|
||||
* The lower threshold is at 50% of the sliders range.
|
||||
*/
|
||||
const int m_LowerThreshold;
|
||||
/**
|
||||
* Contains the slider's upper threshold value.
|
||||
* The upper threshold is at 75% of the sliders range.
|
||||
*/
|
||||
const int m_UpperThreshold;
|
||||
/**
|
||||
* Contains the slider's range minimum value
|
||||
*/
|
||||
const int m_MinRange;
|
||||
/**
|
||||
* Contains the slider's range maximum value
|
||||
*/
|
||||
const int m_MaxRange;
|
||||
|
||||
/**
|
||||
* The QSlider
|
||||
*/
|
||||
QSlider *m_Slider;
|
||||
|
||||
/**
|
||||
* The label for showing the exact slider value.
|
||||
*/
|
||||
QLabel *m_lbl;
|
||||
|
||||
/**
|
||||
* The label for showing the 'zoom' text
|
||||
*/
|
||||
QLabel *m_text;
|
||||
|
||||
/**
|
||||
* contains the zoom value
|
||||
*/
|
||||
double m_ZoomValue;
|
||||
|
||||
/**
|
||||
* The current value of the slider to avoid loops
|
||||
*/
|
||||
int m_curSliderVal;
|
||||
|
||||
private slots :
|
||||
/**
|
||||
* Calculates the zoom value from the slider's position
|
||||
*/
|
||||
void calcZoomFromSlider(int a_value);
|
||||
|
||||
};
|
||||
} // namespace THP
|
||||
Reference in new issue
Block a user