Files
fmviewer3/project/fm_viewer/ui/rm_webview2.cpp
2026-02-21 17:11:31 +09:00

1082 lines
37 KiB
C++

#include "rm_webview2.h"
#if (USE_WEBVIEW2)
#if !(TOGGLE_PLAYER || FIXED_MAP_FRAME)
#include "title_widget.h"
#include "rm_widget_drag.h"
#include "fm_button.h"
#endif // TOGGLE_PLAYER
#include "../webview2/webview2/libwebview2.h"
#include <QDebug>
#include <QResizeEvent>
#include <QUuid>
#include <QDir>
#include <QTemporaryFile>
#include <QTimer>
#include "../fm_dimensions.h"
#include "../rm_include.h"
#include "../ui/fm_colors.h"
#include "../data/rm_sensordata.h"
#include "../data/rm_video_item_2ch.h"
// #include "../core/rm_player.h" // -> 충돌발생
#include "../core/fm_strings.h"
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonArray>
#endif // TB4000
#define WEBVIEW2_STRING_BUFFER_SIZE (1024 * 100)
static wchar_t* g_webview2_buffer = NULL;
#if (USE_GOOGLE_MAP_AND_OSM)
static wchar_t* g_webview2_buffer2 = NULL;
#endif
RMWebView* RMWebView::instance(QWidget* parent)
{
static RMWebView * _instance = NULL;
if ( _instance == NULL )
{
_instance = new RMWebView(parent);
}
return _instance;
}
#if (USE_GOOGLE_MAP_AND_OSM)
RMWebView* RMWebView::instance2(QWidget* parent)
{
static RMWebView * _instance2 = NULL;
if ( _instance2 == NULL )
{
_instance2 = new RMWebView(parent,false);
}
return _instance2;
}
#endif // #if (USE_GOOGLE_MAP_AND_OSM)
#if (USE_GOOGLE_MAP_AND_OSM)
RMWebView::RMWebView(QWidget *parent,bool bGoogleMap) : QDialog(parent)
#else
RMWebView::RMWebView(QWidget *parent) : QDialog(parent)
#endif
{
#if (USE_GOOGLE_MAP_AND_OSM)
_bGoogleMap = bGoogleMap;
#endif
// Qt::Tool 추가하지 않으면 태스크바에 아이콘 생김-> parent 윈도우가 있으면 문제 없음
this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
this->setWindowModality(Qt::NonModal);
//QWidget::setWindowFlags()
// 시작시 표시 및 처리되지 않도록 시작
#if (TOGGLE_PLAYER) // FIXED_MAP_FRAME
this->setHidden(true);
#else
this->setAttribute(Qt::WA_DontShowOnScreen,true);
this->setAttribute(Qt::WA_ShowWithoutActivating,true);
#endif // #if !(TOGGLE_PLAYER)
#if (TOGGLE_PLAYER || FIXED_MAP_FRAME)
this->setFixedSize(RIGHT_FRAME_WIDTH,RIGHT_SUB_HEIGHT);
#else
#if (MAP_SINGLE_PATH)
this->setFixedSize(403,493-48);
#else
this->setFixedSize(403,493);
#endif
#endif
afterLoadingURL = ""; // EMPTY
_hideOnFullScreen = false;
_isLoaded = false;
//_isLoading = false;
_scripts = QStringList(); // EMPTY
#if (USE_GOOGLE_MAP_AND_OSM)
if(_bGoogleMap) {
g_webview2_buffer = (wchar_t*)malloc(sizeof(wchar_t) * WEBVIEW2_STRING_BUFFER_SIZE);
} else {
g_webview2_buffer2 = (wchar_t*)malloc(sizeof(wchar_t) * WEBVIEW2_STRING_BUFFER_SIZE);
}
#else
g_webview2_buffer = (wchar_t*)malloc(sizeof(wchar_t) * WEBVIEW2_STRING_BUFFER_SIZE);
#endif
tempFile = NULL;
#if !(REMOVE_MAP_SWITCH_MODE)
_bToggle = false;
_bIsFullScreen = false;
// _bVisible = true;
// _bVisibleLock = false;
_bMapExist = false;
//bLockToggle = true;
#endif // REMOVE_MAP_SWITCH_MODE
_pbox = new QBoxLayout(QBoxLayout::TopToBottom,this);
_pbox->setMargin(0);
_pbox->setSpacing(0);
#if !(TOGGLE_PLAYER || FIXED_MAP_FRAME)
_title = new TitleWidget(this,FMS::txt("map"),"",true);
_pbox->addWidget(_title);
connect(_title->closeButton,SIGNAL(clicked()),this,SLOT(onClose()));
_drag = new RMWidgetDrag(this,POPUP_TITLE_BAR_HEIGHT);
#endif // TOGGLE_PLAYER
_pwin = new QWidget(this);
_pbox->addWidget(_pwin);
#if !(REMOVE_MAP_SWITCH_MODE)
_bToggleSwitch = false;
#endif // REMOVE_MAP_SWITCH_MODE
#if (DEBUG_WEBVIEW2)
//setStyleSheet("QDialog{ border: 1px solid #FF0000;}"); //
//qInfo() << __FUNCTION__;
#endif // DEBUG_WEBVIEW2
setStyleSheet("QDialog{ background-color: #3a3a3a; border: 1px solid #666666;}"); //
_downloadLink = new QLabel(this);
_downloadLink->setWordWrap(true);
QString message= QString::fromWCharArray(L"&nbsp;&nbsp;<font color='#DDDDDD' size=\"3\">WebView2ランタイムがインストールされていないため、<p>&nbsp;&nbsp;地図を表示できません。</font>");
QString linkMessage = QString::fromWCharArray(L"WebView2 ランタイムをダウンロード");
QString textColor = QString().sprintf("<font color='#%06X'>",FM_SELECTED_TEXT_COLOR);
//QString warning = QString::fromWCharArray(L"<p>&nbsp;&nbsp;<font color='#DDDDDD'>※ダウンロードする際は</font><p><font color='#DDDDDD'>「エバーグリーン ブートストラップ」版を選択してください。</font>");
_downloadLink->setText(message + "<p>&nbsp;&nbsp;<a href=\"https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/#download-section\">" + textColor + linkMessage + "</font></a><p>");
_downloadLink->setTextInteractionFlags(Qt::TextBrowserInteraction);
_downloadLink->setOpenExternalLinks(true);
_downloadLink->setAlignment(Qt::AlignLeading | Qt::AlignVCenter);
_downloadLink->setTextFormat(Qt::RichText);
_downloadLink->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
_downloadLink->setHidden(true);
_pbox->addWidget(_downloadLink);
connect(RMApp::instance(),SIGNAL(appEvent(RMApp::Event,int)),this,SLOT(onAppEvent(RMApp::Event,int)));
sensor = NULL;
lonX = -9999;
latY = -9999;
speed = -9999;
// std + 충돌 발생 하여 문제됨
// connect(RMPlayer::instance(),SIGNAL(positionChanged(qint64,qint64)),SLOT(onPositionChanged(qint64,qint64)));
// connect(RMPlayer::instance(),SIGNAL(playEvent(PLAY_EVENT,RMVideoItem*)),SLOT(onPlayEvent(PLAY_EVENT,RMVideoItem*)));
}
void RMWebView::closeWebView2()
{
#if (DEBUG_WEBVIEW2)
qInfo() << __FUNCTION__;
#endif
if(tempFile != NULL) {
tempFile->remove();
delete tempFile;
tempFile = NULL;
}
#if (USE_GOOGLE_MAP_AND_OSM)
if(_bGoogleMap) {
if(g_webview2_buffer != NULL) {
free(g_webview2_buffer);
g_webview2_buffer = NULL;
}
} else {
if(g_webview2_buffer2 != NULL) {
free(g_webview2_buffer2);
g_webview2_buffer2 = NULL;
}
}
#else // USE_GOOGLE_MAP_AND_OSM
if(g_webview2_buffer != NULL) {
free(g_webview2_buffer);
g_webview2_buffer = NULL;
}
#endif // USE_GOOGLE_MAP_AND_OSM
if(_isLoaded) {
set_g_callback(NULL);
_pbox->removeWidget(_pwin);
_pwin->setParent(NULL);
// 상위 윈도우 delete 하지 않고 처리하면 window_impl.cc(114)] Failed to unregister class Chrome_WidgetWin_0. Error = 0 발생
close_window((HWND)_pwin->winId());
delete _pwin;
_pwin = NULL;
}
}
void RMWebView::runScript(QString script)
{
//qInfo() << script << __FUNCTION__;
#if (DEBUG_WEBVIEW2)
//qInfo() << __FUNCTION__;
#endif
// 아직 페이지 로딩 되지 않은 상태
if(!_isLoaded) {
_scripts.append(script);
//qInfo() << _scripts << __FUNCTION__;
return;
}
#if (USE_GOOGLE_MAP_AND_OSM)
wchar_t* b = _bGoogleMap ? g_webview2_buffer : g_webview2_buffer2;
memset(b,0,WEBVIEW2_STRING_BUFFER_SIZE * sizeof(wchar_t));
script.toWCharArray(b);
exec_js((HWND)_pwin->winId(),b);
#else // USE_GOOGLE_MAP_AND_OSM
memset(g_webview2_buffer,0,WEBVIEW2_STRING_BUFFER_SIZE * sizeof(wchar_t));
script.toWCharArray(g_webview2_buffer);
exec_js((HWND)_pwin->winId(),g_webview2_buffer);
#endif // USE_GOOGLE_MAP_AND_OSM
}
void RMWebView::processMessage(QString msg)
{
// 로딩 완료
if(_isLoaded == false && msg.contains("DOMContentLoaded",Qt::CaseInsensitive)) {
//RMUIManager::window->setEnabled(true);
_isLoaded = true;
emit webviewLoading(true);
// // 파일 삭제해도 별 문제는 없음..
// if(tempFile != NULL) {
// tempFile->remove();
// delete tempFile;
// tempFile = NULL;
// }
// DRAW 처리시 문제가 있음
if(_scripts.size() > 0) {
QThread::msleep(100);
}
// clear 반복 제거 + move 반복 제거
QString last5 = "";
while (_scripts.size() > 0) {
// 반복 제거
if(_scripts.first().left(5) == last5) {
_scripts.removeAt(0);
continue;
}
last5 = _scripts.first().left(5);
//qInfo() << _scripts.first() << __FUNCTION__;
runScript(_scripts.first());
QThread::msleep(200);
_scripts.removeAt(0);
}
}
}
#if (USE_GOOGLE_MAP_AND_OSM)
void __stdcall webview2_callback2(TCHAR* msg) {
RMWebView::instance2()->processMessage(QString::fromWCharArray(msg));
}
#endif // USE_GOOGLE_MAP_AND_OSM
void __stdcall webview2_callback(TCHAR* msg) {
RMWebView::instance()->processMessage(QString::fromWCharArray(msg));
}
bool RMWebView::isWebView2Installed()
{
QString v = QString::fromWCharArray(get_webview2_version());
return !v.isEmpty();
}
void RMWebView::_load(QString url)
{
//qInfo() << "LOAD:" << url << "HIDDEN:" << isHidden() << "VISIBLE:" << isVisible() << "ATTRIBUTE:" << testAttribute(Qt::WA_DontShowOnScreen) << __FUNCTION__;
// 이미 로딩된 경우 처리하지 않는다.
if(_isLoaded) {
return;
}
#if (REMOVE_MAP_SWITCH_MODE)
if(isHidden() || testAttribute(Qt::WA_DontShowOnScreen)) {
#else // REMOVE_MAP_SWITCH_MODE
if(_bToggle == false || isHidden() || testAttribute(Qt::WA_DontShowOnScreen)) {
#endif // REMOVE_MAP_SWITCH_MODE
afterLoadingURL = url;
return;
}
// 로딩 시작 단계라 윈도우 정지
emit webviewLoading(false);
//qInfo() << "LOAD START !!!!!!!!!!!!!!!!:" << url << __FUNCTION__;
//resize_webview((HWND)winId());
//RMUIManager::window->setEnabled(false);
// CALLBACK 설정
#if (USE_GOOGLE_MAP_AND_OSM)
if(_bGoogleMap) {
set_g_callback(webview2_callback);
} else {
set_g_callback(webview2_callback2);
}
#else // USE_GOOGLE_MAP_AND_OSM
set_g_callback(webview2_callback);
#endif // USE_GOOGLE_MAP_AND_OSM
#if (USE_KAKAO_MAP)
memset(g_webview2_buffer,0,WEBVIEW2_STRING_BUFFER_SIZE * sizeof(wchar_t));
url.toWCharArray(g_webview2_buffer);
create_webview2((HWND)_pwin->winId(), 0, g_webview2_buffer);
#else // USE_KAKAO_MAP
saveHTML(url);
#if (USE_GOOGLE_MAP_AND_OSM)
wchar_t* b = _bGoogleMap ? g_webview2_buffer : g_webview2_buffer2;
memset(b,0,WEBVIEW2_STRING_BUFFER_SIZE * sizeof(wchar_t));
//qInfo() << tempFile->fileName() << __FUNCTION__;
tempFile->fileName().toWCharArray(b);
create_webview2((HWND)_pwin->winId(), 0, b);
#else
memset(g_webview2_buffer,0,WEBVIEW2_STRING_BUFFER_SIZE * sizeof(wchar_t));
//qInfo() << tempFile->fileName() << __FUNCTION__;
tempFile->fileName().toWCharArray(g_webview2_buffer);
create_webview2((HWND)_pwin->winId(), 0, g_webview2_buffer);
#endif
afterLoadingURL = ""; // 제거
#endif // USE_KAKAO_MAP
}
void RMWebView::_loadPage()
{
if(isVisible()) {
// 설치되지 않은 경우 링크 표시하고 리턴
if(!isWebView2Installed()) {
_downloadLink->setVisible(true);
return;
}
if(!_isLoaded) {
#if (USE_GOOGLE_MAP_AND_OSM)
QString mapSrc = _bGoogleMap ? ":/html/gmap.html" : ":/html/map.html";
#else // USE_GOOGLE_MAP_AND_OSM
#if (USE_GOOGLE_MAP)
#if (RM_MODEL == RM_MODEL_TYPE_FC_DR232W || RM_MODEL == RM_MODEL_TYPE_NX_DRW22)
QString mapSrc = ":/html/gmap_nx.html";
#else
QString mapSrc = ":/html/gmap.html";
#endif // USE_GOOGLE_MAP
#elif (USE_KAKAO_MAP)
// REST API 키 b23672e4e4a740c68b9b626477415781
// JavaScript 키 c1ae69a037acc4eebfb9f6b038dd44fd
//QString mapSrc = "http://fmproject2.iptime.org/telebit/kakao.html";
QString mapSrc = "http://iotbak.telebit.co.kr/product/TB4000/map/kakao.html";
#elif (USE_ROUTO_MAP)
QString mapSrc = ":/html/map_routo.html";
#else // USE_GOOGLE_MAP
QString mapSrc = ":/html/map.html";
#endif // USE_GOOGLE_MAP
#endif // USE_GOOGLE_MAP_AND_OSM
_load(mapSrc);
#if (SUB_MODEL_KEIYO_360)
// 도쿄타워
runScript("moveToMap(35.6586073,139.7452722);");
#endif // SUB_MODEL_KEIYO_360
} // !_isLoaded
} // isVisible()
}
void RMWebView::setVisible(bool bVisible)
{
// 현재 TOGGLE OFF 되어 있는 상태이며 이미 로딩된 상태일 경우 setVisible true 처리하면
// 지도 윈도우가 다시 표시됨
//#if (REMOVE_MAP_SWITCH_MODE)
// if(_isLoaded) {
//#else // REMOVE_MAP_SWITCH_MODE
// if(!_bToggle && _isLoaded) {
//#endif // REMOVE_MAP_SWITCH_MODE
// return;
// }
//_bVisible = bVisible; // 상태 저장 후 표시 요청 상태일 경우
// bLockToggle = !bVisible;
//qInfo() << "SET VISIBLE:" << bVisible << __FUNCTION__;
QDialog::setVisible(bVisible);
_loadPage();
}
void RMWebView::saveHTML(QString src) {
if(src.startsWith("qrc",Qt::CaseInsensitive)) {
src = src.mid(3);
}
QFile htmlFile(src);
if(htmlFile.open(QIODevice::ReadOnly) == false){
qInfo() << src << "OPEN ERROR" << __FUNCTION__;
return;
}
QUuid uuid = QUuid::createUuid();
QString tempFileFullPath = QDir::tempPath() + "/" + uuid.toString().replace("{","").replace("}","") + ".html";
//qInfo() << "tempFileFullPath:" << tempFileFullPath << __FUNCTION__;
tempFile = new QFile(tempFileFullPath);
//temp.setAutoRemove(false);
if(!tempFile->open(QIODevice::WriteOnly)) {
qWarning() << "LOAD MAP HTML ERROR:" << tempFileFullPath << __FUNCTION__;
return;
}
tempFile->write(htmlFile.readAll());
tempFile->close();
//qInfo() << "LOAD MAP HTML:" << tempFile->fileName() << __FUNCTION__;
//navigate(tempFile->fileName());
}
void RMWebView::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event)
resize_webview((HWND)_pwin->winId());
}
#if !(REMOVE_MAP_SWITCH_MODE)
void RMWebView::updateMap(bool bExist)
{
// _bToggle 현재 켜저있는지 여부
// _bMapExist 현재 지도 존재 여부
// _bToggleSwitch UI 스위치가 켜져있는지 여부
// _bToggleFullScreen 전체화면 상태에서의 백업
// 지도가 켜진 상태에서 지도가 있는 다음파일로 넘어갈 경우
// bExist= true _bToggle = false
// _bToggleSwitch = true
// _bToggleFullScreen = true 로 되어 있음
// 이후 전체화면->일반화면으로 이동시
//qInfo() << "bExist" << bExist << "_bToggle:" << _bToggle << "_bToggleSwitch:" << _bToggleSwitch << "_bToggleFullScreen:" << _bToggleFullScreen << __FUNCTION__;
_bMapExist = bExist;
if(_bToggle == false && _bToggleSwitch == true && _bMapExist) {
// 현재 FULL 스크린 상태에서 hide 되어 있는 경우
// if(_bToggleFullScreen) {
// return;
// }
toggle(true,ON_UPDATE_MAP);
}
}
#endif // REMOVE_MAP_SWITCH_MODE
#if !(REMOVE_MAP_SWITCH_MODE)
// onFullScreen 호출시에만
void RMWebView::toggle(bool bVisible,TOGGLE_EVENT event) // ,bool onFullScreen
{
// 다음파일로 넘어갈 경우 toggle 이 호출되지 않고 업데이트가 호출됨.
#if (DEBUG_WEBVIEW2)
//qInfo() << "TOGGLE bVisible:" << bVisible << "isENABLED:" << isEnabled() << "isVISIBLE:" << isVisible() << "TOGGLE_EVENT:" << event << "_bToggleFullScreen:" << _bToggleFullScreen << __FUNCTION__;
qInfo() << "TOGGLE bVisible:" << bVisible << "isENABLED:" << isEnabled() << "isVISIBLE:" << isVisible() << "TOGGLE_EVENT:" << event << __FUNCTION__;
#endif // DEBUG_WEBVIEW2
// 사용자 ON_OFF 설정일 경우 저장
if(event == ON_USER_SWITCH) {
_bToggleSwitch = bVisible;
}
// 전체화면 변경시 처리 요청일 경우 저장
if(event == ON_NORMAL_SCREEN || event == ON_FULL_SCREEN) {
_bIsFullScreen = (event == ON_FULL_SCREEN);
}
// 사용자가 꺼둔 상태일 경우 표시 요청 무시
if(_bToggleSwitch == false && bVisible) {
bVisible = false;
}
// 전체화면 상태일 경우 표시 요청 무시
if(_bIsFullScreen && bVisible) {
bVisible = false;
}
/*
// 전체화면<->일반화면 변경시
// 전체화면 -> 일반화면
if(event == ON_NORMAL_SCREEN) // 항상 bVisible = true
{
_bIsFullScreen = false;
}
else if(event == ON_FULL_SCREEN ) // 항상 bVisible = false
{
_bIsFullScreen = true;
bVisible = !_bIsFullScreen;
//bVisible = !RMUIManager::window->isFullScreen();
// 표시하도록 요청하는 경우 + 이전에 표시되지 않던 상태일 경우 표시하지 않고 리턴한다.
// 다음파일로 넘어갈 경우 지도가 표시되지 않는 문제가 있음
// if(bVisible && !_bToggleFullScreen)
// {
// return;
// }
// if(RMUIManager::window->isFullScreen()) {
// return;
// }
// 나머지의 경우 값을 보관한다.
// _bToggleFullScreen = _bToggle;
}
else if (event == ON_UPDATE_MAP) {
if(bVisible && _bIsFullScreen)
{
bVisible = false;
}
}
else {
// 사용자가 요청했을 경우 이후 처리하기 위해 값을 저장한다.
_bToggleSwitch = bVisible;
}
*/
if(bVisible) {
if(!_bMapExist) {
return;
}
// webview 2 런타임이 설치되지 않을 경우 표시하지 않는다.
if(!isWebView2Installed()) {
#if (DEBUG_WEBVIEW2)
qInfo() << "WEBVIEW2 RUNTIME NOT INSTALLED" << __FUNCTION__;
#endif
return;
}
// WA_DontShowOnScreen 상태에서는
// WA_ShowWithoutActivating 처리하고 한번더 setHidden 한 후 SHOW 처리해야 한번에 정상 표시됨
if(testAttribute(Qt::WA_DontShowOnScreen))
{
setAttribute(Qt::WA_DontShowOnScreen,false);
setAttribute(Qt::WA_ShowWithoutActivating,false);
setHidden(true);
}
show();
if(!afterLoadingURL.isEmpty()) {
//QTimer::singleShot(500,Qt::PreciseTimer,this,SLOT(onStartLoad()));
//afterLoadingURL = "";
_bToggle = true;
load(afterLoadingURL);
}
// setVisible 에서 현재 toggle off 되어 있는 경우 setVisible 처리하지 않고 넘어가는 경우가 있어 다시 처리해야함
if(!isVisible()) {
QDialog::setVisible(true);
}
}
else {
setHidden(true);
setVisible(false);
close();
}
_bToggle = bVisible;
}
#endif // REMOVE_MAP_SWITCH_MODE
void RMWebView::clearScripts()
{
_scripts.clear();
}
bool RMWebView::isHiddenReal()
{
#if !(TOGGLE_PLAYER)
if(testAttribute(Qt::WA_DontShowOnScreen))
{
setAttribute(Qt::WA_DontShowOnScreen,false);
setAttribute(Qt::WA_ShowWithoutActivating,false);
setHidden(true);
return true;
}
#endif
return isHidden();
}
void RMWebView::snapTo(QWidget* target)
{
if(target != NULL) {
snapTarget = target;
}
QPoint lt = snapTarget->mapToGlobal(QPoint(0,0));
move(lt);
//setGeometry(lt.x(),lt.y(),354,226);
//target->installEventFilter(this);
}
void RMWebView::onAppEvent(RMApp::Event event,int param)
{
#if !(USE_MAXIMIZE)
Q_UNUSED(param)
#endif // !USE_MAXIMIZE
//qInfo() << "EVENT:" << event << "PARAM:" << param << "isHidden():" << isHidden() << __FUNCTION__;
if(event == RMApp::WillFullScreen && isHidden() == false)
{
#if (USE_MAXIMIZE)
// MAXIMIZE 모드
if(param == 1) {
}
else
#endif // USE_MAXIMIZE
{
//qInfo() << "SET HIDDEN" << __FUNCTION__;
_hideOnFullScreen = true;
setHidden(true);
}
}
else if (_hideOnFullScreen == true && event == RMApp::WillNormalScreen && isHidden() == true)
{
#if (USE_MAXIMIZE)
// MAXIMIZE 모드
if(param == 1) {
}
else
#endif // USE_MAXIMIZE
{
_hideOnFullScreen = false;
setHidden(false);
}
}
else if (event == RMApp::WillCloseApplication)
{
// clearHtml();
}
}
void RMWebView::onPositionChanged(qint64 position,qint64 duration)
{
if(sensor != NULL)
{
#if !(MAP_SINGLE_PATH)
// 뒤로 이동
bool isFirstLine = (_lastPosition == -1);
bool drawLine = true;
if(_lastPosition > position)
{
drawLine = false;
}
else if (position > _lastPosition + 2000)
{
drawLine = false;
}
_lastPosition = position;
#endif
double ratio = ((double)position) / ((double)duration);
// 처리 속도를 줄이기 위해
double x,y,s;
if(sensor->getGPSPosition(ratio,&x,&y,&s))
{
if(x != lonX || y != latY || s != speed)
{
#if !(MAP_SINGLE_PATH)
// 시속 200 KM 의 경우 1초당 55.5 m 주행 가능
//qInfo() << "DIST:" << RMDialogMap::distance(y,x,latY,lonX);
if(drawLine == false && isFirstLine)
{
drawLine = true;
}
if(drawLine == true && RMDialogMap::distance(y,x,latY,lonX) > (55*3)) // 버퍼 3초
{
drawLine = false;
}
#endif // MAP_SINGLE_PATH
//qInfo() << "LON:" << lonX << " LAT:" << latY << " SPEED:" << s << " DRAW:" << drawLine;
// Status 는 getGPSPosition 에서 처리하지만 잘못된 경우가 있음
#if (FORCE_VALID_LOCATION)
if(true)
#else
if(IS_VALID_LOCATION(x,y))
#endif
{
#if !(MAP_SINGLE_PATH)
if(drawLine == true)
{
QString key = _packLine(lonX,latY,x,y);
if(_drawList.contains(key) == true)
{
drawLine = false;
}
else
{
_drawList.insert(key,true);
}
}
#endif
lonX = x;
latY = y;
speed = s;
#if !(MAP_SINGLE_PATH)
moveTo(lonX,latY,speed,drawLine);
#else
runScript(QString().sprintf("moveToMap(%.8f,%.8f);",latY,lonX));
#endif
}
else {
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
runScript("clearCarMarker();");
#endif
}
}
}
else {
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
runScript("clearCarMarker();");
#endif
}
}
}
void RMWebView::onPlayEvent(PLAY_EVENT event,RMVideoItem* item)
{
#if (FFMPEG_VTHREAD_DEBUG)
return;
#endif // #endif
// 사용자 STOP 일 경우 PLAY ITEM CLEAR
if(event == PLAY_DID_LOADED) {
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
RMApp::instance()->currentAddress = "";
emit RMApp::instance()->appEvent(RMApp::ADDRESS_UPDATED,0);
#endif //
if(item->getSensorData() != NULL && item->getSensorData()->getGPSCount() > 0)
{
#if (FIXED_MAP_FRAME)
// 전체화면에서는 처리하지 않는다
;
bool keepHidden = RMApp::instance()->pMainWindow->isFullScreen() && RMApp::mMAXIMIZE != 1;
// mMAXIMIZE; ///!< 최대화 모드 0: FULLSCREEN 모드, 1: 최대화 모드
//qInfo() << keepHidden << __FUNCTION__;
if(!keepHidden) {
if(RMWebView::instance()->isHiddenReal()) {
RMWebView::instance()->show();
RMWebView::instance()->setFocus();
} else {
RMWebView::setHidden(false);
}
}
#endif // FIXED_MAP_FRAME
sensor = item->getSensorData();
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
QString arg = "";
const NMEA_INFO* nmea = item->getSensorData()->getGPS();
for(uint32_t i=0;i<item->getSensorData()->getGPSCount();i++) {
if(nmea[i].nStatus) {
// _addressLon = 126.546267;// nmea[i].Longitude;
// _addressLat = 37.391276;//nmea[i].Latitude;
_isAddress = 0; // 주소 검색 모드
_addressLon = nmea[i].Longitude;
_addressLat = nmea[i].Latitude;
QString ll = QString().sprintf("%.8f,%.8f",_addressLat,_addressLon);
arg += "function startMap() {\n";
arg += "map.setCenter(new kakao.maps.LatLng(" + ll + "));\n";
arg += "map.setLevel(3);\n";
arg += "marker.setPosition(new kakao.maps.LatLng(" + ll + "));\n";
arg += "marker.setVisible(true);\n";
arg += "}\n";
arg += "startMap();\n";
// 주소요청
//37.524900, 127.007047
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onNetworkReply(QNetworkReply*)));
QNetworkRequest request;
// curl -v -X GET "https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=127.1086228&y=37.4012191" -H "Authorization: KakaoAK b23672e4e4a740c68b9b626477415781"
// curl -v -X GET "https://dapi.kakao.com/v2/local/geo/coord2address.json?x=127.423084873712&y=37.0789561558879&input_coord=WGS84" -H "Authorization: KakaoAK b23672e4e4a740c68b9b626477415781"
// https://dapi.kakao.com/v2/local/geo/coord2address.
// https://dapi.kakao.com/v2/local/geo/coord2address.json?x=127.423084873712&y=37.0789561558879&input_coord=WGS84
QUrl url = QUrl("https://dapi.kakao.com/v2/local/geo/coord2address.json?x=" + QString::number(_addressLon) + "&y=" + QString::number(_addressLat) + "&input_coord=WGS84");
request.setUrl(url);
request.setRawHeader("Authorization", "KakaoAK b23672e4e4a740c68b9b626477415781");
manager->get(request);
break;
}
}
if(!arg.isEmpty()) {
runScript(arg);
}
#else // TB4000
#if (MAP_SINGLE_PATH)
QString arg = "drawPaths([";
int pointCount = 0;
const NMEA_INFO* nmea = item->getSensorData()->getGPS();
bool bStart = false;
int pathCount = 0;
// 초당 1회만 처리하도록 수정
int lastHMS = -1;
int gpsCount = item->getSensorData()->getGPSCount();
for(uint32_t i=0;i<(uint32_t)gpsCount;i++) {
#if (CHECK_GPS_LOCATION)
if( nmea[i].nStatus != 0 && IS_VALID_LOCATION(nmea[i].Longitude,nmea[i].Latitude)) //
#else // CHECK_GPS_LOCATION
if(nmea[i].nStatus != 0)
#endif // CHECK_GPS_LOCATION
{
// 시작되지 않은 경우 시작
if(bStart == false) {
pointCount = 0;
bStart = true;
if(pathCount > 0) {
arg.append(",");
}
pathCount += 1;
arg.append("[");
}
const int csec = nmea[i].nHour * 3600 + nmea[i].nMin * 60 + nmea[i].nSec;
if(csec == lastHMS) {
continue;
}
lastHMS = csec;
if(pointCount > 0)
{
arg.append(",");
}
arg.append("{lat:" + QString::number(nmea[i].Latitude,'f', 6)
+ ", lng:" + QString::number(nmea[i].Longitude,'f', 6) + "}");
pointCount++;
}
else if (bStart) { // 중단된 경우 닫기
bStart = false;
pointCount = 0;
arg.append("]");
}
}
// 마지막까지 데이터가 정상일 경우 닫기
if(bStart) {
arg.append("]");
}
arg.append("]);");
#if (USE_TRIGGER)
if(item->getSensorData()->triggerE >= 0.0f) {
arg.append("\n");
int eIndex = (int)(((float)gpsCount) * item->getSensorData()->triggerE);
eIndex = qMax(qMin(eIndex,gpsCount-1),0);
arg.append("drawEMarkers(" + QString::number(nmea[eIndex].Latitude,'f', 6) + "," + QString::number(nmea[eIndex].Longitude,'f', 6) + ");");
}
if(item->getSensorData()->triggerM >= 0.0f) {
arg.append("\n");
int mIndex = (int)(((float)gpsCount) * item->getSensorData()->triggerM);
mIndex = qMax(qMin(mIndex,gpsCount-1),0);
arg.append("drawMMarkers(" + QString::number(nmea[mIndex].Latitude,'f', 6) + "," + QString::number(nmea[mIndex].Longitude,'f', 6) + ");");
}
#endif // USE_TRIGGER
runScript(arg);
#endif // MAP_SINGLE_PATH
#endif // #else // TB4000
}
else
{
_scripts.clear();
_lastPosition = -1;
lonX = -9999;
latY = -9999;
speed = -9999;
sensor = NULL;
#if (MAP_SINGLE_PATH)
runScript("clearPath();");
#endif
#if (FIXED_MAP_FRAME)
setHidden(true);
#endif // FIXED_MAP_FRAME
}
}
else if (event == PLAY_DID_CLEARED)
{
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
RMApp::instance()->currentAddress = "";
emit RMApp::instance()->appEvent(RMApp::ADDRESS_UPDATED,0);
#endif //
#if (FIXED_MAP_FRAME)
setHidden(true);
#endif // FIXED_MAP_FRAME
_scripts.clear();
_lastPosition = -1;
sensor = NULL;
// lonX = -9999;
// latY = -9999;
// speed = -9999;
#if (MAP_SINGLE_PATH)
runScript("clearPath();");
#endif
}
}
void RMWebView::onClose()
{
_hideOnFullScreen = false;
setHidden(true);
close();
RMApp::instance()->pMainWindow->setFocus();
}
#if (LIVE_LANGUAGE_CHANGE)
void RMWebView::onLanguageChange(RMLanguage::LANGUAGE_TYPE language)
{
Q_UNUSED(language)
#if (MODEL_BBVIEWER)
refreshSpeedBarUnit();
#else // BBVIEWER
refreshLanguage();
#endif // BBVIEWER
}
#endif // LIVE LANGUAGE
#if (LIVE_LANGUAGE_CHANGE && MODEL_STANDARD)
void RMWebView::refreshLanguage()
{
#if (LIVE_LANGUAGE2)
#if !(TOGGLE_PLAYER || FIXED_MAP_FRAME)
_title->titleLabel->setText(FMS::txt("map"));
#endif // #if !(TOGGLE_PLAYER || FIXED_MAP_FRAME)
#endif
// bool isJP = RMLanguage::isJP();
// _title->titleLabel->setText(isJP ? MKU8("\xe5\x9c\xb0\xe5\x9b\xb3") : "MAP");
// lowLable->setText(isJP ? MKU8("\xe4\xbd\x8e\xe9\x80\x9f") : "Low speed");
// highLable->setText(isJP ? MKU8("\xe9\xab\x98\xe9\x80\x9f \x28 \x31\x33\x30 \x4b\x6d\x2f\x68 \xe4\xbb\xa5\xe4\xb8\x8a \x29") : "High speed (up to 130km/h)");
// _title->closeButton->setToolTip(isJP ? MKU8("\xe9\x96\x89\xe3\x81\x98\xe3\x82\x8b") : "Exit");
}
#endif
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
//void RMWebView::onSslErrors(QNetworkReply* reply, const QList<QSslError> &errors)
//{
// foreach (QSslError e, errors)
// {
// }
// reply->ignoreSslErrors();
//}
void RMWebView::requestBoundary() {
_isAddress = 1; // 행정 구역 탐색으로
// "https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?input_coord=WGS84&output_coord=WGS84&y=35.04069167&x=126.843055"
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onNetworkReply(QNetworkReply*)));
QNetworkRequest request;
// curl -v -X GET "https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=127.1086228&y=37.4012191" -H "Authorization: KakaoAK b23672e4e4a740c68b9b626477415781"
// curl -v -X GET "https://dapi.kakao.com/v2/local/geo/coord2address.json?x=127.423084873712&y=37.0789561558879&input_coord=WGS84" -H "Authorization: KakaoAK b23672e4e4a740c68b9b626477415781"
// https://dapi.kakao.com/v2/local/geo/coord2address.
// https://dapi.kakao.com/v2/local/geo/coord2address.json?x=127.423084873712&y=37.0789561558879&input_coord=WGS84
QUrl url = QUrl("https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=" + QString::number(_addressLon) + "&y=" + QString::number(_addressLat) + "&input_coord=WGS84");
request.setUrl(url);
request.setRawHeader("Authorization", "KakaoAK b23672e4e4a740c68b9b626477415781");
manager->get(request);
}
void RMWebView::onNetworkReply(QNetworkReply* reply)
{
if (reply)
{
if (reply->error() == QNetworkReply::NoError)
{
QByteArray bts = reply->readAll();
QString str(bts);
// https://developers.kakao.com/docs/latest/ko/local/dev-guide#coord-to-district
if(reply->url().toString().contains("kakao.com",Qt::CaseInsensitive)) {
// {"meta":{"total_count":1},"documents":[{"road_address":{"address_name":"경기도 용인시 기흥구 예현로35번길 21","region_1depth_name":"경기","region_2depth_name":"용인시 기흥구","region_3depth_name":"","road_name":"예현로35번길","underground_yn":"N","main_building_no":"21","sub_building_no":"","building_name":"예현마을 현대홈타운 104동","zone_no":"17103"},"address":{"address_name":"경기 용인시 기흥구 서천동 705","region_1depth_name":"경기","region_2depth_name":"용인시 기흥구","region_3depth_name":"서천동","mountain_yn":"N","main_address_no":"705","sub_address_no":"","zip_code":""}}
// 2024/04/26 "{"meta":{"total_count":1},"documents":[{"road_address":null,"address":{"address_name":"경기 성남시 분당구 삼평동 678","region_1depth_name":"경기","region_2depth_name":"성남시 분당구","region_3depth_name":"삼평동","mountain_yn":"N","main_address_no":"678","sub_address_no":"","zip_code":""}}]}"
//qInfo() << str << __FUNCTION__;
QJsonDocument doc = QJsonDocument::fromJson(str.toUtf8());
//QJsonValue val(result);
QJsonObject obj = doc.object();
if(obj.contains("documents")) {
QJsonArray ed = obj.value("documents").toArray();
for(int i=0;i<ed.size();i++) {
QJsonObject lo = ed.at(i).toObject();
if (lo.contains("address") && !lo.value("address").isNull()) {
QJsonObject address = lo.value("address").toObject();
if(address.contains("address_name")) {
bool append = (RMApp::instance()->currentAddress.length() > 0);
if (append) {
RMApp::instance()->currentAddress += "<br>(";
}
RMApp::instance()->currentAddress += address.value("address_name").toString();
if (append) {
RMApp::instance()->currentAddress += ")";
}
}
}
if(lo.contains("road_address") && !lo.value("road_address").isNull()) {
QJsonObject road = lo.value("road_address").toObject();
if(road.contains("address_name")) {
bool append = (RMApp::instance()->currentAddress.length() > 0);
if (append) {
RMApp::instance()->currentAddress += "<br>(";
}
RMApp::instance()->currentAddress += road.value("address_name").toString();
if (append) {
RMApp::instance()->currentAddress += ")";
}
}
}
// 행정구역명
// {"region_type":"H","code":"2818586000","address_name":"인천광역시 연수구 송도5동","region_1depth_name":"인천광역시","region_2depth_name":"연수구","region_3depth_name":"송도5동","region_4depth_name":"","x":126.62326996097005,"y":37.413892557164246}]}
if (RMApp::instance()->currentAddress.isEmpty() && lo.contains("address_name") && !lo.value("address_name").isNull()) {
RMApp::instance()->currentAddress = lo.value("address_name").toString();
}
}
if(!RMApp::instance()->currentAddress.isEmpty()) {
//qInfo() << RMApp::instance()->currentAddress << __FUNCTION__;
emit RMApp::instance()->appEvent(RMApp::ADDRESS_UPDATED,0);
} else {
if(_isAddress == 0) { // 주소 검색일 경우
requestBoundary(); // 행정구역 탐색
}
}
}
}
}
else
{
}
reply->deleteLater();
return;
}
}
#endif // TB4000
#endif // #if (USE_WEBVIEW2)