SVG5/mainwindow.cpp
2025-10-12 13:55:56 +09:00

1557 lines
46 KiB
C++

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "formworklist.h"
#include "formhistory.h"
#include "formsetting.h"
#include "formcapture.h"
#include "formviewer.h"
#include "qrtspthread.h"
#include "qgstreamerplayer.h"
#include <QSharedMemory>
#include "charconvert.h"
#include "dialogpowerbutton.h"
#include <QKeyEvent>
#include "dialoglogin.h"
#include "dialogchecksumerror.h"
#include "dialogexportsamba.h"
#include "dialogsettingnetworkshare.h"
#include <QFileInfo>
#include <QDirIterator>
MainWindow* MainWindow::m_pMainWindow = NULL;
CommonData* MainWindow::m_pCommonData = NULL;
extern QRTSPThread t;
extern SThreadWatchVideoLink v;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
m_bMountDiskUSB = false;
m_pProcessNode = NULL;
m_pCommonData = NULL;
QRTSPThread* pThreadRTSP = &t;
SThreadWatchVideoLink* pThreadWatchVideoLink = &v;
m_pMainWindow = this;
m_pCommonData = new CommonData;
m_pCommonData->SetUseWebDisplay(true);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
m_pThreadWatch = NULL;
//#ifndef _PC
m_pThreadWatch = new SThreadWatchPort();
connect(m_pThreadWatch, SIGNAL(CaptureHandSwitch()), this, SLOT(CaptureHandSwitch()));
m_pThreadWatch->start();
//#endif
WRITE_FUNCTION_LOG();
ui->setupUi(this);
setGeometry(0, 0, 1920, 1080);
FormWorklist* pWorklist = new FormWorklist(this);
pWorklist->setGeometry(58, 166, 1808, 857);
pWorklist->hide();
FormHistory* pHistory = new FormHistory(this);
pHistory->setGeometry(58, 166, 1808, 857);
pHistory->hide();
FormSetting* pSetting = new FormSetting(this);
pSetting->setGeometry(58, 166, 1808, 857);
pSetting->hide();
FormCapture* pCapture = new FormCapture(this);
pCapture->setGeometry(0, 0, 1920, 1080);
pCapture->hide();
FormViewer* pViewer = new FormViewer(this);
pViewer->setGeometry(0, 0, 1920, 1080);
pViewer->hide();
#ifndef _PC
//connect(m_pThreadWatch, SIGNAL(HDMICalbeConnect(bool)), pCapture, SLOT(HDMICalbeConnect(bool)));
#endif
pThreadWatchVideoLink->SetThreadRTSP(pThreadRTSP);
//connect(pThreadWatchVideoLink, SIGNAL(HDMICalbeConnect(bool)), pCapture, SLOT(HDMICalbeConnect(bool)));
pThreadWatchVideoLink->WatchVideoConnect();
connect(this, SIGNAL(SendCaptureHandSwitch()), pCapture, SLOT(CaptureHandSwitch()));
connect(this, SIGNAL(SendCaptureFootSwitch()), pCapture, SLOT(CaptureFootSwitch()));
connect(pThreadRTSP, SIGNAL(VideoButtonChange(bool)), pCapture, SLOT(VideoButtonChange(bool)));
//Test Code
connect(pWorklist, SIGNAL(Exit()), this, SLOT(Exit()));
connect(&m_TimerCheckDiskUSB, SIGNAL(timeout()), this, SLOT(CheckDiskUSB()));
m_ListWidget.push_back(pWorklist);
m_ListWidget.push_back(pHistory);
m_ListWidget.push_back(pSetting);
m_ListWidget.push_back(pCapture);
m_ListWidget.push_back(pViewer);
m_pDialogMissCapture = new DialogMissCapture(this);
m_nCurrentMenuID = -1;
m_nCurrentWidgetID = -1;
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(DeferredInit()));
connect(&m_TimerWatchPowerButton, SIGNAL(timeout()), this, SLOT(WatchPowerButton()));
connect(&m_TimerMissCapture, SIGNAL(timeout()), this, SLOT(MissCapture()));
connect(pCapture, SIGNAL(BackupNetworkShareFolder(QString)), this, SLOT(BackupNetworkShareFolder(QString)));
//m_pCommonData->SetUseNetworkBackupVideo(true);
connect(&m_TimerScreenSaver, SIGNAL(timeout()), this, SLOT(CheckShowScreenSaver()));
connect(&m_TimerLog, SIGNAL(timeout()), this, SLOT(WriteLogTimer()));
m_TimerLog.start(1000*5); // 5 seconds
m_Timer.start(500);
m_TimerWatchPowerButton.start(1000);
m_pScreenSaver = new FormScreenSaver;
m_pScreenSaver->hide();
pThreadWatchVideoLink->ChangeState(0);
}
MainWindow::~MainWindow()
{
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
disconnect(&m_Timer, SIGNAL(timeout()), this, SLOT(DeferredInit()));
disconnect(&m_TimerWatchPowerButton, SIGNAL(timeout()), this, SLOT(WatchPowerButton()));
disconnect(&m_TimerMissCapture, SIGNAL(timeout()), this, SLOT(MissCapture()));
disconnect(&m_TimerScreenSaver, SIGNAL(timeout()), this, SLOT(CheckShowScreenSaver()));
disconnect(this, SIGNAL(SendCaptureHandSwitch()), pCapture, SLOT(CaptureHandSwitch()));
disconnect(this, SIGNAL(SendCaptureFootSwitch()), pCapture, SLOT(CaptureFootSwitch()));
SThreadImageSave* pThreadImageSave = m_pCommonData->GetThreadCaptureImage();
if(pThreadImageSave!=NULL)
{
disconnect(pThreadImageSave, SIGNAL(ViewDialogMissCapture()), this, SLOT(ViewDialogMissCapture()) );
}
WRITE_FUNCTION_LOG();
SAFE_DELETE(m_pCommonData);
SAFE_DELETE(m_pScreenSaver);
if(m_pThreadWatch!=NULL)
{
m_pThreadWatch->ExitThread();
SAFE_DELETE(m_pThreadWatch);
}
delete ui;
}
void MainWindow::CheckShowScreenSaver()
{
qint64 nTime = m_TimeCheckScreenSaver.elapsed()/(1000);
int nScreenSaverTime = m_pCommonData->GetScreenSaverTime();
if(nScreenSaverTime==0)
{
return;
}
if(nTime>=60*nScreenSaverTime) //60 sec * 10 --> 10 minutes
{
if(m_pScreenSaver->isVisible()==false)
{
m_pScreenSaver->Init();
StopScreenSaverTimer();
}
}
}
MainWindow* MainWindow::GetMainWindow()
{
return m_pMainWindow;
}
CommonData* MainWindow::GetCommonData()
{
return m_pCommonData;
}
void MainWindow::SetDisplayType(int nType)
{
WRITE_FUNCTION_LOG_PARAM(QString::number(nType));
m_nDisplayType = nType;
m_pCommonData->SetDisplayType(nType);
if(m_nDisplayType==SDISPLAY_1920X1080)
{
resize(1920, 1080);
}
else if(m_nDisplayType==SDISPLAY_1280X1024)
{
resize(1280, 1024);
}
}
void MainWindow::ChangeMenu(int nID)
{
WRITE_FUNCTION_LOG_PARAM(QString::number(nID));
int nPrevCurrentMenuID = m_nCurrentMenuID;
int nPrevCurrentWidgetID = m_nCurrentWidgetID;
SThreadImageSave* pThreadImageSave = m_pCommonData->GetThreadCaptureImage();
if(m_nCurrentWidgetID>=0)
{
m_ListWidget[m_nCurrentWidgetID]->hide();
}
switch(nID)
{
case SMENU_WORKLIST:
m_nCurrentWidgetID = SWIDGET_WORKLIST;
break;
case SMENU_HISTORY:
m_nCurrentWidgetID = SWIDGET_HISTORY;
break;
case SMENU_SETTING:
m_nCurrentWidgetID = SWIDGET_SETTING;
break;
case SMENU_CAPTURE:
m_nCurrentWidgetID = SWIDGET_CAPTURE;
break;
case SMENU_VIEWER:
m_nCurrentWidgetID = SWIDGET_VIEWER;
break;
}
if(nID!=SMENU_CAPTURE)
{
if(m_pCommonData->GetScreenSaverTime()>0)
{
if(m_TimerScreenSaver.isActive()==false)
{
ResetScreenSaverTimer();
StartScreenSaverTimer();
}
}
}
else
{
if(m_pCommonData->GetScreenSaverTime()>0)
{
if(m_TimerScreenSaver.isActive()==true)
{
StopScreenSaverTimer();
}
}
}
if(nID<=SMENU_SETTING)
{
m_nCurrentMenuID = nID;
if(m_nCurrentMenuID==SMENU_WORKLIST)
{
((FormWorklist*)m_ListWidget[m_nCurrentWidgetID])->Init();
}
else if(m_nCurrentMenuID==SMENU_HISTORY)
{
((FormHistory*)m_ListWidget[m_nCurrentWidgetID])->Init();
}
else if(m_nCurrentMenuID==SMENU_SETTING)
{
((FormSetting*)m_ListWidget[m_nCurrentWidgetID])->Init();
}
m_ListWidget[m_nCurrentWidgetID]->show();
return;
}
else
{
if(nID==SMENU_CAPTURE)
{
{
ACQUISITION_INFO* pAcquisitionInfo = m_pCommonData->GetAcquisitionInfo();
QDateTime dt = QDateTime::currentDateTime();
int nYear = dt.date().year();
int nMonth = dt.date().month();
int nDay = dt.date().day();
int nHour = dt.time().hour();
int nMinute = dt.time().minute();
int nSecond = dt.time().second();
SDATA_STUDY* pStudy = pAcquisitionInfo->GetStudyInfo();
//if(pStudy->strStudyDate.length()==0)
{
//pStudy->strStudyDate = (QString("%1%2%3").arg(QString::number(nYear).rightJustified(4, '0')).arg(QString::number(nMonth).rightJustified(2, '0')).arg(QString::number(nDay).rightJustified(2, '0'))).toStdString();
//pStudy->strStudyTime = (QString("%1%2%3").arg(QString::number(nHour).rightJustified(2, '0')).arg(QString::number(nMinute).rightJustified(2, '0')).arg(QString::number(nSecond).rightJustified(2, '0'))).toStdString();
}
if(pAcquisitionInfo->GetPatientInfo()->strPatientID.size()==0)
{
pAcquisitionInfo->Clear();
pAcquisitionInfo->GetPatientInfo()->strPatientID = (QString("%1%2%3%4%5%6").arg(QString::number(nYear)).arg(QString::number(nMonth)).arg(QString::number(nDay)).arg(QString::number(nHour)).arg(QString::number(nMinute)).arg(QString::number(nSecond))).toStdString().c_str();
pAcquisitionInfo->GetPatientInfo()->strPatientName = (QString("테스트%1").arg(pAcquisitionInfo->GetPatientInfo()->strPatientID)).toStdString().c_str();
pAcquisitionInfo->GetStudyInfo()->strStudyInstanceUID = (QString("1.1.22.33.%1.1%2%3.1%4").arg(pAcquisitionInfo->GetPatientInfo()->strPatientID.toStdString().c_str()).arg(QString::number(nHour)).arg(QString::number(nMinute)).arg(QString::number(nSecond))).toStdString().c_str();
pAcquisitionInfo->GetStudyInfo()->strStudyDescription = "Emergency Study Desc.";
pAcquisitionInfo->GetSeriesInfo()->strSeriesDescription = "Emergency Series Desc.";
pAcquisitionInfo->GetSeriesInfo()->strOperatorsName = "";
pAcquisitionInfo->GetPatientInfo()->strPatientSex = "F";
pAcquisitionInfo->GetPatientInfo()->strPatientWeight = "70";
pAcquisitionInfo->GetPatientInfo()->strPatientBirthDate = "19990909";
}
SDatabase* pDatabase = NULL;
int nStudyIndex = 0;
int nPatientIndex = 0;
int nSeriesImageIndex = 0;
int nSeriesMovieIndex = 0;
bool bCreateStudy = false;
int nMaxTestCount = 10;
int nTestCount = 0;
for(nTestCount=0 ; nTestCount<nMaxTestCount ; nTestCount++)
{
SUTIL::SDatabase db(QString("CreateStudyThread_%1").arg(reinterpret_cast<quintptr>(this)));
if (db.OpenDatabase("/home/birdhead/test.db") != 0) {
qWarning() << "DB open failed, retrying...";
usleep(100 * 1000); // DB 연결 실패 시 잠시 대기 후 재시도
continue;
}
// 2. 트랜잭션을 시작합니다. 이제부터 모든 작업은 "All or Nothing" 입니다.
if (!db.BeginTransaction()) {
qWarning() << "Failed to begin transaction, retrying...";
usleep(10 * 1000);
continue;
}
// 3. 트랜잭션 내에서 모든 INSERT 작업을 수행합니다.
nPatientIndex = db.InsertPatient(pAcquisitionInfo);
nStudyIndex = db.InsertStudy(pAcquisitionInfo);
nSeriesImageIndex = db.InsertSeriesImage(pAcquisitionInfo);
nSeriesMovieIndex = db.InsertSeriesMovie(pAcquisitionInfo);
// 4. 모든 작업의 성공 여부를 확인합니다.
if (nPatientIndex > 0 && nStudyIndex > 0 && nSeriesImageIndex > 0 && nSeriesMovieIndex > 0) {
// 5. 모두 성공했다면, 트랜잭션을 최종적으로 데이터베이스에 반영 (Commit)
if (db.Commit()) {
bCreateStudy = true; // 최종 성공!
} else {
qWarning() << "Transaction commit failed! Rolling back...";
db.Rollback(); // Commit 실패 시 롤백
}
} else {
// 하나라도 실패했다면, 지금까지의 모든 작업을 취소 (Rollback)
qWarning() << "One or more insert failed. Rolling back...";
db.Rollback();
}
// 무언가 실패하여 재시도해야 하는 경우, 잠시 대기
if (!bCreateStudy) {
usleep(10 * 1000);
}
}
nStudyIndex = pAcquisitionInfo->m_nIndexStudy;
m_pCommonData->ReleaseAcquisitionInfo();
//bCreateStudy = false;
if(bCreateStudy==false)
{
m_nCurrentMenuID = nPrevCurrentMenuID;
m_nCurrentWidgetID = nPrevCurrentWidgetID;
m_ListWidget[m_nCurrentWidgetID]->show();
if(m_nCurrentMenuID==SMENU_WORKLIST)
{
FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[m_nCurrentWidgetID];
pWorklist->ErrorPatientInfo();
}
else if(m_nCurrentMenuID==SMENU_HISTORY)
{
FormHistory* pHistory = (FormHistory*)m_ListWidget[m_nCurrentWidgetID];
}
SetDisplayError(0x08);
return;
}
if (nStudyIndex > 0)
{
// 1. 이 로직 블록 전체에서 사용할 단 하나의 지역 DB 인스턴스를 생성합니다.
SUTIL::SDatabase db(QString("ProcessStudy_%1").arg(reinterpret_cast<quintptr>(this)));
if (db.OpenDatabase("/home/birdhead/test.db") != 0) {
qWarning() << "DB open failed for study processing, StudyIndex:" << nStudyIndex;
return; // 또는 다른 오류 처리
}
// 2. 새로운 API를 사용합니다. 함수가 직접 결과 "값"을 반환합니다.
QList<QStringList> listResponse = db.GetImageWithStudyIndexASC(nStudyIndex);
int nTotalCount = listResponse.size();
if (nTotalCount > 0)
{
// 3. 동일한 지역 DB 인스턴스를 사용하여 다음 DB 작업을 수행합니다.
db.AddImageToAcquisitionTemp(nStudyIndex);
usleep(10 * 1000);
// 4. 다른 스레드로 데이터를 넘겨줄 때도 값으로 넘겨줍니다.
// (참고: pThreadImageSave의 SetListImageWithStudyASC 함수 시그니처도
// const QList<QStringList>& 타입으로 변경하는 것이 가장 이상적입니다.)
pThreadImageSave->SetListImageWithStudyASC(listResponse);
pThreadImageSave->ChangeState(0x200);
while (pThreadImageSave->GetCurrentState() != 0x2000)
{
QThread::usleep(1000 * 100);
}
pThreadImageSave->ChangeState(0);
}
// 5. 더 이상 수동으로 메모리를 해제할 필요가 없습니다.
// SDatabase::DeleteListReponse(listResponse); // 이 줄은 완전히 제거됩니다.
}
}
m_nCurrentMenuID = (m_nCurrentMenuID | SMENU_CAPTURE);
FormCapture* pCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
pCapture->Init();
pCapture->show();
pCapture->setFocus();
/*
if(m_pCommonData->IsAutoVideoCapture()==true)
{
//m_pCommonData->GetThreadRTSP()->ChangeState(0);
QString strVideoFilename = m_pCommonData->GetNewFilename(DISPLAY_VIDEO);
m_pCommonData->GetThreadRTSP()->SaveFile(strVideoFilename);
m_pCommonData->GetThreadRTSP()->ChangeState(6);
}
else
{
m_pCommonData->GetThreadRTSP()->ChangeState(0);
}
*/
m_pCommonData->GetThreadRTSP()->ChangeState(0);
usleep(1*1000);
}
else if(nID==SMENU_VIEWER)
{
HISTORY_STUDY* pHistoryStudy = m_pCommonData->GetCurrentHistoryStudy();
if(pHistoryStudy==NULL)
{
return;
}
//QString strStudyInstanceUID = *pHistoryStudy->pStrStudyInstanceUID;
//int nStudyIndex = pDatabase->GetStudyIndexWithStudyInstanceUID(strStudyInstanceUID);
QString strStudyIndex = *pHistoryStudy->pStrStudyIndex;
m_pCommonData->ReleaseCurrentHistoryStudy();
int nStudyIndex = strStudyIndex.toInt();
FormViewer* pViewer = (FormViewer*)m_ListWidget[m_nCurrentWidgetID];
m_nCurrentMenuID = (m_nCurrentMenuID | SMENU_VIEWER);
QDate dateToday = QDate::currentDate();
int nYear = dateToday.year();
int nMonth = dateToday.month();
int nDay = dateToday.day();
QString strSearchDate = QString("%1/%2/%3-%1/%2/%3").arg(QString::number(nYear).rightJustified(4, '0')).arg(QString::number(nMonth).rightJustified(2, '0')).arg(QString::number(nDay).rightJustified(2, '0'));
CommonData* pCommonData = MainWindow::GetCommonData();
pCommonData->ClearHistoryImage();
pCommonData->ClearHistorySearchItem();
pCommonData->ClearHistorySearchStudyIndex();
SEARCH_ITEM si;
//QList<QStringList*> listResponse;
si.m_strStudyDate = strSearchDate;
//si.m_strStudyDate = "2021/08/06-2021/08/12";
//si.m_strPatientName = "202188";
int historyCount = 0;
QList<QStringList> listResponse; // 포인터가 아닌 값 타입의 리스트
// 1. 이 작업을 위한 지역 DB 인스턴스를 생성하고 연결합니다.
SUTIL::SDatabase db(QString("HistoryAndImageFetch_%1").arg(reinterpret_cast<quintptr>(this)));
if (db.OpenDatabase("/home/birdhead/test.db") == 0) // 0이 성공
{
// 2. 새로운 GetHistory API를 호출하고, 반환 값을 변수에 저장합니다.
// (기존 코드에서는 이 값을 사용하지 않았지만, 필요할 수 있으므로 받아둡니다.)
historyCount = db.GetHistory(&si);
// 3. 새로운 GetImageWithStudyIndex API를 호출하여 결과를 직접 받습니다.
// 더 이상 출력 파라미터나 포인터를 사용하지 않습니다.
listResponse = db.GetImageWithStudyIndex(nStudyIndex);
}
else
{
qWarning() << "DB open failed for history/image fetching.";
// 필요에 따라 오류 처리
}
// 이제 'historyCount'와 'listResponse'를 안전하게 사용할 수 있습니다.
// 예를 들어:
qDebug() << "Found history items:" << historyCount;
qDebug() << "Found images in study:" << listResponse.size();
// 수동 메모리 해제는 더 이상 필요 없습니다.
// SDatabase::DeleteListReponse(listResponse); // 이 줄은 완전히 제거됩니다.
pCommonData->SetSearchItemHistory(si);
pCommonData->SetHistorySearchStudyIndex(nStudyIndex);
int nImageCount = listResponse.size();
pViewer->Init();
pViewer->SetTotalImageCount(nImageCount);
//pViewer->UpdateViewer();
pViewer->ChangeViewMode(2);
SThreadImageSave* pThreadImageSave = m_pCommonData->GetThreadCaptureImage();
pThreadImageSave->SetListImageWithStudy(listResponse);
pThreadImageSave->ChangeState(0x08);
pViewer->show();
//SDatabase::DeleteListReponse(listResponse);
}
return;
}
}
void MainWindow::ExitCapture()
{
WRITE_FUNCTION_LOG();
m_nCurrentMenuID = (m_nCurrentMenuID & ~SMENU_CAPTURE);
SThreadImageSave* pThreadCaptureImage = m_pCommonData->GetThreadCaptureImage();
pThreadCaptureImage->ExitCapture();
pThreadCaptureImage->ClearCaptureSaveToFile();
FormCapture* pCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
if(pCapture->isVisible()==true)
{
pCapture->ExitCapture();
pCapture->hide();
}
m_pCommonData->ClearCaptureImage();
ACQUISITION_INFO* pAcquisitionInfo = m_pCommonData->GetAcquisitionInfo();
pAcquisitionInfo->Clear();
m_pCommonData->ReleaseAcquisitionInfo();
switch(m_nCurrentMenuID)
{
case SMENU_WORKLIST:
m_nCurrentWidgetID = SWIDGET_WORKLIST;
break;
case SMENU_HISTORY:
m_nCurrentWidgetID = SWIDGET_HISTORY;
break;
case SMENU_SETTING:
m_nCurrentWidgetID = SWIDGET_SETTING;
break;
case SMENU_CAPTURE:
m_nCurrentWidgetID = SWIDGET_CAPTURE;
break;
case SMENU_VIEWER:
m_nCurrentWidgetID = SWIDGET_VIEWER;
break;
}
if(m_nCurrentMenuID==0x22)
{
ui->widgetMainMenu->SelectWorklist();
//m_nCurrentMenuID = SMENU_WORKLIST;
//m_nCurrentWidgetID = SWIDGET_WORKLIST;
//ChangeMenu(m_nCurrentMenuID);
}
m_ListWidget[m_nCurrentWidgetID]->show();
if(m_nCurrentWidgetID!=SMENU_CAPTURE)
{
if(m_pCommonData->GetScreenSaverTime()>0)
{
if(m_TimerScreenSaver.isActive()==false)
{
ResetScreenSaverTimer();
StartScreenSaverTimer();
}
}
}
QWidget* pFocusWidget = focusWidget();
if(m_nCurrentWidgetID==SWIDGET_WORKLIST)
{
FormWorklist* pFormWorklist = (FormWorklist*)m_ListWidget[m_nCurrentWidgetID];
pFormWorklist->Init();
repaint();
}
if(pFocusWidget!=m_ListWidget[m_nCurrentWidgetID])
{
m_ListWidget[m_nCurrentWidgetID]->setFocus(Qt::ActiveWindowFocusReason);
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(ViewerChangeFocusCheck()));
m_Timer.start();
}
if(m_pCommonData->IsUseWebDisplay()==true)
{
if(m_pProcessNode!=NULL)
{
if(m_pProcessNode->state()==QProcess::Running)
{
m_pProcessNode->close();
int nCount = 0;
while(m_pProcessNode->state()==QProcess::Running && nCount<100)
{
usleep(100);
nCount++;
}
if(m_pProcessNode->state()!=QProcess::Running)
{
m_pProcessNode->start("/usr/bin/node", QStringList("index.js"));
}
}
}
}
}
void MainWindow::ErrorCapture()
{
WRITE_FUNCTION_LOG();
ExitCapture();
}
void MainWindow::ExitViewer()
{
WRITE_FUNCTION_LOG();
SThreadImageSave* pThreadImageSave = m_pCommonData->GetThreadCaptureImage();
if(pThreadImageSave->GetCurrentState()==4)
{
pThreadImageSave->StopLoadImage();
while(pThreadImageSave->GetCurrentState()==4)
{
usleep(100*1000);
}
}
m_nCurrentMenuID = (m_nCurrentMenuID & ~SMENU_VIEWER);
m_ListWidget[m_nCurrentWidgetID]->hide();
switch(m_nCurrentMenuID)
{
case SMENU_WORKLIST:
m_nCurrentWidgetID = SWIDGET_WORKLIST;
break;
case SMENU_HISTORY:
m_nCurrentWidgetID = SWIDGET_HISTORY;
((FormHistory*)m_ListWidget[m_nCurrentWidgetID])->Init();
break;
case SMENU_SETTING:
m_nCurrentWidgetID = SWIDGET_SETTING;
break;
case SMENU_CAPTURE:
m_nCurrentWidgetID = SWIDGET_CAPTURE;
break;
case SMENU_VIEWER:
m_nCurrentWidgetID = SWIDGET_VIEWER;
break;
}
m_ListWidget[m_nCurrentWidgetID]->show();
m_pCommonData->ClearHistoryImage();
}
void MainWindow::BackupNetworkShareFolder(QString strFilename)
{
//test samba backup
DialogExportSamba dlgExport(this);
QThread::usleep(1000*1000);
dlgExport.exec();
}
void MainWindow::SetRTSPThread(QRTSPThread* pThread)
{
m_pCommonData->SetRTSPThread(pThread);
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
pThread->SetVideoWidget(pCapture->GetVideoWidget());
}
void MainWindow::SetThreadCaptureImage(SThreadImageSave* pThread)
{
m_pCommonData->SetThreadCaptureImage(pThread);
pThread->OpenDatabase();
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
connect(pThread, SIGNAL(captureImage(CAPTURE_IMAGE*)), pCapture, SLOT(captureImage(CAPTURE_IMAGE*)));
connect(pThread, SIGNAL(captureVideo(CAPTURE_IMAGE*)), pCapture, SLOT(captureVideo(CAPTURE_IMAGE*)));
FormViewer* pViewer = (FormViewer*)m_ListWidget[4];
connect(pThread, SIGNAL(SetImageLoadInfo(int, int, ImageSelect*)), pViewer, SLOT(SetImageLoadInfo(int, int, ImageSelect*)));
connect(pThread, SIGNAL(ImageLoadComplete()), pViewer, SLOT(ImageLoadComplete()));
//FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[0];
//connect(pThread, SIGNAL(worklistUpdateComplete()), pWorklist, SLOT(worklistUpdateComplete()));
//connect(pThread, SIGNAL(worklistError()), pWorklist, SLOT(worklistError()));
//connect(pThread, SIGNAL(SetWorklistProgress(int)), pWorklist, SLOT(SetWorklistProgress(int)));
connect(pThread, SIGNAL(CompleteCleanStorage()), this, SLOT(CompleteCleanStorage()));
connect(pThread, SIGNAL(CompleteAcquisitionFromHistory()), this, SLOT(CompleteAcquisitionFromHistory()));
connect(pThread, SIGNAL(LoadInfoAcquisitionFromHistory(int, int)), this, SLOT(LoadInfoAcquisitionFromHistory(int, int)));
connect(pThread, SIGNAL(ViewDialogMissCapture()), this, SLOT(ViewDialogMissCapture()));
}
void MainWindow::SetThreadSendDICOM(SThreadSendDICOM* pThread)
{
m_pCommonData->SetThreadSendDICOM(pThread);
//FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[0];
//connect(pThread, SIGNAL(worklistUpdateComplete()), pWorklist, SLOT(worklistUpdateComplete()));
//connect(pThread, SIGNAL(worklistError()), pWorklist, SLOT(worklistError()));
//connect(pThread, SIGNAL(SetWorklistProgress(int)), pWorklist, SLOT(SetWorklistProgress(int)));
connect(pThread, SIGNAL(UpdateSendFailed()), this, SLOT(UpdateSendFailed()));
}
void MainWindow::CompleteCleanStorage()
{
WRITE_FUNCTION_LOG();
if (m_pDialogStorageClean != NULL) {
m_pDialogStorageClean->accept();
}
// --- 첫 번째 블록: 스케줄에 따른 자동 삭제 ---
{
// 1. 이 블록만을 위한 지역 DB 인스턴스 생성
SUTIL::SDatabase db("AutoRemoveTask");
if (db.OpenDatabase("/home/birdhead/test.db") == 0)
{
// 2. 두 개의 수정 작업을 하나의 트랜잭션으로 묶어 원자성 보장
db.BeginTransaction();
bool success1 = db.AutoremoveImageTable();
// UpdateScheduled... 함수도 이전에 bool을 반환하도록 수정했어야 하나,
// void라면 일단 호출만 합니다.
db.UpdateScheduledDeleteCompleteStudyDate();
// AutoremoveImageTable의 성공 여부에 따라 Commit 결정
if (success1) {
db.Commit();
} else {
db.Rollback();
}
}
}
// --- 두 번째 블록: 필요 시 추가 공간 확보 ---
m_pCommonData->ComputeStorageSize();
int nStorageFreeSize = m_pCommonData->GetStorageFreeSize();
const int nRemainSize = 100000; // 100MB
if (nStorageFreeSize < nRemainSize)
{
// 1. 이 블록만을 위한 별도의 지역 DB 인스턴스 생성
SUTIL::SDatabase db("FreeUpSpaceTask");
if (db.OpenDatabase("/home/birdhead/test.db") == 0)
{
// 2. 새로운 API를 사용하여 파일 목록을 값(QStringList)으로 직접 받음
QStringList videoFiles = db.GetVideoFileList();
// 3. 파일 삭제 및 DB 업데이트를 하나의 트랜잭션으로 처리
db.BeginTransaction();
bool bSuccess = true;
for (const QString& strFileLocation : videoFiles)
{
bool bFileActuallyDeleted = false;
if(strFileLocation.contains(MOVIE_FILE_EXTENSION)==true)
{
QString strTest = strFileLocation;
QFileInfo fi(strTest);
QString strPath = fi.path();
QString strFilename = fi.fileName();
strFilename = strFilename.replace(MOVIE_FILE_EXTENSION, "");
strFilename += "*";
QDirIterator itDir(strPath, {strFilename}, QDir::Files);
while(itDir.hasNext()==true)
{
QString strFileDelete = itDir.next();
QFile fileRemove(strFileDelete);
if(fileRemove.exists()==true)
{
fileRemove.remove();
bFileActuallyDeleted = true;
}
}
}
// ... (기존과 동일한 파일 시스템에서 파일 삭제 로직) ...
// 이 로직이 성공적으로 파일을 삭제했다면, DB에 업데이트
if (bFileActuallyDeleted) {
// SetDeleteStorageFile 함수도 bool을 반환하도록 수정하는 것이 좋음
if (!db.SetDeleteStorageFile(strFileLocation)) {
bSuccess = false;
break; // DB 업데이트 실패 시 중단
}
}
// 성능 참고: 이 부분은 여전히 비효율적입니다.
// 루프 밖에서 한 번만 계산하거나, 10개 파일 처리 후 한 번씩만 계산하는 것이 좋습니다.
m_pCommonData->ComputeStorageSize();
if (m_pCommonData->GetStorageFreeSize() >= nRemainSize) {
break; // 목표 공간 확보 시 루프 탈출
}
}
if (bSuccess) {
db.Commit();
} else {
db.Rollback();
}
}
}
}
#include "sexception.h"
void MainWindow::DeferredInit()
{
WRITE_FUNCTION_LOG();
m_Timer.stop();
disconnect(&m_Timer, SIGNAL(timeout()), this, SLOT(DeferredInit()));
ChangeMenu(SMENU_WORKLIST);
if (m_pCommonData->IsAutoLogin() == false)
{
DialogLogin dlgLogin(this);
dlgLogin.exec();
}
SThreadImageSave* pThreadImageSave = m_pCommonData->GetThreadCaptureImage();
// --- 첫 번째 블록 리팩토링 ---
{
// 1. 이 작업을 위한 지역 DB 인스턴스를 생성합니다.
SUTIL::SDatabase db("DeferredInit_DeleteList_Connection");
if (db.OpenDatabase("/home/birdhead/test.db") == 0) // 0이 성공
{
// 2. 새로운 API를 호출하여 QStringList 값을 직접 받습니다.
QStringList dateList = db.GetScheduledDeleteStudyDateList();
// 3. 다른 스레드로 값을 전달합니다.
// 참고: SetSchduledDeleteStudyDateList의 파라미터도 const QStringList&로 변경해야 합니다.
pThreadImageSave->SetSchduledDeleteStudyDateList(dateList);
}
else
{
qWarning() << "DB open failed for GetScheduledDeleteStudyDateList in DeferredInit.";
}
// 'db'와 'dateList'는 스코프가 끝나면 자동으로 메모리가 정리됩니다.
// DeleteListReponse 호출이 필요 없습니다.
}
usleep(10 * 1000);
pThreadImageSave->ChangeState(0x100);
m_pDialogStorageClean = new DialogProgress(this);
m_pDialogStorageClean->Init(2);
m_pDialogStorageClean->exec();
delete m_pDialogStorageClean;
m_pDialogStorageClean = NULL;
if (m_pCommonData->IsUseNetworkBackupVideo() == true)
{
// Samba 관련 로직
}
// --- 두 번째 블록 리팩토링 ---
{
// 1. 별도의 작업을 위한 또 다른 지역 DB 인스턴스를 생성합니다.
SUTIL::SDatabase db("DeferredInit_MergeTemp_Connection");
if (db.OpenDatabase("/home/birdhead/test.db") == 0)
{
// 2. 이 함수 하나가 데이터 병합과 임시 테이블 정리를 모두 수행합니다.
db.AddAcquisitionTempToImage();
}
else
{
qWarning() << "DB open failed for AddAcquisitionTempToImage in DeferredInit.";
}
// 'db'는 스코프가 끝나면 자동으로 소멸됩니다.
}
m_TimeCheckScreenSaver.start();
m_TimerScreenSaver.setInterval(1000 * 10);
if (m_pCommonData->IsUseWebDisplay() == true)
{
m_pProcessNode = new QProcess();
m_pProcessNode->setWorkingDirectory("/home/birdhead/web_display");
m_pProcessNode->start("/usr/bin/node", QStringList("index.js"));
}
UmountDiskUSB("/home/birdhead/backup");
m_TimerCheckDiskUSB.start(2000);
}
void MainWindow::Exit()
{
WRITE_FUNCTION_LOG();
FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[0];
FormHistory* pHistory = (FormHistory*)m_ListWidget[1];
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
m_pCommonData->GetThreadRTSP()->exitRTSP();
usleep(1000*1000);
//pWorklist->Exit();
//pHistory->Exit();
m_pCommonData->Exit();
QApplication::quit();
}
void MainWindow::ViewerChangeFocusCheck()
{
WRITE_FUNCTION_LOG();
QWidget* pFocusWidget = focusWidget();
if(pFocusWidget!=m_ListWidget[m_nCurrentWidgetID])
{
usleep(10*1000);
m_ListWidget[m_nCurrentWidgetID]->setFocus(Qt::ActiveWindowFocusReason);
}
else
{
m_ListWidget[m_nCurrentWidgetID]->update();
update();
disconnect(&m_Timer, SIGNAL(timeout()), this, SLOT(ViewerChangeFocusCheck()));
m_Timer.stop();
}
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
QSize nSize = size();
if(m_nDisplayType==SDISPLAY_1280X1024)
{
//ui->widgetMainMenu->setGeometry(45, 40, 462, 58);
ui->widgetMainMenu->setGeometry(45, 40, 1190, 58);
FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[0];
pWorklist->setGeometry(45, 120, 1190, 864);
FormHistory* pHistory = (FormHistory*)m_ListWidget[1];
pHistory->setGeometry(45, 120, 1190, 864);
FormSetting* pSetting = (FormSetting*)m_ListWidget[2];
pSetting->setGeometry(45, 120, 1190, 864);
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
pCapture->setGeometry(0, 0, 1280, 1024);
FormViewer* pViewer = (FormViewer*)m_ListWidget[4];
pViewer->setGeometry(0, 0, 1280, 1024);
m_pDialogMissCapture->setGeometry(0, 0, 1280, 1024);
}
else if(m_nDisplayType==SDISPLAY_1920X1080)
{
ui->widgetMainMenu->setGeometry(58, 58, 573, 70);
FormWorklist* pWorklist = (FormWorklist*)m_ListWidget[0];
pWorklist->setGeometry(58, 166, 1808, 857);
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
pCapture->setGeometry(0, 0, 1920, 1080);
}
}
QWidget* MainWindow::GetFormCapture()
{
FormCapture* pCapture = (FormCapture*)m_ListWidget[3];
return pCapture;
}
void MainWindow::UpdateMakeDICOMInfo(int nCurrent, int nTotal)
{
WRITE_FUNCTION_LOG_PARAM(QString::number(nCurrent) + ", " +QString::number(nTotal));
if(m_nCurrentWidgetID==SWIDGET_VIEWER)
{
FormViewer* pFormViewer = (FormViewer*)m_ListWidget[m_nCurrentWidgetID];
pFormViewer->UpdateMakeDICOMInfo(nCurrent, nTotal);
}
else if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
FormCapture* pFormCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
pFormCapture->UpdateMakeDICOMInfo(nCurrent, nTotal);
}
}
void MainWindow::UpdateSendInfo(int nCount, int nTotalCount)
{
WRITE_FUNCTION_LOG_PARAM(QString::number(nCount) + ", " + QString::number(nTotalCount));
if(m_nCurrentWidgetID==SWIDGET_VIEWER)
{
FormViewer* pFormViewer = (FormViewer*)m_ListWidget[m_nCurrentWidgetID];
pFormViewer->UpdateSendInfo(nCount, nTotalCount);
}
else if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
FormCapture* pFormCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
pFormCapture->UpdateSendInfo(nCount, nTotalCount);
}
/*
switch(nID)
{
case SMENU_WORKLIST:
m_nCurrentWidgetID = SWIDGET_WORKLIST;
break;
case SMENU_HISTORY:
m_nCurrentWidgetID = SWIDGET_HISTORY;
break;
case SMENU_SETTING:
m_nCurrentWidgetID = SWIDGET_SETTING;
break;
case SMENU_CAPTURE:
m_nCurrentWidgetID = SWIDGET_CAPTURE;
break;
case SMENU_VIEWER:
m_nCurrentWidgetID = SWIDGET_VIEWER;
break;
}
*/
}
void MainWindow::UpdateSendComplete()
{
WRITE_FUNCTION_LOG();
if(m_nCurrentWidgetID==SWIDGET_VIEWER)
{
FormViewer* pFormViewer = (FormViewer*)m_ListWidget[m_nCurrentWidgetID];
pFormViewer->UpdateSendComplete();
}
else if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
FormCapture* pFormCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
pFormCapture->UpdateSendComplete();
}
}
void MainWindow::UpdateSendFailed()
{
WRITE_FUNCTION_LOG();
if(m_nCurrentWidgetID==SWIDGET_VIEWER)
{
FormViewer* pFormViewer = (FormViewer*)m_ListWidget[m_nCurrentWidgetID];
pFormViewer->UpdateSendFailed();
}
else if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
FormCapture* pFormCapture = (FormCapture*)m_ListWidget[m_nCurrentWidgetID];
pFormCapture->UpdateSendFailed();
}
}
void MainWindow::UpdateAutoSendDICOMFailed()
{
}
void MainWindow::ClearHistoryView()
{
WRITE_FUNCTION_LOG();
FormHistory* pForm = (FormHistory*)m_ListWidget[SWIDGET_HISTORY];
pForm->Init();
}
int MainWindow::GetCurrentWidgetID()
{
return m_nCurrentWidgetID;
}
void MainWindow::DeleteUI()
{
WRITE_FUNCTION_LOG();
int i=0;
for(i=0 ; i<m_ListWidget.size() ; i++)
{
QWidget* pWidget = m_ListWidget[i];
delete pWidget;
}
m_ListWidget.clear();
m_pCommonData->GetThreadRTSP()->ExitThread();
}
void MainWindow::WatchPowerButton()
{
QSharedMemory shared("SmartQuadra");
if(shared.create(512, QSharedMemory::ReadWrite)==false)
{
//exit(0);
bool bAttach = shared.attach();
if(bAttach==true)
{
int nSize = shared.size();
shared.lock();
{
const char* pData1 = (const char*)shared.constData();
int nLength = strlen(pData1);
if(nLength>0)
{
//Dialog Power Button
DialogPowerButton dlg(this);
//dlg.setGeometry(0, 0, 1280, 1280);
dlg.exec();
char* pPipe = (char*)shared.data();
memset(pPipe, 0, 512);
}
}
shared.unlock();
shared.detach();
}
}
}
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
WRITE_FUNCTION_LOG();
int nKey = event->key();
SThreadImageSave* pThread = MainWindow::GetCommonData()->GetThreadCaptureImage();
if(nKey==Qt::Key_F10)
{
pThread->MissCapture();
}
else if(nKey==Qt::Key_F11)
{
pThread->MissCapture();
}
}
void MainWindow::ViewDialogMissCapture()
{
m_TimerMissCapture.start();
if(m_pDialogMissCapture!=NULL)
{
m_pDialogMissCapture->show();
m_pDialogMissCapture->SetErrorType(0);
}
}
void MainWindow::MissCapture()
{
//m_pDialogMissCapture->show();
m_pDialogMissCapture->exec();
m_TimerMissCapture.stop();
}
void MainWindow::CompleteAcquisitionFromHistory()
{
}
void MainWindow::LoadInfoAcquisitionFromHistory(int nCurrent, int nTotal)
{
}
void MainWindow::ResetScreenSaverTimer()
{
m_TimeCheckScreenSaver.restart();
}
void MainWindow::StartScreenSaverTimer()
{
m_TimerScreenSaver.start();
}
void MainWindow::StopScreenSaverTimer()
{
m_TimerScreenSaver.stop();
}
void MainWindow::CaptureHandSwitch()
{
WRITE_FUNCTION_LOG();
if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
SendCaptureHandSwitch();
}
else
{
SThreadImageSave* pThread = MainWindow::GetCommonData()->GetThreadCaptureImage();
pThread->MissCapture();
}
}
void MainWindow::CaptureFootSwitch()
{
WRITE_FUNCTION_LOG();
if(m_nCurrentWidgetID==SWIDGET_CAPTURE)
{
SendCaptureFootSwitch();
}
else
{
SThreadImageSave* pThread = MainWindow::GetCommonData()->GetThreadCaptureImage();
pThread->MissCapture();
}
}
void MainWindow::WriteLogTimer()
{
if(m_pCommonData->GetLogLevel()==0)
{
return;
}
QStringList* pListLog = m_pCommonData->GetListLog();
QString strLog = QString::fromStdString(pListLog->join("").toStdString());
pListLog->clear();
m_pCommonData->ReleaseListLog();
if(strLog.size()>0)
{
m_pCommonData->WriteLogFile(strLog);
}
}
void MainWindow::SetDisplayError(int nTypeError)
{
m_TimerMissCapture.start();
if(m_pDialogMissCapture!=NULL)
{
m_pDialogMissCapture->show();
m_pDialogMissCapture->SetErrorType(nTypeError);
}
}
void MainWindow::SetDisplayError(QString strError)
{
CommonData::RestartNetworkManager();
m_TimerMissCapture.start();
if(m_pDialogMissCapture!=NULL)
{
m_pDialogMissCapture->show();
m_pDialogMissCapture->SetErrorString(strError);
}
}
void MainWindow::CheckDiskUSB()
{
bool bExists = false;
QString strDevice;
#ifdef _PC
strDevice = "/dev/sdb1";
#else
strDevice = "/dev/sda1";
#endif
QFileInfo fi(strDevice);
bExists = fi.exists();
if(ui->widgetMainMenu->isVisible()==false)
{
return;
}
if(bExists==true)
{
if(m_bMountDiskUSB==false)
{
bool bMount = false;
QProcess processCheckMount;
processCheckMount.start("mount");
while(processCheckMount.waitForStarted(100)==false)
{
usleep(1000);
}
bool retval = false;
QByteArray buffer;
while ((retval = processCheckMount.waitForFinished(100)))
{
usleep(1000);
}
buffer.append(processCheckMount.readAll());
processCheckMount.terminate();
processCheckMount.waitForFinished(100);
processCheckMount.deleteLater();
QString strDeviceMount;
QString strLocationMount;
QString strBufferMount = buffer.toStdString().c_str();
QStringList listMount = strBufferMount.split("\n");
if(strBufferMount.contains(strDevice)==true)
{
int i=0;
for(i=0 ; i<listMount.size() ; i++)
{
QString strTmpMount = listMount[i];
if(strTmpMount.contains(strDevice)==true)
{
QStringList listDeviceMount = strTmpMount.split(" ");
int j=0;
strDeviceMount = listDeviceMount[0];
if(listDeviceMount.size()>=6)
{
for(j=2 ; j<listDeviceMount.size()-3 ; j++)
{
strLocationMount += listDeviceMount[j];
if(j<listDeviceMount.size()-4)
{
strLocationMount += " ";
}
}
}
break;
}
}
//Already mounted
bMount = true;
}
buffer.clear();
if(bMount==true)
{
if(strLocationMount!="/home/birdhead/backup")
{
//umount
UmountDiskUSB(strLocationMount);
MountDiskUSB(strDevice, "/home/birdhead/backup");
}
}
else
{
MountDiskUSB(strDevice, "/home/birdhead/backup");
}
m_bMountDiskUSB = true;
ui->widgetMainMenu->SetEnableDiskUSB(true);
}
}
else
{
if(m_bMountDiskUSB==true)
{
UmountDiskUSB("/home/birdhead/backup");
}
ui->widgetMainMenu->SetEnableDiskUSB(false);
m_bMountDiskUSB = false;
}
}
void MainWindow::MountDiskUSB(QString strDeviceMount, QString strLocationMount)
{
QString strCommand;
strCommand = QString("sudo -S mount %1 %2").arg(strDeviceMount).arg(strLocationMount);
CommandSudo(strCommand);
}
void MainWindow::UmountDiskUSB(QString strLocationMount)
{
QString strCommand;
strCommand = QString("sudo -S umount %1").arg(strLocationMount);
CommandSudo(strCommand);
}
void MainWindow::CommandSudo(QString strCommand)
{
bool retval = false;
QByteArray buffer;
QProcess process1;
QProcess process2;
process1.setStandardOutputProcess(&process2);
process1.start("echo 1");
process2.start(strCommand);
process2.setProcessChannelMode(QProcess::ForwardedChannels);
// Wait for it to start
if(!process1.waitForStarted())
return;
// To be fair: you only need to wait here for a bit with shutdown,
// but I will still leave the rest here for a generic solution
while ((retval = process2.waitForFinished()))
{
buffer.append(process2.readAll());
}
process1.terminate();
process2.terminate();
process1.waitForFinished(100);
process2.waitForFinished(100);
process1.deleteLater();
process2.deleteLater();
buffer.clear();
}