UltraScan III
us_report.cpp
Go to the documentation of this file.
1 
3 #include "us_report.h"
4 #include "us_settings.h"
5 #include "us_util.h"
6 #include "us_db2.h"
7 
8 // Report types
10 {
11  // Open the etc/reports.xml file, then read to create mappings
12  QString path = US_Settings::appBaseDir() + "/etc/reports.xml";
13  QFile file( path );
14 
15  if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
16  {
17  QXmlStreamReader xml( &file );
18 
19  while ( ! xml.atEnd() )
20  {
21  xml.readNext();
22 
23  if ( xml.isStartElement() )
24  {
25  QXmlStreamAttributes atts = xml.attributes();
26  QString name = atts.value( "name" ).toString();
27  QString label = atts.value( "label" ).toString();
28 
29  if ( xml.name() == "application" )
30  { // Map application (analysis) name to label
31  appLabels[ name ] = label;
32  }
33 
34  else if ( xml.name() == "report" )
35  { // Map report (subAnalysis) name to label
36  rptLabels[ name ] = label;
37  }
38 
39  else if ( xml.name() == "extension" )
40  { // Map extension (documentType) name to label and to mime-type
41  extLabels[ name ] = label;
42  extMTypes[ name ] = atts.value( "mimetype" ).toString();
43  }
44  }
45  }
46  }
47 }
48 
49 // Function to show the current values of the class variables
51 {
52  qDebug() << "Application (analysis) mappings:";
53  foreach ( QString label, appLabels.keys() )
54  qDebug() << label << ": " << appLabels.value( label );
55 
56  qDebug() << "";
57 
58  qDebug() << "Report (subAnalysis) mappings:";
59  foreach ( QString label, rptLabels.keys() )
60  qDebug() << label << ": " << rptLabels.value( label );
61 
62  qDebug() << "";
63 
64  qDebug() << "Extension (documentType) mappings:";
65  foreach ( QString label, extLabels.keys() )
66  qDebug() << label << ": " << extLabels.value( label );
67 
68  qDebug() << "";
69 
70  qDebug() << "Extension (mime-type) mappings:";
71  foreach ( QString label, extMTypes.keys() )
72  qDebug() << label << ": " << extMTypes.value( label );
73 
74  qDebug() << "";
75 }
76 
77 // Methods relating to the report document
79 {
80  reset();
81 }
82 
83 // Saves a report document record to DB
85  int tripleID, QString dir, US_DB2* db )
86 {
87  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
88  int status;
89 
90  // First let's be sure we have a valid GUID
91  if ( ! rx.exactMatch( this->documentGUID ) )
92  this->documentGUID = US_Util::new_guid();
93 DbgLv(1) << "Doc::saveDB - GUID" << this->documentGUID;
94 
95  // Find out if this document has been saved already or not
96  QStringList q( "get_reportDocumentID" );
97  q << this->documentGUID;
98  db->query( q );
99 
100  status = db->lastErrno();
101 
102  if ( status == US_DB2::OK )
103  {
104 DbgLv(1) << "Doc::saveDB - UPD ID(old)" << this->documentID;
105  db->next();
106  QString docID = db->value( 0 ).toString();
107  this->documentID = docID.toInt();
108 DbgLv(1) << "Doc::saveDB - UPD ID" << this->documentID;
109  // Update the existing report document record in the DB
110  QStringList q( "update_reportDocument" );
111  q << docID
112  << QString::number( this->editedDataID )
113  << this->label
114  << this->filename
115  << this->analysis
116  << this->subAnalysis
117  << this->documentType;
118  db->query( q );
119 
120  int updateStatus = db->lastErrno();
121 
122  if ( updateStatus != US_DB2::OK )
123  {
124  qDebug() << "update_reportDocument error"
125  << updateStatus;
126  return DB_ERROR;
127  }
128  }
129 
130  else if ( status == US_DB2::NOROWS )
131  {
132 DbgLv(1) << "Doc::saveDB - NEW ID" << this->documentID << "tripID" << tripleID;
133 DbgLv(1) << "Doc::saveDB - NEW editID" << this->editedDataID;
134  // Create a new report document record in the DB
135  QStringList q( "new_reportDocument" );
136  q << QString::number( tripleID )
137  << this->documentGUID
138  << QString::number( this->editedDataID )
139  << this->label
140  << this->filename
141  << this->analysis
142  << this->subAnalysis
143  << this->documentType;
144  db->query( q );
145 
146  int newStatus = db->lastErrno();
147 
148  if ( newStatus != US_DB2::OK )
149  {
150  qDebug() << "new_reportDocument error"
151  << newStatus << db->lastError();
152  return DB_ERROR;
153  }
154 
155  this->documentID = db->lastInsertID();
156  }
157 
158  else // some other database error
159  {
160  qDebug() << "get_reportDocumentID error"
161  << status;
162  return DB_ERROR;
163  }
164 
165  // We can also upload the report contents
166  QString fpath = ( dir.endsWith( "/" ) ? dir : dir + "/" ) + this->filename;
167  int writeStatus = db->writeBlobToDB( fpath,
168  QString( "upload_reportContents" ), this->documentID );
169 
170  if ( writeStatus != US_DB2::OK )
171  {
172  qDebug() << "upload_reportContents error"
173  << writeStatus << db->lastError();
174  return DB_ERROR;
175  }
176 
177  return REPORT_OK;
178 }
179 
180 // Function to read a document from the DB, including document content,
181 // into the local data structure
183 {
184  QStringList q( "get_reportDocument_info" );
185  q << QString::number( this->documentID );
186  db->query( q );
187 
188  int status = db->lastErrno();
189 
190  if ( status == US_DB2::NOROWS )
191  {
192  qDebug() << "get_reportDocument_info NOT_FOUND error" << status;
193  return NOT_FOUND;
194  }
195 
196  else if ( status != US_DB2::OK )
197  {
198  qDebug() << "get_reportDocument_info error" << status;
199  return DB_ERROR;
200  }
201 
202  int docID = this->documentID;
203  this->reset();
204  db->next();
205 
206  this->documentID = docID;
207  this->documentGUID = db->value(0).toString();
208  this->editedDataID = db->value(1).toInt();
209  this->label = db->value(2).toString();
210  this->filename = db->value(3).toString();
211  this->analysis = db->value(4).toString();
212  this->subAnalysis = db->value(5).toString();
213  this->documentType = db->value(6).toString();
214 
215  // We can also download the document contents
216  QString fpath = ( dir.endsWith( "/" ) ? dir : dir + "/" ) + this->filename;
217  int readStatus = db->readBlobFromDB( fpath,
218  QString( "download_reportContents" ), this->documentID );
219 
220  if ( readStatus != US_DB2::OK )
221  {
222  qDebug() << "download_reportContents error"
223  << readStatus;
224  return DB_ERROR;
225  }
226 
227  return REPORT_OK;
228 }
229 
230 // Function to clear out the report document structure
232 {
233  documentID = -1;
234  documentGUID = "";
235  editedDataID = 1;
236  label = "";
237  filename = "";
238  analysis = "";
239  subAnalysis = "";
240  documentType = "";
242 }
243 
244 // Function to show the current values of the class variables
246 {
247  qDebug() << " documentID = " << documentID ;
248  qDebug() << " documentGUID = " << documentGUID ;
249  qDebug() << " editedDataID = " << editedDataID ;
250  qDebug() << " label = " << label ;
251  qDebug() << " filename = " << filename ;
252  qDebug() << " analysis = " << analysis ;
253  qDebug() << " subAnalysis = " << subAnalysis ;
254  qDebug() << " documentType = " << documentType ;
255  qDebug() << "";
256 
257 }
258 
259 // Methods relating to the report triple structure (each triple)
261 {
262  reset();
263 }
264 
265 // Saves a report triple record to DB
267 {
268  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
269  int status;
270 
271  // First let's be sure we have a valid GUID
272  if ( ! rx.exactMatch( this->tripleGUID ) )
273  this->tripleGUID = US_Util::new_guid();
274 
275  // Find out if this triple has been saved already or not
276  QStringList q( "get_reportTripleID" );
277  q << this->tripleGUID;
278  db->query( q );
279 
280  status = db->lastErrno();
281 
282  if ( status == US_DB2::OK )
283  {
284  // Update the existing report triple record in the DB
285  QStringList q( "update_reportTriple" );
286  q << QString::number( this->tripleID )
287  << QString::number( -1 ) // resultID unknown in this context
288  << this->triple
289  << this->dataDescription;
290  db->query( q );
291 
292  int updateStatus = db->lastErrno();
293 
294  if ( updateStatus != US_DB2::OK )
295  {
296  qDebug() << "update_reportTriple error"
297  << updateStatus;
298  return DB_ERROR;
299  }
300  }
301 
302  else if ( status == US_DB2::NOROWS )
303  {
304  // Create a new report triple record in the DB
305  QStringList q( "new_reportTriple" );
306  q << this->tripleGUID
307  << QString::number( reportID )
308  << QString::number( -1 ) // resultID unknown in this context
309  << this->triple
310  << this->dataDescription;
311  db->query( q );
312 
313  int newStatus = db->lastErrno();
314 
315  if ( newStatus != US_DB2::OK )
316  {
317  qDebug() << "new_reportTriple error"
318  << newStatus;
319  return DB_ERROR;
320  }
321 
322  this->tripleID = db->lastInsertID();
323  }
324 
325  else // some other database error
326  {
327  qDebug() << "get_reportTripleID error"
328  << status;
329  return DB_ERROR;
330  }
331 
332  return REPORT_OK;
333 }
334 
335 // Reads all the documents for the current triple, except document content
337 {
338  docs.clear();
339  QStringList q( "get_reportDocument_desc" );
340  q << QString::number( tripleID );
341  db->query( q );
342 
343  int status = db->lastErrno();
344  if ( status == US_DB2::OK )
345  {
346  while ( db->next() )
347  {
349 
350  d.documentID = db->value(0).toInt();
351  d.documentGUID = db->value(1).toString();
352  d.editedDataID = db->value(2).toInt();
353  d.label = db->value(3).toString();
354  d.filename = db->value(4).toString();
355  d.analysis = db->value(5).toString();
356  d.subAnalysis = db->value(6).toString();
357  d.documentType = db->value(7).toString();
358 
359  docs << d;
360  }
361  }
362 
363  else if ( status != US_DB2::NOROWS )
364  return DB_ERROR;
365 
366  return REPORT_OK;
367 }
368 
369 // Function to add a report document record, both in the object and the DB
371  int editedDataID,
372  QString label,
373  QString dir,
374  QString filename,
375  QString analysis,
376  QString subAnalysis,
377  QString documentType,
378  US_DB2* db )
379 {
381 
382  d.editedDataID = editedDataID;
383  d.label = label;
384  d.filename = filename;
385  d.analysis = analysis;
386  d.subAnalysis = subAnalysis;
387  d.documentType = documentType;
388 
389  return this->addDocument( d, dir, db );
390 }
391 
392 // Function to add/replace an entire document record
395  QString dir,
396  US_DB2* db )
397 {
398  int ndx = this->findDocument( d.analysis, d.subAnalysis, d.documentType );
399 DbgLv(1) << "Trip::addDoc - ndx" << ndx << "ana,subA,Type"
400  << d.analysis << d.subAnalysis << d.documentType;
401 
402 
403  // Easier to delete/add the document if it exists
404  if ( ndx != -1 )
405  {
406 DbgLv(1) << "Trip::addDoc - remove Doc";
407  this->removeDocument( ndx, db );
408  }
409 
410  this->docs << d;
411 
412  // Refresh ndx
413  ndx = this->findDocument( d.analysis, d.subAnalysis, d.documentType );
414 DbgLv(1) << "Trip::addDoc - ndx aft list add" << ndx;
415 
416  return this->docs[ndx].saveDB( this->tripleID, dir, db );
417 }
418 
420  int ndx,
421  US_DB2* db )
422 {
423  QStringList q( "delete_reportDocument" );
424  q << QString::number( this->docs[ndx].documentID );
425  db->query( q );
426 
427  int status = db->lastErrno();
428 
429  if ( status != US_DB2::OK )
430  return DB_ERROR;
431 
432  this->docs.remove( ndx );
433  return REPORT_OK;
434 }
435 
436 // Function to find an existing report document record, based on the
437 // analysis, subAnalysis, and documentType fields
439  QString searchAnal, QString searchSubanal, QString searchType )
440 {
441  for ( int i = 0; i < this->docs.size(); i++ )
442  {
443  if ( ( this->docs[i].analysis == searchAnal ) &&
444  ( this->docs[i].subAnalysis == searchSubanal ) &&
445  ( this->docs[i].documentType == searchType ) )
446  return i;
447  }
448 
449  // If we're here then the triple string we were searching for
450  // was not found
451  return -1;
452 }
453 
454 // Function to clear out the entire report triple structure
456 {
457  tripleID = -1;
458  tripleGUID = "";
459  resultID = -1;
460  triple = "";
461  dataDescription = "";
463 
464  docs.clear();
465 }
466 
467 // Function to show the current values of the class variables
469 {
470  qDebug() << " tripleID = " << tripleID ;
471  qDebug() << " tripleGUID = " << tripleGUID ;
472  qDebug() << " resultID = " << resultID ;
473  qDebug() << " triple = " << triple ;
474  qDebug() << " dataDescription = " << dataDescription ;
475  qDebug() << "";
476 
477  if ( docs.size() > 0 )
478  {
479  qDebug() << " Documents:";
480  foreach ( US_Report::ReportDocument document, docs )
481  document.show();
482  }
483 }
484 
485 // Methods relating to the global report
487 {
488  reset();
489 }
490 
491 // Reads all the report information from DB, except document content
493  QString new_triple )
494 {
495  QStringList q( "get_report_info_by_runID" );
496  q << QString::number( US_Settings::us_inv_ID() )
497  << new_runID;
498  db->query( q );
499 
500  int status = db->lastErrno();
501 
502  if ( status == US_DB2::NOROWS )
503  return NOT_FOUND;
504 
505  else if ( status != US_DB2::OK )
506  return DB_ERROR;
507 
508  this->reset();
509  db->next();
510 
511  this->ID = db->value(0).toInt();
512  GUID = db->value(1).toString();
513  experimentID = db->value(2).toInt();
514  this->runID = db->value(3).toString();
515  title = db->value(4).toString();
516  html = db->value(5).toString();
517  bool edittr = ! new_triple.isEmpty();
518 
519  // Now lets get all the report triple records
520  triples.clear();
521  q.clear();
522  q << "get_reportTriple_desc"
523  << QString::number( ID );
524  db->query( q );
525 
526  status = db->lastErrno();
527  if ( status == US_DB2::OK )
528  {
529  while ( db->next() )
530  {
532 
533  t.tripleID = db->value(0).toInt();
534  t.tripleGUID = db->value(1).toString();
535  t.resultID = db->value(2).toInt();
536  t.triple = db->value(3).toString();
537  t.dataDescription = db->value(4).toString();
538 
539  if ( edittr && t.triple != new_triple )
540  continue;
541 
542  triples << t;
543  }
544  }
545 
546  else if ( status != US_DB2::NOROWS )
547  return DB_ERROR;
548 
549  // Now cycle through and load all the document metadata
550  for ( int i = 0; i < triples.size(); i++ )
551  {
552  US_Report::Status writeStatus = triples[i].readDocsDB( db );
553  if ( writeStatus != REPORT_OK )
554  return writeStatus;
555  }
556 
557  return REPORT_OK;
558 }
559 
560 // Saves the global report information to DB
562 {
563  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
564  int status;
565  QString now = QDateTime::currentDateTime().toString();
566 
567  // First let's be sure we have a valid GUID
568  if ( ! rx.exactMatch( this->GUID ) )
569  this->GUID = US_Util::new_guid();
570 
571  // Find out if the runID is in the DB already
572  QString invID = QString::number( US_Settings::us_inv_ID() );
573  QStringList q( "get_reportID_by_runID" );
574  q << invID
575  << this->runID;
576  db->query( q );
577 
578  this->title = this->title.isEmpty()
579  ? this->runID + " Report"
580  : this->title;
581 
582  status = db->lastErrno();
583 
584  if ( status == US_DB2::OK )
585  {
586  // Update existing global report structure in the DB
587  db->next();
588  this->ID = db->value( 0 ).toInt();
589  this->html = "<p>Report updated " + now + "</p>";
590 
591  q.clear();
592  q << "update_report"
593  << QString::number( this->ID )
594  << this->title
595  << this->html;
596  db->query( q );
597 
598  int updateStatus = db->lastErrno();
599 
600  if ( updateStatus != US_DB2::OK )
601  {
602  qDebug() << "update_report error"
603  << updateStatus;
604  return DB_ERROR;
605  }
606  }
607 
608  else if ( status == US_DB2::NOROWS )
609  {
610  // Create a new global report structure in the DB
611  this->html = "<p>Report created " + now + "</p>";
612 
613  q.clear();
614  q << "new_report"
615  << this->GUID
616  << this->runID
617  << this->title
618  << this->html
619  << invID;
620  db->query( q );
621 
622  int newStatus = db->lastErrno();
623 
624  if ( newStatus != US_DB2::OK )
625  {
626  qDebug() << "new_report error"
627  << newStatus;
628  return DB_ERROR;
629  }
630 
631  this->ID = db->lastInsertID();
632  }
633 
634  else // some other database error
635  {
636  qDebug() << "get_reportID error"
637  << status;
638  return DB_ERROR;
639  }
640 
641  // Ensure that we have the experimentID
642  q.clear();
643  q << "get_report_info"
644  << QString::number( this->ID );
645  db->query( q );
646 
647  db->next();
648  this->experimentID = db->value(2).toInt();
649 
650  return REPORT_OK;
651 }
652 
653 // Function to add a new, empty triple record, both in the object and the DB
655  QString triple,
656  QString dataDescription,
657  US_DB2* db )
658 {
660 
661  d.triple = triple;
662  d.dataDescription = dataDescription;
663 
664  return this->addTriple( d, db );
665 }
666 
667 // Function to add or replace an entire triple
670  US_DB2* db )
671 {
672  int ndx = this->findTriple( t.triple );
673 
674  // Easier to delete/add the triple if it exists
675  if ( ndx != -1 )
676  this->removeTriple( ndx, db );
677 
678  this->triples << t;
679 
680  // Refresh ndx
681  ndx = this->findTriple( t.triple );
682 
683  return this->triples[ndx].saveDB( this->ID, db );
684 }
685 
686 // Function to remove a triple record, and all the documents
688  int ndx,
689  US_DB2* db )
690 {
691  QStringList q( "delete_reportTriple" );
692  q << QString::number( this->triples[ ndx ].tripleID );
693  db->query( q );
694 
695  int status = db->lastErrno();
696 
697  if ( status != US_DB2::OK )
698  return DB_ERROR;
699 
700  this->triples.remove( ndx );
701  return REPORT_OK;
702 }
703 
704 // Function to find the index of the triple that matches the
705 // supplied triple string
706 int US_Report::findTriple( QString searchTriple )
707 {
708  for ( int i = 0; i < this->triples.size(); i++ )
709  {
710  if ( this->triples[i].triple == searchTriple )
711  return i;
712  }
713 
714  // If we're here then the triple string we were searching for
715  // was not found
716  return -1;
717 }
718 
719 // Store a single reportDocument record.
720 // For example, dir = /home/user/ultrascan/reports/demo1_veloc
721 // and filename = 2dsa.2A260.tinoise.svg
723  const QString& filename, US_DB2* db, int idEdit,
724  const QString dataDescription )
725 {
726  // Parse the directory for the runID
727  QStringList parts = dir.split( "/" );
728  if ( parts.size() < 2 )
729  return US_Report::MISC_ERROR;
730 
731  QString new_runID = parts.last();
732  if ( new_runID.isEmpty() )
733  new_runID = parts[ parts.size() - 2 ];
734 
735  // Now parse the filename for the other information
736  parts.clear();
737  parts = filename.split( '.' );
738  if ( parts.size() != 4 )
739  return US_Report::MISC_ERROR;
740 
741  QString newAnal = parts[0];
742  QString newTriple = US_Util::expanded_triple( parts[1], false );
743  QString newSubanal = parts[2];
744  QString newDoctype = parts[3];
745 
746  // Create a label
747  QString newLabel = this->rTypes.appLabels[newAnal] + ":" +
748  this->rTypes.rptLabels[newSubanal] + ":" +
749  this->rTypes.extLabels[newDoctype] ;
750 
751  // Start by reading any DB info we have, or create new report
752  QString now = QDateTime::currentDateTime().toString();
753  US_Report::Status status = this->readDB( new_runID, db );
754 
755  if ( status == US_Report::NOT_FOUND )
756  {
757  US_Report::Status saveStatus = this->saveDB( db );
758  if ( saveStatus != US_Report::REPORT_OK )
759  {
760  qDebug() << "report.saveDB error"
761  << saveStatus;
762  qDebug() << db->lastError() << db->lastErrno();
763  this->show();
764  }
765  }
766 
767  // Read an existing triple, or create a new one
768  int tripNdx = this->findTriple( newTriple );
769  if ( tripNdx < 0 )
770  {
771  // Not found
772  status = this->addTriple( newTriple, dataDescription, db );
773  if ( status != US_Report::REPORT_OK )
774  {
775  qDebug() << "saveDocumentFromFile.addTriple error"
776  << status;
777  qDebug() << db->lastError() << db->lastErrno();
778  return US_Report::DB_ERROR;
779  }
780 
781  }
782 
783  else if ( this->triples[tripNdx].dataDescription != dataDescription )
784  {
785  // Then the data description field has changed and needs to be updated
786  this->triples[tripNdx].dataDescription = dataDescription;
787  this->triples[tripNdx].saveDB( this->ID, db );
788  }
789 
790  // Refresh tripNdx
791  tripNdx = this->findTriple( newTriple );
792  US_Report::ReportTriple t = this->triples[tripNdx];
793 
794  // Now find this document if it already exists
795  int docNdx = t.findDocument( newAnal, newSubanal, newDoctype );
796 
797 if(docNdx<0)
798 DbgLv(1) << "Doc::saveDB: NOT FOUND newDoctype" << newDoctype;
799  if ( docNdx < 0 && newDoctype.endsWith( "svgz" ) )
800  { // If SVGZ not found, test for SVG
801  docNdx = t.findDocument( newAnal, newSubanal, QString( "svg" ) );
802 DbgLv(1) << "Doc::saveDB: NOT FOUND svg docNdx" << docNdx;
803  }
804 
805  if ( docNdx < 0 )
806  {
807  // Not found
808  status = t.addDocument( idEdit,
809  newLabel,
810  dir,
811  filename,
812  newAnal,
813  newSubanal,
814  newDoctype,
815  db );
816  }
817 
818  else
819  {
820 DbgLv(1) << "Doc::saveDB: Replace ndx label" << docNdx << newLabel;
821  t.docs[ docNdx ].editedDataID = idEdit;
822  t.docs[ docNdx ].label = newLabel;
823  t.docs[ docNdx ].filename = filename;
824  t.docs[ docNdx ].documentType = newDoctype;
825 
826  status = t.docs[ docNdx ].saveDB( t.tripleID, dir, db );
827  if ( status != US_Report::REPORT_OK )
828  {
829  qDebug() << "saveDocumentFromFile.docs.saveDB error"
830  << status;
831  qDebug() << db->lastError() << db->lastErrno();
832  return US_Report::DB_ERROR;
833  }
834 
835  }
836 
837  // Refresh docNdx
838  docNdx = t.findDocument( newAnal, newSubanal, newDoctype );
839 
840  // Finally, update the triple
841  status = t.saveDB( this->ID, db );
842  this->triples[tripNdx] = t;
843 
844  //status = this->saveAllToDB( dir, db );
845  if ( status != US_Report::REPORT_OK )
846  return status;
847 
848  return US_Report::REPORT_OK;
849 }
850 
851 // Saves a list of report document records to DB
853  const QStringList& filepaths, US_DB2* db, int idEdit,
854  const QString dataDescription )
855 {
856  // Get the runID by parsing the directory
857  QString new_runID = QString( dir ).section( "/", -1, -1 );
858  if ( new_runID.isEmpty() )
859  return US_Report::MISC_ERROR;
860 
861  // Parse the triple string from the first filename
862  int nfiles = filepaths.count();
863 
864  if ( nfiles < 1 )
865  return US_Report::MISC_ERROR;
866 
867  QStringList filenames;
868  for ( int jj = 0; jj < nfiles; jj++ )
869  filenames << QString( filepaths[ jj ] ).section( "/", -1, -1 );
870 
871  QString filename = filenames[ 0 ];
872  QString newTriple = filename.section( '.', -3, -3 );
873  newTriple = US_Util::expanded_triple( newTriple, false );
874 
875  // Get any existing report for this run
876  // Start by reading any DB info we have, or create new report
877  QString now = QDateTime::currentDateTime().toString();
878  US_Report::Status status = this->readDB( new_runID, db, newTriple );
879 
880  if ( status == US_Report::NOT_FOUND )
881  { // For a new report, save what we have
882  US_Report::Status saveStatus = this->saveDB( db );
883  if ( saveStatus != US_Report::REPORT_OK )
884  {
885  qDebug() << "report.saveDB error"
886  << saveStatus;
887  qDebug() << db->lastError() << db->lastErrno();
888  this->show();
889  }
890  }
891 
892  // Read an existing triple, or create a new one
893  int tripNdx = this->findTriple( newTriple );
894  if ( tripNdx < 0 )
895  {
896  // Not found, so create one
897  status = this->addTriple( newTriple, dataDescription, db );
898  if ( status != US_Report::REPORT_OK )
899  {
900  qDebug() << "saveDocumentFromFile.addTriple error"
901  << status;
902  qDebug() << db->lastError() << db->lastErrno();
903  return US_Report::DB_ERROR;
904  }
905  // Refresh tripNdx
906  tripNdx = this->findTriple( newTriple );
907  }
908 
909  else if ( this->triples[ tripNdx ].dataDescription != dataDescription )
910  { // The data description field has changed and needs to be updated
911  this->triples[ tripNdx ].dataDescription = dataDescription;
912  this->triples[ tripNdx ].saveDB( this->ID, db );
913  }
914 
915  US_Report::ReportTriple* trip = &this->triples[ tripNdx ];
916 
917  // Build a list of documents already assigned to the triple
918  QStringList tdnames;
919  QList< int > tdNdxs;
920  QString filepath;
921  QString dirfile = dir.endsWith( "/" ) ? dir : ( dir + "/" );
922  int ntdocs = trip->docs.count();
923  int idTrip = trip->tripleID;
924 
925  for ( int ii = 0; ii < ntdocs; ii++ )
926  {
927  filename = trip->docs[ ii ].filename;
928  int tidEdit = trip->docs[ ii ].editedDataID;
929 
930  if ( tidEdit == idEdit && filenames.contains( filename ) )
931  {
932  tdnames << filename;
933  tdNdxs << ii;
934  }
935  }
936 
937  // Add any new documents to the triple's list
938  if ( tdNdxs.count() < nfiles )
939  {
940  for ( int ii = 0; ii < nfiles; ii++ )
941  { // Examine each specified file name
942  filename = filenames[ ii ];
943 
944  if ( !tdnames.contains( filename ) )
945  { // This document is new and needs to be added to the triple's list
947  QString newAnal = filename.section( ".", -4, -4 );
948  QString newSubanal = filename.section( ".", -2, -2 );
949  QString newDoctype = filename.section( ".", -1, -1 );
950  QString newLabel = this->rTypes.appLabels[ newAnal ] + ":" +
951  this->rTypes.rptLabels[ newSubanal ] + ":" +
952  this->rTypes.extLabels[ newDoctype ];
953  QString docGUID = US_Util::new_guid();
954 
955  rdoc.documentGUID = docGUID; // Build report doc
956  rdoc.label = newLabel;
957  rdoc.filename = filename;
958  rdoc.analysis = newAnal;
959  rdoc.subAnalysis = newSubanal;
960  rdoc.documentType = newDoctype;
961  rdoc.editedDataID = idEdit;
962 
963  QStringList qry( "new_reportDocument" ); // Create new doc record
964  qry << QString::number( idTrip )
965  << docGUID
966  << QString::number( idEdit )
967  << newLabel
968  << filename
969  << newAnal
970  << newSubanal
971  << newDoctype;
972  db->query( qry );
973 
974  int ndstat = db->lastErrno();
975  if ( ndstat != US_DB2::OK )
976  {
977  qDebug() << "new_reportDocument error"
978  << ndstat << db->lastError();
979  return US_Report::DB_ERROR;
980  }
981 
982  rdoc.documentID = db->lastInsertID(); // Save doc DB Id
983 
984  trip->docs << rdoc; // Add to triple's docs
985 
986  tdnames << filename; // Save doc file name
987  tdNdxs << ntdocs; // Save index in doc list
988  ntdocs++; // Bump triple's doc count
989  }
990  }
991  }
992 
993  // Update the contents of each of the specified report documents
994  for ( int ii = 0; ii < nfiles; ii++ )
995  {
996  filepath = filepaths[ ii ];
997  filename = filenames[ ii ];
998  int tdnamx = tdnames.indexOf( filename );
999 
1000  if ( tdnamx < 0 )
1001  {
1002  qDebug() << "upload_reportContents TDNAMX error"
1003  << filename;
1004  return US_Report::MISC_ERROR;
1005  }
1006 
1007  int tdndx = tdNdxs[ tdnamx ];
1008  int idDoc = trip->docs[ tdndx ].documentID;
1009 
1010  int wrstat = db->writeBlobToDB( filepath,
1011  QString( "upload_reportContents" ), idDoc );
1012 
1013  if ( wrstat != US_DB2::OK )
1014  {
1015  qDebug() << "upload_reportContents error"
1016  << wrstat << db->lastError();
1017  return US_Report::DB_ERROR;
1018  }
1019  }
1020 
1021  return US_Report::REPORT_OK;
1022 }
1023 
1024 // Function to remove an entire report structure, all the triples, and all the documents
1026  int reportID,
1027  US_DB2* db )
1028 {
1029  QStringList q( "delete_report" );
1030  q << QString::number( reportID );
1031  db->query( q );
1032 
1033  int status = db->lastErrno();
1034 
1035  if ( status != US_DB2::OK )
1036  return DB_ERROR;
1037 
1038  this->reset();
1039  return REPORT_OK;
1040 }
1041 
1042 // Saves an entire report structure to DB
1044 {
1045  US_Report::Status status = this->saveDB( db );
1046  if ( status != US_Report::REPORT_OK )
1047  {
1048  qDebug() << "report.saveDB error"
1049  << status;
1050  }
1051 
1052  foreach( US_Report::ReportTriple triple, this->triples )
1053  {
1054  status = triple.saveDB( this->ID, db );
1055  if ( status != US_Report::REPORT_OK )
1056  {
1057  qDebug() << "triple.saveDB error"
1058  << status;
1059  }
1060 
1061  foreach ( US_Report::ReportDocument doc, triple.docs )
1062  {
1063  status = doc.saveDB( triple.tripleID, dir, db );
1064  if ( status != US_Report::REPORT_OK )
1065  {
1066  qDebug() << "document.saveDB error"
1067  << status;
1068  }
1069  }
1070  }
1071 
1072  return REPORT_OK;
1073 }
1074 
1075 // Function to clear out the entire report structure
1076 void US_Report::reset( void )
1077 {
1078  ID = -1;
1079  GUID = "";
1080  experimentID = -1;
1081  runID = "";
1082  title = "";
1083  html = "";
1085 
1086  triples.clear();
1087 }
1088 
1089 // Function to show the current values of the class variables
1090 void US_Report::show( void )
1091 {
1092  qDebug() << "ID = " << ID ;
1093  qDebug() << "GUID = " << GUID ;
1094  qDebug() << "experimentID = " << experimentID ;
1095  qDebug() << "runID = " << runID ;
1096  qDebug() << "title = " << title ;
1097  qDebug() << "html = " << html ;
1098  qDebug() << "";
1099 
1100  if ( triples.size() > 0 )
1101  {
1102  qDebug() << "Triples:";
1103  foreach ( US_Report::ReportTriple triple, triples )
1104  triple.show();
1105  }
1106 }
1107