/******************************************************************************* * * * Société de Transports de Montréal. * * 2012 - 2013 * * * * Projet Zones Tests * * * * * * * *******************************************************************************/ /* Description: Cette classe est responsable de la création d'une liste d'objets CLogElement à partir des données de passage des trains contenues dans les fichiers log. Cette classe est principalement utilisée par l'interface graphique pour la visualisation des passages. */ /* ************************************************************************** */ /* Revision: ### 20121024 JFM ### YYYYMMDD Description du besoin ou du bug Description du changement. */ /* ************************************************************************** */ #include "LogMgr.h" #include "TrainLogFileMgr.h" #include "OutilZT.h" //#include "ZTLog.h" #include #include #include CLogMgr::CLogMgr() { mProgramHandle = 0; mDirParserThread = new QThread(); mDirParserWorkerThread = new CDirParserThread(); mDirParserWorkerThread->moveToThread(mDirParserThread); connect(mDirParserThread,SIGNAL(started()),mDirParserWorkerThread,SLOT(ParseDirectories())); connect(mDirParserThread,SIGNAL(finished()),this,SLOT(ThreadQuit())); connect(mDirParserThread,SIGNAL(terminated()),this,SLOT(ThreadTerminated())); // connect(mDirParserWorkerThread,SIGNAL(NewLogParsed(QString,bool)),this,SLOT(NewLogParsed(QString,bool))); connect(mDirParserWorkerThread,SIGNAL(NewLogParsed(CLogElement*)),this,SLOT(NewLogParsed(CLogElement*))); connect(mDirParserWorkerThread,SIGNAL(ParsingFinished(int)),this,SLOT(DirParsingFinished(int))); connect(mDirParserWorkerThread,SIGNAL(EmptyDirParsed()),this,SLOT(EmptyDirParsed())); mDatabaseParsingTimer = new QTimer(); mDatabaseParsingTimer->setInterval(60000); connect(mDatabaseParsingTimer,SIGNAL(timeout()),this,SLOT(ParsingTimerExpired())); } CLogMgr::~CLogMgr() { DestroyLogList(); delete mDirParserThread; delete mDirParserWorkerThread; delete mDatabaseParsingTimer; } unsigned int CLogMgr::DestroyLogList() { for(int i = 0; i < mPassagesList.size(); i++) { delete mPassagesList.at(i); } mPassagesList.clear(); return RET_OK; } unsigned int CLogMgr::ProtectLogElementFile(bool IsProtected, CLogElement *Element) { if(Element->mZTLogType == ZT1_LOG_TYPE) { CZT1LogElement *ZT1Element = (CZT1LogElement*)Element; if(CTrainLogFileMgr::instance()->SetTrainLogProtected(IsProtected,ZT1Element->mLogFileName) == RET_OK) { ZT1Element->mFileProtected = IsProtected; SaveDatabaseFile(); return RET_OK; } } else if(Element->mZTLogType == ZT2_LOG_TYPE) { CZT2LogElement *ZT2Element = (CZT2LogElement*)Element; if(CTrainLogFileMgr::instance()->SetTrainLogProtected(IsProtected,ZT2Element->mLogFileName) == RET_OK) { ZT2Element->mFileProtected = IsProtected; SaveDatabaseFile(); return RET_OK; } } return RET_ERROR; } unsigned int CLogMgr::ParseLogs(bool RebuildDatabase, bool KeepData) { DestroyLogList(); qDebug("Parsing Logs now..."); mSaveDBFile = false; mParsingFinished = false; mProgramHandle->DatabaseFetchingBegin(this); mDatabaseFileCounter = 0; if(RebuildDatabase == true) { qDebug("Rebuilding database now..."); mDirParserWorkerThread->SetParsingInfo(QDir(mLogDataDir),"*.bin",KeepData); qDebug("Starting parser thread now..."); mDirParserThread->start(); mSaveDBFile = true; } else { //Load database file. QDir BaseDir(mLogDataDir); QString DatabaseFilePath = BaseDir.filePath("Trains.zdb"); // DatabaseFilePath += "Trains.zdb"; QFile* DatabaseFile = new QFile(BaseDir.filePath("Trains.zdb")/*DatabaseFilePath*/); if(DatabaseFile) { if(DatabaseFile->open(QIODevice::ReadOnly | QIODevice::Unbuffered) == false) { //rebuild database... qDebug("Failed to open Trains.zdb, rebuilding database now..."); mDirParserWorkerThread->SetParsingInfo(QDir(mLogDataDir),"*.bin",KeepData); qDebug("Starting parser thread now..."); mDirParserThread->start(); mSaveDBFile = true; delete DatabaseFile; return RET_OK; } } else { DirParsingFinished(0); return RET_ERROR; } QByteArray DBData = DatabaseFile->readAll(); QDataStream *DBStrm = new QDataStream(DBData); DBStrm->setVersion(QDataStream::Qt_4_8); qint32 NBRecords; *DBStrm >> NBRecords; for(qint32 i = 0; i < NBRecords; i++) { unsigned int LogType; *DBStrm >> LogType; if(LogType == ZT1_LOG_TYPE) { CZT1LogElement *NewElement = new CZT1LogElement; *DBStrm >> NewElement->mPassageDateTime >> NewElement->mTrainType >> NewElement->mNbElements >> NewElement->mThreadDataStartTime >> NewElement->mThreadDataEndTime >> NewElement->mLogFileName >> NewElement->mMeanSpeed >> NewElement->mFlags >> NewElement->mStationName >> NewElement->mFileProtected; int NBDetect; *DBStrm >> NBDetect; for(int i = 0; i < NBDetect; i++) { CZTDetectionData *NewDetection = new CZTDetectionData; *DBStrm >> NewDetection->mDetectionID >> NewDetection->mRank >> NewDetection->mTimeStamp; NewElement->mZTDetections.append(NewDetection); } NewLogParsed(NewElement); } else if(LogType == ZT2_LOG_TYPE) { CZT2LogElement *NewElement = new CZT2LogElement; *DBStrm >> NewElement->mPassageDateTime >> NewElement->mLogFileName >> NewElement->mNbElements >> NewElement-> mStationName >> NewElement->mFlags >> NewElement->mFileProtected; int NBDetect; *DBStrm >> NBDetect; for(int i = 0; i < NBDetect; i++) { CZTDetectionData *NewDetection = new CZTDetectionData; *DBStrm >> NewDetection->mDetectionID >> NewDetection->mRank >> NewDetection->mTimeStamp; NewElement->mZTDetections.append(NewDetection); } NewLogParsed(NewElement); } else { qDebug("Invalid logtype in DB file..."); } } DatabaseFile->close(); delete DatabaseFile; delete DBStrm; DirParsingFinished(1); } return RET_OK; } unsigned int CLogMgr::SaveDatabaseFile() { QDir BaseDir(mLogDataDir); QString DatabaseFilePath = BaseDir.filePath("Trains.zdb"); // DatabaseFilePath += "Trains.zdb"; QFile* DatabaseFile = new QFile(BaseDir.filePath("Trains.zdb")/*DatabaseFilePath*/); if(DatabaseFile) { if(DatabaseFile->open(QIODevice::WriteOnly | QIODevice::Unbuffered) == false) { QMessageBox::information(0,"Erreur","Impossible de créer le fichier DB"); delete DatabaseFile; return RET_ERROR; } } else { QMessageBox::information(0,"Erreur","Impossible de créer le fichier DB"); return RET_ERROR; } QByteArray byteArray; QBuffer FileBuffer(&byteArray); FileBuffer.open(QIODevice::WriteOnly); QDataStream *DBStrm = new QDataStream(&FileBuffer); DBStrm->setVersion(QDataStream::Qt_4_8); qint32 NBRecords = mPassagesList.size(); *DBStrm << NBRecords; for(qint32 i = 0; i < NBRecords; i++) { unsigned int LogType = mPassagesList.at(i)->mZTLogType; *DBStrm << LogType; if(LogType == ZT1_LOG_TYPE) { CZT1LogElement *NewElement = (CZT1LogElement*)mPassagesList.at(i); QDateTime test = NewElement->mPassageDateTime; // *DBStrm << NewElement->mPassageDateTime *DBStrm << test << NewElement->mTrainType << NewElement->mNbElements << NewElement->mThreadDataStartTime << NewElement->mThreadDataEndTime << NewElement->mLogFileName << NewElement->mMeanSpeed << NewElement->mFlags << NewElement->mStationName << NewElement->mFileProtected; int NBDetect = NewElement->mZTDetections.size(); *DBStrm << NBDetect; for(int i = 0; i < NBDetect; i++) { *DBStrm << NewElement->mZTDetections.at(i)->mDetectionID << NewElement->mZTDetections.at(i)->mRank << NewElement->mZTDetections.at(i)->mTimeStamp; } } else if(LogType == ZT2_LOG_TYPE) { CZT2LogElement *NewElement = (CZT2LogElement*)mPassagesList.at(i); *DBStrm << NewElement->mPassageDateTime << NewElement->mLogFileName << NewElement->mNbElements << NewElement->mStationName << NewElement->mFlags << NewElement->mFileProtected; int NBDetect = NewElement->mZTDetections.size(); *DBStrm << NBDetect; for(int i = 0; i < NBDetect; i++) { *DBStrm << NewElement->mZTDetections.at(i)->mDetectionID << NewElement->mZTDetections.at(i)->mRank << NewElement->mZTDetections.at(i)->mTimeStamp; } } else { qDebug("Invalid log type in array!!!"); } } FileBuffer.seek(0); DatabaseFile->write(FileBuffer.buffer()); DatabaseFile->flush(); FileBuffer.close(); DatabaseFile->close(); delete DatabaseFile; delete DBStrm; mSaveDBFile = false; return RET_OK; } unsigned int CLogMgr::RebuildDatabaseFile() { ParseLogs(true,false); mSaveDBFile = true; return RET_OK; } int CLogMgr::ParseDir(QDir dir, bool KeepData) { QStringList LogFilters; QFileInfoList list; // QString LogDataDir = mProgramHandle->GetLogDataPath(); LogFilters << "*.bin"; //Load files in base directory QDir LogDir(dir); LogDir.setFilter(QDir::Files | QDir::NoDotAndDotDot); LogDir.setNameFilters(LogFilters); LogDir.setSorting(QDir::Name); list = LogDir.entryInfoList(); if(list.size() != 0) { //Extract data for each passage for(int i = 0; i < list.size(); i++) { ParseNewLog(list.at(i).filePath(),KeepData); } } //Check for subdirectories QDir SubDirectories(dir); SubDirectories.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList SubDirList = SubDirectories.entryInfoList(); for(int i = 0; i < SubDirList.size(); i++) { ParseDir(QDir(SubDirList.at(i).absoluteFilePath()), KeepData); } return 1; } CLogElement* CLogMgr::LoadLogData(CLogElement *Element) { if(Element->mZTLogType == ZT1_LOG_TYPE) { CZT1LogElement *TargetElement = (CZT1LogElement*)Element; QString FilePath = TargetElement->mLogFileName; unsigned int ret; //Make shure that the lists are empty in the target element for(int i = 0; i < TargetElement->mZTLogData.size(); i++) { delete TargetElement->mZTLogData.at(i); } for(int i = 0; i < TargetElement->mZTDetections.size(); i++) { delete TargetElement->mZTDetections.at(i); } TargetElement->mZTLogData.clear(); TargetElement->mZTDetections.clear(); //Passing the TargetElement to the OpenTrainLog function will fill it with data CTrainLogFileMgr::instance()->OpenTrainLog(FilePath,ret,TargetElement,true); return (CLogElement*)TargetElement; } else if(Element->mZTLogType == ZT2_LOG_TYPE) { CZT2LogElement *TargetElement = (CZT2LogElement*)Element; QString FilePath = TargetElement->mLogFileName; unsigned int ret; //Make shure that the lists are empty in the target element for(int i = 0; i < TargetElement->mZTLogData.size(); i++) { delete TargetElement->mZTLogData.at(i); } for(int i = 0; i < TargetElement->mZTDetections.size(); i++) { delete TargetElement->mZTDetections.at(i); } TargetElement->mZTLogData.clear(); TargetElement->mZTDetections.clear(); //Passing the TargetElement to the OpenTrainLog function will fill it with data CTrainLogFileMgr::instance()->OpenTrainLog(FilePath,ret,TargetElement,true); return (CLogElement*)TargetElement; } return 0; } unsigned int CLogMgr::FreeLogData(CLogElement *Element) { if(Element->mZTLogType == ZT1_LOG_TYPE) { CZT1LogElement *temp = (CZT1LogElement*)Element; for(int i = 0; i < temp->mZTLogData.size(); i++) delete temp->mZTLogData.at(i); temp->mZTLogData.clear(); } if(Element->mZTLogType == ZT2_LOG_TYPE) { CZT2LogElement *temp = (CZT2LogElement*)Element; for(int i = 0; i < temp->mZTLogData.size(); i++) delete temp->mZTLogData.at(i); temp->mZTLogData.clear(); } return RET_OK; } unsigned int CLogMgr::DeleteLog(int LogIndex) { if(LogIndex >= mPassagesList.size()) return RET_ERROR; QString Filename; CLogElement *Element = mPassagesList.takeAt(LogIndex); FreeLogData(Element); //make shure no data will be leaked { if(Element->mZTLogType == ZT1_LOG_TYPE) { CZT1LogElement *temp = (CZT1LogElement*)Element; Filename = temp->mLogFileName; } if(Element->mZTLogType == ZT2_LOG_TYPE) { CZT2LogElement *temp = (CZT2LogElement*)Element; Filename = temp->mLogFileName; } } QDir DirObject; DirObject.remove(Filename); delete Element; SaveDatabaseFile(); return RET_OK; } bool CLogMgr::ParseNextLog() { if((int)mLogsFileIndex >= mLogsFilelist.size()) return false; //Extract data if(ParseNewLog(mLogsFilelist.at(mLogsFileIndex).filePath()) == RET_ERROR) return false; mLogsFileIndex++; return true; } void CLogMgr::NewLogParsed(QString Filename,bool KeepData) { ParseNewLog(Filename,KeepData); mDatabaseParsingTimer->start(); } void CLogMgr::NewLogParsed(CLogElement * NewLog) { mPassagesList.append(NewLog); mDatabaseParsingTimer->start(); mProgramHandle->DatabaseFetchingTick(this,mDatabaseFileCounter++); } void CLogMgr::DirParsingFinished(int Res) { mDatabaseParsingTimer->stop(); mParsingFinished = true; mDirParserThread->quit(); mProgramHandle->LogsDatabaseLoaded(this,Res); if(mSaveDBFile == true) { SaveDatabaseFile(); } } void CLogMgr::ParsingTimerExpired() { qDebug("Parsing timer timeout"); mDirParserWorkerThread->KillThread(); mDirParserThread->terminate(); DirParsingFinished(2); } void CLogMgr::EmptyDirParsed() { //The thread is not stuck. Kick the timer... mDatabaseParsingTimer->start(); } void CLogMgr::ThreadQuit() { qDebug("Thread quit slot"); } void CLogMgr::ThreadTerminated() { qDebug("Thread terminated slot"); } unsigned int CLogMgr::ParseNewLog(QString FileName, bool KeepData) { Q_UNUSED(KeepData) unsigned int ret; CLogElement *NewLog = CTrainLogFileMgr::instance()->OpenTrainLog(FileName,ret); if(ret == RET_ERROR) { return RET_ERROR; } //the date and time of the log entry is assigned the date and time of the first record... if(NewLog->mZTLogType == ZT1_LOG_TYPE) { mPassagesList.append(NewLog); } else if(NewLog->mZTLogType == ZT2_LOG_TYPE) { mPassagesList.append(NewLog); } return RET_OK; } unsigned int CLogMgr::ParseImportedLogs(QStringList *NewLogFiles) { if(NewLogFiles == 0) { return RET_ERROR; } for(int i = 0; i < NewLogFiles->size(); i++) { ParseNewLog(NewLogFiles->at(i)); } SaveDatabaseFile(); mProgramHandle->LogsDatabaseLoaded(this,1); return RET_OK; } unsigned int CLogMgr::GetLogsCount() { return mPassagesList.size(); } QList * CLogMgr::GetLogsList() { return &mPassagesList; } CLogElement::~CLogElement() { } CZT1LogElement::~CZT1LogElement() { qDeleteAll(mZTLogData); mZTLogData.clear(); qDeleteAll(mZTDetections); mZTDetections.clear(); } CZT2LogElement::~CZT2LogElement() { for(int i = 0; i < mZTLogData.size(); i++) delete mZTLogData.at(i); mZTLogData.clear(); for(int i = 0; i < mZTDetections.size(); i++) delete mZTDetections.at(i); mZTDetections.clear(); }