Files
qt5-legatus-legacy/Lts/Application/THP/thp_viewer.cpp
T
2026-08-13 18:33:10 +02:00

687 lines
23 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Main thp viewer widget
* $Id$
* $HeadURL$
* $Author$
*/
#include "thp_viewer.h"
#include "ui_thp_viewer.h"
#include "thp_plugin_provider.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QKeyEvent>
#include <QPrintDialog>
#include <QPrinter>
#include <QPainter>
#include <QMessageBox>
#include <QTextDocument>
#include <QScreen>
#include <QDesktopServices>
#include <QDomElement>
#include <QDomDocument>
#include <QUrl>
#include <QRect>
#include <QSize>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QSettings>
#include <QInputDialog>
#include <QDir>
#include <ngltranslator/ngltranslator.h>
#include <ngltools/ngltools_dtg.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace NGL
{
/*
* ThpViewer base class
*/
ThpViewer::ThpViewer(const QUrl &url, QWidget *parent)
: QWidget(parent)
, ui(new Ui::thpViewer)
, m_scaleFactor(1.0)
, m_homeLink(url)
, m_homePath(QFileInfo(m_homeLink.toLocalFile()).absolutePath())
, m_trainingName(QString())
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("ThpViewer"))
{
ui->setupUi(this);
ui->audioWidget->setAV(true);
ui->videoWidget->setAV(false);
/*
TODO
if (!conffile.isEmpty())
{
QSettings thpsettings(conffile, QSettings::IniFormat, this);
// needed?
const char timeZone = thpsettings.value(QStringLiteral("Time/Timezone"), QStringLiteral("Z")).toString().at(0).toLatin1();
DTG::setTimezone(timeZone, true);
}
*/
QString basedir(url.toLocalFile());
basedir = basedir.left(basedir.lastIndexOf(QLatin1Char('/')));
DEBUG_LOG(m_logger) << "url: " << url.toString() << " basedir: " << basedir;
QFont f = ui->mainLabel->font();
f.setBold(true);
f.setPointSizeF(f.pointSizeF() * 1.2);
ui->mainLabel->setFont(f);
connect(ui->closeButton, &QToolButton::clicked, this, &ThpViewer::close);
connect(ui->backButton, &QToolButton::clicked, this, &ThpViewer::onBack);
connect(ui->homeButton, &QToolButton::clicked, this, &ThpViewer::onHome);
connect(ui->helpButton, &QToolButton::clicked, this, &ThpViewer::onHelp);
connect(ui->printButton, &QToolButton::clicked, this, &ThpViewer::onPrint);
connect(ui->fullScreenButton, &QToolButton::clicked, this, &ThpViewer::onFullScreen);
connect(ui->htmlWidget, &THP::HtmlWidget::linkClicked, this, &ThpViewer::onLinkClicked);
connect(ui->htmlWidget, &THP::HtmlWidget::urlChanged, this, &ThpViewer::onUrlChanged);
connect(ui->htmlWidget, &THP::HtmlWidget::titleChanged, this, &ThpViewer::onTitleChanged);
ui->backButton->setEnabled(false);
ui->helpButton->setVisible(false); // Help disabled for now
#ifndef Q_WS_WIN
setWindowIcon(QIcon(QStringLiteral(":icons/16x16/rde.ico")));
#endif
setWindowTitle(tr("Combat Training Center"));
}
ThpViewer::~ThpViewer()
{
delete ui;
}
bool ThpViewer::init()
{
QFile file(m_homePath + QStringLiteral("/data.json"));
int exerciseId = 0;
if (file.exists() && file.open(QIODevice::ReadOnly))
{
const auto obj = QJsonDocument::fromJson(file.readAll()).object();
exerciseId = obj.value(QLatin1String("exerciseId")).toInt();
}
else
{
QFile file2(m_homePath + QStringLiteral("/../data.json"));
if (file2.exists() && file2.open(QIODevice::ReadOnly))
{
const auto obj = QJsonDocument::fromJson(file2.readAll()).object();
exerciseId = obj.value(QLatin1String("exerciseId")).toInt();
}
}
DEBUG_LOG(m_logger) << "Use EXERCISE" << exerciseId;
if (!ui->situationWidget->init(m_homePath, exerciseId))
{
ERROR_LOG(m_logger) << "Could not init situation widget - abort";
return false;
}
if (!ui->buildingWidget->init(ui->situationWidget->replayHandler(),
ui->situationWidget->pluginProvider()->buildingPluginProvider(),
m_homePath))
{
ERROR_LOG(m_logger) << "Could not init situation widget - abort";
return false;
}
onZoomChanged();
onLinkClicked(m_homeLink);
return true;
}
void ThpViewer::center()
{
QRect rect = QGuiApplication::primaryScreen()->availableGeometry();
// 80 %
int width = rect.width() * 4 / 5;
int height = rect.height() * 4 / 5;
int x = rect.width() / 2 - width / 2;
int y = rect.height() / 2 - height / 2;
resize(width, height);
move(x, y);
}
void ThpViewer::closeEvent(QCloseEvent *event)
{
// explicit delete those two widgets here, otherwise we may get in trouble
// on windows when the app is closed with the 'X' button from the window frame
delete ui->buildingWidget;
ui->buildingWidget = nullptr;
delete ui->situationWidget;
ui->situationWidget = nullptr;
QWidget::closeEvent(event);
}
void ThpViewer::onNewThp(const QString &index)
{
DEBUG_LOG(m_logger) << "onNewThp: " << index;
if (index.isEmpty())
return;
m_homeLink = QUrl::fromLocalFile(index);
m_homePath = QFileInfo(m_homeLink.toLocalFile()).absolutePath();
DEBUG_LOG(m_logger) << "home: " << m_homeLink.toString();
onLinkClicked(m_homeLink);
ui->backButton->setEnabled(false);
this->raise();
}
void ThpViewer::onTitleChanged(const QString &title)
{
if (title.endsWith(QLatin1String("html")) ||
title.endsWith(QLatin1String("html#!/")))
return;
if (m_trainingName.isEmpty())
m_trainingName = title;
ui->mainLabel->setText(m_trainingName == title ? m_trainingName : QStringLiteral("%1 - %2").arg(m_trainingName, title));
}
void ThpViewer::keyPressEvent(QKeyEvent *e)
{
switch (e->key())
{
case Qt::Key_Backspace:
onBack();
break;
case Qt::Key_Plus:
if (ui->stackedWidget->isVisible() && ui->stackedWidget->currentWidget() == ui->situationWidget)
return;
if (m_scaleFactor < 10)
{
m_scaleFactor *= 1.5;
onZoomChanged();
}
break;
case Qt::Key_M:
{
if (QApplication::queryKeyboardModifiers() == Qt::ControlModifier)
onLinkClicked(QUrl::fromLocalFile(QDir::currentPath() + QStringLiteral("/") + QInputDialog::getText(this, {}, QStringLiteral("href_local"))));
break;
}
case Qt::Key_Minus:
if (ui->stackedWidget->isVisible() && ui->stackedWidget->currentWidget() == ui->situationWidget)
return;
if (m_scaleFactor > 0.05)
{
m_scaleFactor /= 1.5;
onZoomChanged();
}
break;
case Qt::Key_F1:
onHelp();
break;
case Qt::Key_Escape:
if (isFullScreen())
onFullScreen();
break;
default:
QWidget::keyPressEvent(e);
break;
}
}
void ThpViewer::onHelp()
{
QFileInfo f(QStringLiteral("%1/../DATA/help/%2/help.html").arg(QCoreApplication::applicationDirPath(), QString::fromLatin1(NGL::translationLocale())));
if (f.exists())
onLinkClicked(QUrl::fromLocalFile(f.absoluteFilePath())); // TODO Pfad anpassen!
else
{
f.setFile(qApp->applicationDirPath() + QStringLiteral("/../DATA/help/en_US/help.html")); // TODO Pfad anpassen!
if (f.exists())
onLinkClicked(QUrl::fromLocalFile(f.absoluteFilePath()));
}
}
void ThpViewer::onZoomChanged()
{
ui->pdfWidget->setZoomFactor(m_scaleFactor);
ui->htmlWidget->setZoomFactor(m_scaleFactor);
// double zoom = ( int ) ( m_scaleFactor * 100. + 0.5 );
// ui->statusbar->showMessage ( tr ( "zoom: %1 %" ).arg ( zoom ) );
}
void ThpViewer::onLinkClicked(const QUrl &url)
{
DEBUG_LOG(m_logger) << "url: " << url.toString();
const QString path = url.path();
const QString lpath = path.toLower();
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
const QStringRef ext2Chars = ext.left(2);
ui->audioWidget->stop();
ui->videoWidget->stop();
// Video-only
if (lpath.endsWith(QLatin1String("video.pls")) ||
ext == QLatin1String("mpg") ||
ext == QLatin1String("avi") ||
ext == QLatin1String("ogg"))
{
ui->videoWidget->play(url);
ui->stackedWidget->hide();
ui->videoWidget->show();
ui->audioWidget->hide();
ui->backButton->setEnabled(true);
// Audio-only
}
else if (lpath.endsWith(QLatin1String("audio.pls")) ||
ext == QLatin1String("mp3"))
{
ui->audioWidget->play(url);
// Ermitteln der Groesse des AudioWidgets
QSize sizeAudio = ui->audioWidget->sizeHint();
QSize sizeStack = ui->stackedWidget->sizeHint();
sizeStack -= sizeAudio;
QList<int> l;
l << sizeStack.height() << sizeAudio.height();
ui->splitter_1->setSizes(l);
ui->stackedWidget->show(); // hier können wir html mit anzeigen
ui->videoWidget->hide();
ui->audioWidget->show();
ui->backButton->setEnabled(true);
// PDF-only
}
else if (ext == QLatin1String("pdf"))
{
if (ui->pdfWidget->showPDF(url))
{
ui->stackedWidget->setCurrentWidget(ui->pdfWidget);
ui->stackedWidget->show();
ui->pdfWidget->resizePdfToWidth();
ui->videoWidget->hide();
ui->audioWidget->hide();
ui->backButton->setEnabled(true);
}
else
{
QMessageBox::warning(this,
tr("Opening PDF file"),
tr("Can not open PDF file %1 - missing or corrupt file!").arg(url.toString()));
}
}
else if (lpath.endsWith(QLatin1String("sitmap.json"), Qt::CaseInsensitive))
{
// 2D oder 3D ?
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " lpath = '" << lpath << "'";
// peek into <lpath>/sitreplay.json:
QFileInfo fi(path);
const QString basePath = fi.absolutePath();
const QString replayConfigFile = basePath + QDir::separator() + QStringLiteral("sitreplay.json"); // aka replayConfigPath
NOTICE_LOG(m_logger) << LOGFUNCTION << " replayConfigFile = '" << replayConfigFile << "'";
}
// Lage-only
QString localFile = url.toLocalFile();
QString basePath = localFile;
int idx = basePath.lastIndexOf(QLatin1Char('/'));
idx = basePath.lastIndexOf(QLatin1Char('/'), idx - 1);
if (idx >= 0)
basePath.chop(basePath.size() - idx - 1);
ui->situationWidget->showSituation(url.toLocalFile(),
basePath);
ui->stackedWidget->setCurrentWidget(ui->situationWidget);
ui->stackedWidget->show();
ui->videoWidget->hide();
ui->audioWidget->hide();
ui->backButton->setEnabled(true);
}
else if (lpath.endsWith(QLatin1String("buildingViewer.json"), Qt::CaseInsensitive))
{
// BuildingViewer-only
QString localFile = url.toLocalFile();
QString basePath = localFile;
int idx = basePath.lastIndexOf(QLatin1Char('/'));
idx = basePath.lastIndexOf(QLatin1Char('/'), idx - 1);
if (idx >= 0)
basePath.chop(basePath.size() - idx - 1);
ui->buildingWidget->showSituation(url.toLocalFile(),
basePath);
ui->stackedWidget->setCurrentWidget(ui->buildingWidget);
ui->stackedWidget->show();
ui->videoWidget->hide();
ui->audioWidget->hide();
ui->backButton->setEnabled(true);
}
else if (ext == QLatin1String("html") &&
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
{
// Kombiniert
QHash<QString, QUrl> urls = getCombinedPlaybackDetails(url);
if (urls.isEmpty())
return;
if (urls.contains(QLatin1String("audio")))
{
ui->audioWidget->show();
ui->audioWidget->play(urls[QLatin1String("audio")]);
}
if (urls.contains(QLatin1String("video")))
{
ui->videoWidget->show();
ui->videoWidget->play(urls[QLatin1String("video")]);
}
// Einer von dreien:
if (urls.contains(QLatin1String("pdf")))
{
ui->stackedWidget->setCurrentWidget(ui->pdfWidget);
ui->pdfWidget->showPDF(urls[QLatin1String("pdf")]);
ui->stackedWidget->show();
}
else if (urls.contains(QLatin1String("html")))
{
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
ui->htmlWidget->showHTML(urls[QLatin1String("html")]);
ui->stackedWidget->show();
}
else if (urls.contains(QLatin1String("jpg")))
{
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
ui->htmlWidget->showHTML(urls[QLatin1String("jpg")]);
ui->stackedWidget->show();
}
else if (urls.contains(QLatin1String("png")))
{
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
ui->htmlWidget->showHTML(urls[QLatin1String("png")]);
ui->stackedWidget->show();
}
else
ui->stackedWidget->hide();
ui->backButton->setEnabled(true);
}
else if (ext2Chars == QLatin1String("do") ||
ext2Chars == QLatin1String("xl") ||
ext2Chars == QLatin1String("pp"))
QDesktopServices::openUrl(url);
else
{
DEBUG_LOG(m_logger) << "Trying to open url: " << url.toString();
ui->htmlWidget->showHTML(url);
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
ui->stackedWidget->show();
ui->videoWidget->hide();
ui->audioWidget->hide();
ui->backButton->setEnabled(url != m_homeLink);
}
}
/********************************************************************************************
* Parsed eine HTML-Dateinach allen Links, die sich direkt unterhalb des BODY-Tags befinden
* und liefert die entsprechenden Link-URLs zurück, wenn diese das Tag ID besitzen.
*
* Von der aufrufenden Funktion derzeit ausgewertete Werte für ID sind:
* html, audio, video, lage, pdf (alles klein geschrieben!)
*/
QHash<QString, QUrl> ThpViewer::getCombinedPlaybackDetails(const QUrl &url) const
{
QHash<QString, QUrl> hash;
QFile file(url.toLocalFile());
QDomDocument doc(QStringLiteral("RSS"));
if (!file.open(QIODevice::ReadOnly))
return hash;
QString errorStr;
int errorLine, errorColumn;
if (!doc.setContent(&file, true, &errorStr, &errorLine, &errorColumn))
{
file.close();
return hash;
}
QDomElement domel = doc.documentElement();
domel = domel.firstChildElement(QStringLiteral("BODY"));
domel = domel.firstChildElement(QStringLiteral("A"));
while (!domel.isNull())
{
if (!domel.attribute(QStringLiteral("id")).isEmpty())
{
QUrl linkurl(domel.attribute(QStringLiteral("HREF")));
if (linkurl.isRelative())
linkurl = url.resolved(linkurl);
DEBUG_LOG(m_logger) << "attr: " << domel.attribute(QStringLiteral("id")).toLower() << " url: " << linkurl.toString();
hash[domel.attribute(QStringLiteral("id")).toLower()] = linkurl;
}
domel = domel.nextSiblingElement(QStringLiteral("A"));
}
file.close();
return hash;
}
void ThpViewer::onPrint()
{
if (ui->stackedWidget->isVisible())
{
if (ui->stackedWidget->currentWidget() == ui->situationWidget)
{
QImage image = ui->situationWidget->grabFrameBuffer();
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (dialog->exec() != QDialog::Accepted)
return;
QPainter painter;
painter.begin(&printer);
QRectF rect = painter.viewport();
double mmH = printer.logicalDpiY() / 25.4; // 25.4 = mm/inch
double mmW = printer.logicalDpiX() / 25.4;
painter.setFont(QFont(QStringLiteral("Arial"), 30));
QString title = tr("Combat Training Center");
QRectF textBox = painter.boundingRect(QRectF(), Qt::AlignLeft & Qt::TextSingleLine, title);
textBox.setWidth(painter.viewport().width());
painter.drawText(textBox, Qt::AlignCenter & Qt::TextSingleLine, title);
QPointF underImage;
if (printer.orientation() == QPrinter::Portrait)
{
const QPointF textBlockBegin = QPointF(0 * mmW, 25 * mmH); // Baseline 25mm unter Seitenbeginn
// Noch mal schauen, welches (auch übersetzt!) der breiteste Bezeichner (also 1. Spalte) ist!
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
textBox = painter.boundingRect(QRect(), Qt::AlignLeft & Qt::TextSingleLine, tr("Center point:\nExercise:\nTime:"));
// Textbox hat 3 Zeilen, also ist der Faktor pro Zeile 0.33 = 1/3
// Spalte 1
painter.drawText(textBlockBegin, tr("Exercise:"));
painter.drawText(textBlockBegin + QPointF(0, 0.33 * textBox.height()), tr("Time:"));
painter.drawText(textBlockBegin + QPointF(0, 0.66 * textBox.height()), tr("Center point:"));
// Zwischen Spalte 1 und Spalte 2 noch 3mm Platz lassen
// Spalte 2
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0), m_trainingName);
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0.33 * textBox.height()), ui->situationWidget->currentDTGTime());
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0.66 * textBox.height()), ui->situationWidget->centerPointString());
// Das Bild soll formatfüllend angezeigt werden, das Rechteck muss 45mm "flacher" sein, da es erst ab 45mm gedruckt werden soll.
QSizeF size = image.size();
rect.adjust(0, 0, 0, -45 * mmH);
size.scale(rect.size(), Qt::KeepAspectRatio);
// Und ab 45mm von oben drucken:
QRectF imgrect = QRectF(QPointF(0 * mmW, 45 * mmH), size);
painter.drawImage(imgrect, image);
// Untere linke Ecke des Bildes
underImage = imgrect.bottomLeft();
}
else // Landscape
{
// Noch mal schauen, welches (auch übersetzt!) der breiteste Bezeichner oder variable Text ist!
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
textBox = painter.boundingRect(QRect(), Qt::AlignLeft, tr("Center point:\n%1\n\nTime:\n%2\n\nExercise:\n%3")
.arg(m_trainingName,
ui->situationWidget->currentDTGTime(),
ui->situationWidget->centerPointString()));
// TextBlock fängt an: Notwendige Breite von rechts und 15 mm + 1 Zeilenhöhe (=1/8 der Textboxhöhe) von oben.
// Die Zeilenhöhe ist notwendig weil drawText(QPoint, QString) den QPoint auf die Baseline setzt!
QPointF textBlockBegin = QPointF(painter.viewport().width() - textBox.width(), 15 * mmH + 0.125 * textBox.height());
// Die Textbox hat 8 Zeilen, also ist der Faktor pro Zeile 1/8 = 0.125
// Übung
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
painter.drawText(textBlockBegin, tr("Exercise:"));
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
painter.drawText(textBlockBegin + QPointF(0, 0.125 * textBox.height()), m_trainingName);
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
painter.drawText(textBlockBegin + QPointF(0, 0.375 * textBox.height()), tr("Time:"));
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
painter.drawText(textBlockBegin + QPointF(0, 0.500 * textBox.height()), ui->situationWidget->currentDTGTime());
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
painter.drawText(textBlockBegin + QPointF(0, 0.750 * textBox.height()), tr("Center point:"));
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
painter.drawText(textBlockBegin + QPointF(0, 0.875 * textBox.height()), ui->situationWidget->centerPointString());
// Das Bild soll formatfüllend angezeigt werden, das Rechteck muss 15mm "flacher" sein, da es erst ab 15mm gedruckt werden soll.
// Ausserdem müssen in der Breite die Textboxbreite und 3mm Luft dazwischen abgezogen werden.
QSizeF size = image.size();
rect.adjust(0, 0, -textBox.width() - 3 * mmW, -15 * mmH);
size.scale(rect.size(), Qt::KeepAspectRatio);
// Und ab 15mm von oben drucken:
QRectF imgrect = QRectF(QPointF(0 * mmW, 15 * mmH), size);
painter.drawImage(imgrect, image);
// Untere linke Ecke des Bildes
underImage = imgrect.bottomLeft();
}
painter.setFont(QFont(QStringLiteral("Arial"), 12));
// String für Breite und Höhe erstellen
const QRectF extent = ui->situationWidget->extentMgrs();
QString areasize = tr("Width: %1m, Height: %2m").arg(extent.width()).arg(extent.height());
// Die Größe herausfinden
textBox = painter.boundingRect(QRect(), Qt::AlignLeft & Qt::TextSingleLine, areasize);
// Einen Dot vergrößern (siehe QRect: Die Rahmenpixel unten und rechts sind nicht Teil der Rechteckgröße)
textBox.adjust(0, 0, 1, 1);
// An die richtige Stelle bugsieren
textBox.moveBottomLeft(underImage);
// Und mit weiß und 50% Deckkraft vollmalen.
painter.fillRect(textBox, QColor(255, 255, 255, 128));
//Dann den Text drüberlegen
painter.drawText(underImage, areasize);
painter.end();
}
else if (ui->stackedWidget->currentWidget() == ui->pdfWidget)
{
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (dialog->exec() != QDialog::Accepted)
return;
QVector<QImage> images = ui->pdfWidget->getPrintableImages(printer.resolution());
int lastItem = images.size() - 1;
QPainter painter;
painter.begin(&printer);
for (int i = 0; i < images.size(); ++i)
{
QRect rect = painter.viewport();
QSize size = images.at(i).size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(),
size.width(), size.height());
painter.setWindow(images.at(i).rect());
painter.drawImage(0, 0, images.at(i));
if (i != lastItem)
printer.newPage();
}
painter.end();
}
else if (ui->stackedWidget->currentWidget() == ui->htmlWidget)
{
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (dialog->exec() != QDialog::Accepted)
return;
ui->htmlWidget->print(&printer);
}
else // Audio/Video-Widget
{
}
}
else // nur HTML sichtbar...
{
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (dialog->exec() != QDialog::Accepted)
return;
ui->htmlWidget->print(&printer);
}
}
void ThpViewer::onBack()
{
ui->audioWidget->stop();
ui->videoWidget->stop();
ui->situationWidget->stop();
ui->audioWidget->hide();
ui->videoWidget->hide();
if (ui->stackedWidget->currentWidget() == ui->htmlWidget &&
ui->stackedWidget->isVisible())
ui->htmlWidget->back();
ui->stackedWidget->show();
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
onUrlChanged(ui->htmlWidget->url());
}
void ThpViewer::onHome()
{
ui->htmlWidget->show();
onLinkClicked(m_homeLink);
}
void ThpViewer::onFullScreen()
{
setWindowState(windowState() ^ Qt::WindowFullScreen);
}
void ThpViewer::onUrlChanged(const QUrl &url)
{
ui->backButton->setEnabled(url != m_homeLink);
}
} // namespace NGL