#include #include "CppSQLite3.h" #include #include //#include //#include #include #include "wx/wx.h" #include #include //#include #include #include using namespace crea; #include #include namespace creaImageIO { //============================================================= DicomDatabase::DicomDatabase(const std::string& location, int flags) : DicomNode(DicomNode::Database,0,0), mFileName(location), mFlags(flags) { mDicomDatabase = this; DicomNodeTypeDescription::FieldDescriptionMapType& M = mDicomNodeTypeDescription[DicomNode::Database].GetFieldDescriptionMap(); boost::filesystem::path full_path(location); mName = full_path.leaf(); Field::Description fname("Name",0,0,"Name",0); M[fname.key] = fname; UnsafeSetFieldValue(fname.key,mName); Field::Description flocation("File name",0,0,"File name",0); M[flocation.key] = flocation; UnsafeSetFieldValue(flocation.key,location); // Field::Description ftype("Type",0,0,"Type",0); // M[ftype.key] = ftype; // UnsafeSetFieldValue(ftype.key,"Invalid location"); mDB = new CppSQLite3DB; // std::cout << "** SQLite Version: " << mDB->SQLiteVersion() << std::endl; } //============================================================= //============================================================= DicomDatabase::~DicomDatabase() { delete mDB; /* Already done in DicomNode now that DicomDatabase inherits from it ChildrenListType::iterator i; for (i=GetChildrenList().begin(); i!=GetChildrenList().end(); i++) { delete *i; } */ } //============================================================= //============================================================= void DicomDatabase::BuildDefaultDicomNodeTypeDescriptions() { for (int i = DicomNode::Patient; i <= DicomNode::Image; ++i) { mDicomNodeTypeDescription[i].BuildDefault(i); } } //============================================================= //============================================================= void DicomDatabase::Print() const { std::cout << "-> '"<Print(); } } //============================================================= //===================================================================== bool DicomDatabase::LocationIsValid() { // TO DO return true; } //===================================================================== char* format_sql(const std::string& s) { return sqlite3_mprintf("%q",s.c_str()); } // sqlite3_exec(db, zSQL, 0, 0, 0); // sqlite3_free(zSQL); // char* CHAIN = format_sql(QUER); \ // sqlite3_free(CHAIN); \ //===================================================================== #define QUERYDB(QUER,RES) \ try \ { \ RES = mDB->execQuery(QUER.c_str()); \ } \ catch (CppSQLite3Exception& e) \ { \ std::cout << "SQLite query '"<execDML(UP.c_str()); \ } \ catch (CppSQLite3Exception& e) \ { \ std::cout << "SQLite update '"< DicomDatabase::Open('"< DicomDatabase::New('"<open(GetFileName().c_str()); } catch (CppSQLite3Exception& e) { std::cerr << "Opening '"<open(GetFileName().c_str()); } catch (CppSQLite3Exception& e) { std::cerr << "Creating '"< keys; DicomNodeTypeDescription::FieldDescriptionMapType::iterator i; for (i = GetDicomNodeTypeDescription(c).GetFieldDescriptionMap().begin(); i != GetDicomNodeTypeDescription(c).GetFieldDescriptionMap().end(); ++i) { if (i->second.flags==1) continue; keys.push_back(&(i->second.key)); } std::vector::iterator j; for (j=keys.begin();j!=keys.end();) { s += **j + " text"; ++j; if (j!=keys.end()) s += ",\n"; } } //===================================================================== //===================================================================== void DicomDatabase::ExportDicomNodeTypeDescriptionsToDB() { // std::cout<<"ExportDicomNodeTypeDescriptionsToDB()"< DicomDatabase::Close"<GetType()==DicomNode::Series) { return false; creaError("DicomDatabase::LoadSeriesImages : node is not a series !"); } DBLoadChildren(series,true); return true; } //===================================================================== */ //===================================================================== void DicomDatabase::Clear() { } //===================================================================== //===================================================================== int DicomDatabase::DBLoadChildren(DicomNode* parent, DicomNode::Type maxlevel) { // std::cout << "DicomDatabase::DBLoadChildren("<ChildrenLoaded() ) { // std::cout << "--> Children already loaded"<GetType() == DicomNode::Image ) { return nbloaded; } if ( xparent->GetType() >= maxlevel ) { return nbloaded; } /* if ( parent->ChildrenLoaded().size()>0 ) { DicomNode* n = this; if (parent) n = parent; // If parent already has loaded its children // simply recurse to its children DicomNode::ChildrenListType::iterator i; for (i = n->GetChildrenList().begin(); i != n->GetChildrenList().end(); i++) { DBLoadChildren(*i,load_images); } return; } */ msw[2].Pause(); msw[2].Resume(); DicomNode::Type type = xparent->GetType()+1; // Query DB std::string query = "SELECT * FROM "; query += DicomDatabaseStructure::Table(type); if (parent!=0) { query += " WHERE PARENT_ID='" + parent->GetFieldValue("ID") + "'"; } // std::cout << "** SQL = '"<SetFieldValue(q.fieldName(fld),q.getStringField(fld)); } // Index TypeId ti; ti.type = type; ti.id = n->GetFieldValue("ID"); mTypeIdToDicomNodeMap[ti] = n; // recurse if ( type < maxlevel ) { msw[2].Pause(); nbloaded += DBLoadChildren(n,maxlevel); msw[2].Resume(); } // next entry in db q.nextRow(); } xparent->SetChildrenLoaded(true); msw[2].Pause(); return nbloaded; } //===================================================================== //===================================================================== bool DicomDatabase::DBStructureIsValid() { bool success = true; for (int i = DicomDatabaseStructure::TableBegin(); i != DicomDatabaseStructure::TableEnd();++i) { bool ok = mDB->tableExists(DicomDatabaseStructure::Table(i)); if (ok) { // std::cout << "** Table "<GetLabel() // <<"')"<GetLabel()<<"'" // << std::endl; // Load the patients if not already done DBLoadChildren(this,DicomNode::Patient); parent_id = ""; DicomNode* parent = this; // The chain of ancestors std::deque chain; DicomNode* cur = alien_node->GetParent(); for (int type=DicomNode::Patient; typeGetType();++type) { chain.push_front(cur); cur = cur->GetParent(); } // create the nodes if do not exist std::deque::iterator i; for (i=chain.begin();i!=chain.end();++i) { // std::cout << " cur = '"<<(*i)->GetLabel()<<"'"<GetType()+1); /* } else { // Node exists : get it and load its children parent = GetDicomNodeFromTypeId((*i)->GetType(),cur_id); DBLoadChildren(parent,parent->GetType()+1); } */ parent_id = cur_id; } return parent; } //===================================================================== //===================================================================== void DicomDatabase::DBRecursiveGetOrCreateDicomNode(DicomNode* alien_node, DicomNode* parent, const std::string& parent_id, UpdateSummary& summary) { // std::cout << "DicomDatabase::RecursiveGetOrCreateDicomNode('" // <GetLabel() // <<"','"<GetChildrenList().begin(); i != alien_node->GetChildrenList().end(); i++) { DBRecursiveGetOrCreateDicomNode((*i),new_node,new_id,summary); } } //===================================================================== //===================================================================== DicomNode* DicomDatabase::DBGetOrCreateDicomNode(DicomNode* alien_node, DicomNode* internal_parent, std::string parent_id, std::string& node_id, UpdateSummary& summary) { // std::cout << "DBGetOrCreateDicomNode('"<GetLabel()<<"','" // << internal_parent << "','"<< parent_id<<"')"<0) { node_id = node->UnsafeGetFieldValue("ID"); return node; } // Second : try in DB /* node_id = DBGetDicomNodeId(alien_node,parent_id); if (node_id.size()>0) { msw[4].Pause(); return GetDicomNodeFromTypeId(alien_node->GetType(),node_id); } */ // Does not exist : Create new one node = new DicomNode(alien_node->GetType(),this,internal_parent); node->SetChildrenLoaded(true); // Copy fields values from alien DicomNode::FieldValueMapType::iterator i,j; for (i = node->GetFieldValueMap().begin(); i != node->GetFieldValueMap().end(); i++) { j = alien_node->GetFieldValueMap().find(i->first); if (j != alien_node->GetFieldValueMap().end() ) { i->second = j->second; } } msw[2].Resume(); if (node->GetType()!=DicomNode::Patient) node->SetFieldValue("PARENT_ID",parent_id); // Insert in DB std::string val; BuildSQLFieldsValues(node,val); std::string insert("INSERT INTO "); insert += std::string(DicomDatabaseStructure::Table(node->GetType())) + " " + val + ";"; // std::cout << "** SQL = '"<lastRowId(); std::stringstream ri; ri << mDB->lastRowId(); node_id = ri.str(); // std::cout << "LastRowId='"<lastRowId()<<"' vs '"<SetFieldValue("ID",node_id); // Insert in TypeId map TypeId ti; ti.type = node->GetType(); ti.id = node_id; mTypeIdToDicomNodeMap[ti] = node; // std::cout << "== Insert TypeId ("<GetType()==DicomNode::Patient) summary.added_patients++; if (node->GetType()==DicomNode::Study) summary.added_studies++; if (node->GetType()==DicomNode::Series) summary.added_series++; if (node->GetType()==DicomNode::Image) summary.added_images++; return node; } //===================================================================== //===================================================================== DicomNode* DicomDatabase::GetChildrenLike(DicomNode* parent, DicomNode* alien_node) { DicomNode::ChildrenListType::iterator i; for (i = parent->GetChildrenList().begin(); i != parent->GetChildrenList().end(); i++) { DicomNode::Type type = alien_node->GetType(); bool ok = true; for (int j=0; jGetFieldValue(DicomDatabaseStructure:: QueryField(type,j).key ) != (*i)->GetFieldValue(DicomDatabaseStructure:: QueryField(type,j).key ) ) { ok = false; break; } } if (ok) { return (*i); } } return 0; } //===================================================================== //===================================================================== std::string DicomDatabase::DBGetDicomNodeId(DicomNode* node, const std::string& parent_id) { // std::cout << "DicomDatabase::DBGetDicomNodeId('"<GetLabel() // <<"','"<GetType(); std::string table = DicomDatabaseStructure::Table(type); std::string where = "WHERE "; if (type!=DicomNode::Patient) { where += "PARENT_ID='" + parent_id //node->GetFieldValue("PARENT_ID") + "' AND "; } for (int i=0;iGetParent()) { node->GetParent()->RemoveChildrenFromList(node); } delete node; // std::cout << "DELETE OK"<GetLabel()<<"')"<GetType()); query += " WHERE ID='"+ node->GetFieldValue("ID") + "';"; UPDATEDB(query); DicomNode::ChildrenListType::iterator i; for (i = node->GetChildrenList().begin(); i != node->GetChildrenList().end(); i++) { DBRecursiveRemoveDicomNode((*i)); } } //===================================================================== //===================================================================== int DicomDatabase::DBQueryNumberOfChildren(DicomNode* node) { std::string query = "SELECT COUNT (ID) FROM "; query += DicomDatabaseStructure::Table(node->GetType()+1); if (node->GetType() != DicomNode::Database) { query += " WHERE PARENT_ID='"+ node->GetFieldValue("ID")+"'"; } query += ";"; // std::cout << "**SQL = "<< query << std::endl; CppSQLite3Query q; QUERYDB(query,q); // std::cout << "**RES = "<< q.getIntField(0) <GetLabel()<<"')"<GetFieldValueMap().begin(); i != n->GetFieldValueMap().end(); i++) { if (i->first=="ID") { continue; } // std::cout << "("<first<<","<second<<")"<first + "'"; values += "'" + format_sql2(i->second) + "'"; atts += ","; values += ","; } atts[atts.size()-1]=' '; values[values.size()-1]=' '; str = "("+atts+") VALUES ("+values+")"; } //===================================================================== //===================================================================== bool DicomDatabase::IsHandledFile( const std::string& filename) { return (mReader.CanRead(filename,"")); } //===================================================================== //===================================================================== bool DicomDatabase::AddFiles( const std::vector& filenames, wxProgressDialog* progress, UpdateSummary& summary) { for (int swi=0;swi<10;swi++) { msw[swi].Start(0); msw[swi].Pause(); } // Parse directory wxStopWatch sw; summary.added_images = 0; unsigned int nbf = filenames.size(); std::vector::const_iterator i; for (i=filenames.begin();i!=filenames.end();++i) { summary.scanned_files++; if (IsHandledFile(*i)) { summary.handled_images++; AddFile(*i,summary); if (progress) { std::string mess("Adding "); mess += *i; if (!progress->Update( (int)(summary.added_images*999./nbf), std2wx(mess))) { // Some file was added hence we must return true ! summary.cancelled_by_user = true; break; } } } } sw.Pause(); msw[0].Pause(); msw[1].Pause(); msw[2].Pause(); summary.total_time = sw.Time(); summary.file_scan_time = msw[1].Time(); summary.update_database_time = msw[2].Time(); summary.update_structs_time = summary.total_time - summary.parse_time - summary.file_scan_time - summary.update_database_time; return true; } //===================================================================== //===================================================================== bool DicomDatabase::AddFile( const std::string& filename, UpdateSummary& summary) { // std::cout << "** DicomDatabase::AddFile '"<*/(patient,0); // patient->SetData(new DirDicomNodeData()); // Insert //GetChildrenList().push_back(patient); DicomNode* study = new DicomNode(DicomNode::Study,this,patient); //FillFields/**/(study,0); //study->SetData(new DirDicomNodeData()); DicomNode* series = new DicomNode(DicomNode::Series,this,study); //FillFields/**/(series,0); //series->SetData(new DirDicomNodeData()); DicomNode* image = new DicomNode(DicomNode::Image,this,series); msw[1].Resume(); mReader.ReadDicomInfo(filename,image); msw[1].Pause(); image->SetFieldValue("FullFileName",filename); DBInsert(patient,summary); delete patient; //image->SetData(new DirDicomNodeData()); // Fill Fields //FillFields/**/(image,0); //std::string f(Utilities::GetFileName(*i)); //image->SetFieldValue("A0004_1500",cclean(f)); //image->SetFieldValue("FullFileName",cclean(*i)); return true; } //===================================================================== //===================================================================== /** * \brief Explore a directory with possibility of recursion * return number of files read * @param dirpath directory to explore * @param recursive whether we want recursion or not */ void DicomDatabase::ParseDirectory( const std::string &dirpath, std::vector &Filenames, bool recursive, wxProgressDialog* progress, UpdateSummary& summary) { if (progress) { std::string mess("Parsing "); mess += dirpath; progress->Pulse(std2wx(mess)); } wxStopWatch sw; sw.Start(0); std::string fileName; std::string dirName = dirpath; summary.scanned_dirs++; wxDir dir( std2wx(dirpath) ); if ( !dir.IsOpened() ) { // deal with the error here - wxDir would already log an error message // explaining the exact reason of the failure return; } wxString filename; bool cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN ); while ( cont ) { if ((progress)&&( sw.Time() >= 250 )) { // std::cout << "PULSE"<Pulse()) { summary.cancelled_by_user = true; break; } } summary.scanned_files++; wxFileName wxffn(dir.GetName(),filename); std::string ffn = wx2std(wxffn.GetFullPath()); // std::cout << ffn << std::endl; if (mReader.CanRead(ffn,"")) { Filenames.push_back( ffn ); summary.handled_images++; } cont = dir.GetNext(&filename); } // Recurse into subdirs if ( recursive ) { cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN ); while ( cont ) { wxFileName wxffn(dir.GetName(),filename); std::string ffn = wx2std(wxffn.GetFullPath()); // std::cout << "dir="<< ffn<< std::endl; ParseDirectory( ffn, Filenames, recursive, progress, summary); if (summary.cancelled_by_user) break; cont = dir.GetNext(&filename); } } } //======================================================================= //===================================================================== bool DicomDatabase::AddDirectory( const std::string& directory, bool recurse, wxProgressDialog* progress, UpdateSummary& summary ) { // std::cout << "** DicomDatabase::AddDirectory" // << " '"<Pulse(); } for (int swi=0;swi<10;swi++) { msw[swi].Start(0); msw[swi].Pause(); } // Parse directory wxStopWatch sw; bool was_canceled_by_user(false); std::vector filenames; ParseDirectory( directory, filenames, recurse, progress, summary); if ( summary.cancelled_by_user ) { return false; } summary.parse_time = sw.Time(); summary.added_images = 0; unsigned int nbf = filenames.size(); // , nf = 0; std::vector::iterator i; for (i=filenames.begin();i!=filenames.end();++i) { AddFile(*i,summary); if (progress) { std::string mess("Adding "); mess += *i; if (!progress->Update( (int)(summary.added_images*999./nbf), std2wx(mess))) { // Some file was added hence we must return true ! summary.cancelled_by_user = true; break; } } } sw.Pause(); msw[0].Pause(); msw[1].Pause(); msw[2].Pause(); summary.total_time = sw.Time(); summary.file_scan_time = msw[1].Time(); summary.update_database_time = msw[2].Time(); summary.update_structs_time = summary.total_time - summary.parse_time - summary.file_scan_time - summary.update_database_time; return true; } //===================================================================== } // namespace creaImageIO