UltraScan III
us_solution.cpp
Go to the documentation of this file.
1 
3 #include <QtCore>
4 
5 #include "us_settings.h"
6 #include "us_db2.h"
7 #include "us_util.h"
8 #include "us_solution.h"
9 #include "us_buffer.h"
10 #include "us_analyte.h"
11 #include "us_math2.h"
12 
13 // The constructor clears out the data structure
15 {
16  clear();
17 }
18 
19 // Function to load a solution from the disk
20 int US_Solution::readFromDisk( QString& guid )
21 {
22  QString filename;
23  bool found = diskFilename( guid, filename );
24 
25  if ( ! found )
26  {
27  qDebug() << "Error: solution file not found - guid "
28  << guid;
29  return US_DB2::NO_SOLUTION;
30  }
31 
32  QFile file( filename );
33  if ( !file.open( QIODevice::ReadOnly | QIODevice::Text) )
34  {
35  qDebug() << "Error: can't open file for reading"
36  << filename;
37  return US_DB2::NO_SOLUTION;
38  }
39 
40  QXmlStreamReader xml( &file );
41 
42  clear();
43 
44  while ( ! xml.atEnd() )
45  {
46  xml.readNext();
47 
48  if ( xml.isStartElement() )
49  {
50  if ( xml.name() == "solution" )
51  {
52  QXmlStreamAttributes a = xml.attributes();
53  solutionID = a.value( "id" ).toString().toInt();
54  solutionGUID = a.value( "guid" ).toString();
55  commonVbar20 = a.value( "commonVbar20" ).toString().toDouble();
56  storageTemp = a.value( "storageTemp" ).toString().toDouble();
57 
58  readSolutionInfo( xml );
59  }
60  }
61  }
62 
63  file.close();
64 
65  if ( xml.hasError() )
66  {
67  qDebug() << "Error: xml error: \n"
68  << xml.errorString();
69  return US_DB2::ERROR;
70  }
71 
72  // Load actual buffer and analyte files if we can find them
73  US_Buffer newBuffer;
74  int status = readBufferDiskGUID( newBuffer, buffer.GUID );
75 
76  if ( status != US_DB2::OK ) // Probably US_DB2::NO_BUFFER
77  return status;
78 
79  // Then we found the actual buffer.xml file
80  buffer = newBuffer;
81 
82  for ( int i = 0; i < analyteInfo.size(); i++ )
83  {
84  AnalyteInfo newInfo;
85  status = newInfo.analyte.load( false, analyteInfo[ i ].analyte.analyteGUID );
86 
87  if ( status != US_DB2::OK ) // Probably US_DB2::NO_ANALYTE
88  return status;
89 
90  // Found the analyte.xml file
91  newInfo.amount = analyteInfo[ i ].amount;
92  analyteInfo[ i ] = newInfo;
93  }
94 
96 
97  return US_DB2::OK;
98 }
99 
100 void US_Solution::readSolutionInfo( QXmlStreamReader& xml )
101 {
102  buffer.GUID = "";
103 
104  while ( ! xml.atEnd() )
105  {
106  xml.readNext();
107 
108  if ( xml.isEndElement() && xml.name() == "solution" ) return;
109 
110  if ( xml.isStartElement() )
111  {
112  if ( xml.name() == "description" )
113  {
114  xml.readNext();
115  solutionDesc = xml.text().toString();
116  }
117 
118  else if ( xml.name() == "notes" )
119  {
120  xml.readNext();
121  notes = xml.text().toString();
122  }
123 
124  else if ( xml.name() == "buffer" )
125  {
126  QXmlStreamAttributes a = xml.attributes();
127  buffer.bufferID = a.value( "id" ) .toString();
128  buffer.GUID = a.value( "guid" ).toString();
129  buffer.description = a.value( "desc" ).toString();
130  }
131 
132  else if ( xml.name() == "analyte" )
133  {
134  AnalyteInfo ai;
135 
136  QXmlStreamAttributes a = xml.attributes();
137  ai.analyte.analyteID = a.value( "id" ).toString();
138  ai.analyte.analyteGUID = a.value( "guid" ).toString();
139  ai.analyte.description = a.value( "desc" ).toString();
140  ai.amount = a.value( "amount" ).toString().toDouble();
141  ai.analyte.mw = a.value( "mw" ).toString().toDouble();
142  ai.analyte.vbar20 = a.value( "vbar20" ).toString().toDouble();
143  QString typetext = a.value( "type" ).toString();
145  analyte_type( typetext );
146 
147  analyteInfo << ai;
148 
149  }
150  }
151  }
152 }
153 
154 // Function to load a solution from the db
155 int US_Solution::readFromDB ( int solutionID, US_DB2* db )
156 {
157  // Try to get solution info
158  QStringList q( "get_solution" );
159  q << QString::number( solutionID );
160  db->query( q );
161 
162  clear();
163 
164  if ( db->next() )
165  {
166  this->solutionID = solutionID;
167  solutionGUID = db->value( 0 ).toString();
168  solutionDesc = db->value( 1 ).toString();
169  commonVbar20 = db->value( 2 ).toDouble();
170  storageTemp = db->value( 3 ).toDouble();
171  notes = db->value( 4 ).toString();
172 
173  q.clear();
174  q << "get_solutionBuffer"
175  << QString::number( solutionID );
176  db->query( q );
177  if ( db->next() )
178  {
179  buffer.bufferID = db->value( 0 ).toString();
180  buffer.GUID = db->value( 1 ).toString();
181  buffer.description = db->value( 2 ).toString();
182  }
183 
184  if ( ! buffer.readFromDB( db, buffer.bufferID ) )
185  return US_DB2::NO_BUFFER;
186 
187  // We need to get a list of analyteGUID's and amounts first
188  q.clear();
189  q << "get_solutionAnalyte"
190  << QString::number( solutionID );
191  db->query( q );
192 
193  QList< QString > GUIDs;
194  QList< double > amounts;
195  while ( db->next() )
196  {
197  GUIDs << db->value( 1 ).toString();
198  amounts << db->value( 3 ).toDouble();
199  }
200 
201  // Now get the rest of the analyte info
202  for ( int i = 0; i < GUIDs.size(); i++ )
203  {
204  AnalyteInfo newInfo;
205 
206  int status = newInfo.analyte.load( true, GUIDs[ i ], db );
207  if ( status != US_DB2::OK )
208  return US_DB2::NO_ANALYTE;
209 
210  newInfo.amount = amounts[ i ];
211  analyteInfo << newInfo;
212  }
213  }
214 
216 
217  return US_DB2::OK;
218 }
219 
220 // Function to save solution information to disk
222 {
223  // First make sure we have a GUID
224  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}$" );
225 
226  if ( ! rx.exactMatch( solutionGUID ) )
228 
229  // Get a path and file name for solution
230  QString path;
231  if ( ! diskPath( path ) ) return;
232 
233  bool newFile;
234  QString filename = get_filename(
235  path,
236  newFile );
237 
238  QFile file( filename );
239  if ( !file.open( QIODevice::WriteOnly | QIODevice::Text) )
240  {
241  qDebug() << "Error: can't open file for writing"
242  << filename;
243  return;
244  }
245 
246  if ( commonVbar20 == 0 ||
247  solutionDesc.isEmpty() ||
248  buffer.GUID.isEmpty() ||
249  buffer.bufferID.isEmpty() ||
250  buffer.bufferID.toInt() < 0 )
251  {
252  qDebug() << "Error: Solution cannot be written to disk,"
253  << " due to invalid values:";
254  qDebug() << " commonVbar20" << commonVbar20;
255  qDebug() << " solutionDesc" << solutionDesc;
256  qDebug() << " bufferGUID" << buffer.GUID;
257  qDebug() << " bufferID" << buffer.bufferID;
258  return;
259  }
260 
261  // Generate xml
262  QXmlStreamWriter xml;
263  xml.setDevice( &file );
264  xml.setAutoFormatting( true );
265 
266  xml.writeStartDocument();
267  xml.writeDTD("<!DOCTYPE US_Solution>");
268  xml.writeStartElement("SolutionData");
269  xml.writeAttribute("version", "1.0");
270 
271  // elements
272  xml.writeStartElement( "solution" );
273  xml.writeAttribute ( "id", QString::number( solutionID ) );
274  xml.writeAttribute ( "guid", solutionGUID );
275  xml.writeAttribute ( "commonVbar20", QString::number( commonVbar20 ) );
276  xml.writeAttribute ( "storageTemp", QString::number( storageTemp ) );
277  xml.writeTextElement ( "description", solutionDesc );
278  xml.writeTextElement ( "notes", notes );
279 
280  xml.writeStartElement( "buffer" );
281  xml.writeAttribute ( "id", buffer.bufferID );
282  xml.writeAttribute ( "guid", buffer.GUID );
283  xml.writeAttribute ( "desc", buffer.description );
284  xml.writeEndElement ();
285 
286  // Loop through all the analytes
287  for ( int i = 0; i < analyteInfo.size(); i++ )
288  {
289  AnalyteInfo ai = analyteInfo[ i ];
290 
291  xml.writeStartElement( "analyte" );
292  xml.writeAttribute ( "id", ai.analyte.analyteID );
293  xml.writeAttribute ( "guid", ai.analyte.analyteGUID );
294  xml.writeAttribute ( "desc", ai.analyte.description );
295  xml.writeAttribute ( "amount", QString::number( ai.amount ) );
296  xml.writeAttribute ( "mw", QString::number( ai.analyte.mw ) );
297  xml.writeAttribute ( "vbar20", QString::number( ai.analyte.vbar20 ) );
298  xml.writeAttribute ( "type", analyte_typetext( (int)ai.analyte.type ) );
299  xml.writeEndElement ();
300  }
301 
302  xml.writeEndElement (); // solution
303  xml.writeEndDocument ();
304 
305  file.close();
306 
307  // Save the buffer and analytes to disk
308  saveBufferDisk();
310 
312 }
313 
314 // Function to save solution information to db
315 int US_Solution::saveToDB( int expID, int channelID, US_DB2* db )
316 {
317  QStringList q;
318  int status;
319 
320  // Save to disk too
321  saveToDisk();
322 
323  if ( ! buffer.GUID.isEmpty() )
324  {
325  // Let's see if the buffer is in the db already
326  q << "get_bufferID";
327  q << buffer.GUID;
328  db->query( q );
329 
330  status = db->lastErrno();
331  if ( status == US_DB2::NOROWS )
332  buffer.saveToDB( db, QString::number( 1 ) ); // 1 = private
333 
334  else if ( status != US_DB2::OK )
335  return status;
336  }
337 
338  // Now let's see if the analytes are in the db already
339  foreach( AnalyteInfo newInfo, analyteInfo )
340  {
341  q.clear();
342  q << "get_analyteID"
343  << newInfo.analyte.analyteGUID;
344  db->query( q );
345 
346  status = db->lastErrno();
347  if ( status == US_DB2::NOROWS )
348  newInfo.analyte.write( true, "", db );
349 
350  else if ( status != US_DB2::OK )
351  return status;
352  }
353 
354  // Make sure we have a solutionGUID
355  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}$" );
356  if ( ! rx.exactMatch( solutionGUID ) )
358 
359  // Check for solutionGUID in database
360  solutionID = 0;
361  q.clear();
362  q << "get_solutionID_from_GUID"
363  << solutionGUID;
364  db->query( q );
365 
366  status = db->lastErrno();
367  if ( status == US_DB2::OK )
368  {
369  // Edit existing solution entry
370  db->next();
371  solutionID = db->value( 0 ).toInt();
372  q.clear();
373  q << "update_solution"
374  << QString::number( solutionID )
375  << solutionGUID
376  << solutionDesc
377  << QString::number( commonVbar20 )
378  << QString::number( storageTemp )
379  << notes;
380 
381  db->statusQuery( q );
382  }
383 
384  else if ( status == US_DB2::NOROWS )
385  {
386  // Create new solution entry
387  q.clear();
388  q << "new_solution"
389  << solutionGUID
390  << solutionDesc
391  << QString::number( commonVbar20 )
392  << QString::number( storageTemp )
393  << notes
394  << QString::number( expID )
395  << QString::number( channelID )
396  << QString::number( US_Settings::us_inv_ID() );
397 
398  db->statusQuery( q );
399  solutionID = db->lastInsertID();
400  }
401 
402  else // unspecified error
403  {
404  qDebug() << "MySQL error: " << db->lastError();
405  return status;
406  }
407 
408  if ( solutionID == 0 ) // double check
409  return US_DB2::NO_SOLUTION;
410 
411  if ( ! buffer.GUID.isEmpty() )
412  {
413  // new_solutionBuffer will Remove existing buffer associations,
414  // and associate the solution with this buffer
415  q.clear();
416  q << "new_solutionBuffer"
417  << QString::number( solutionID )
418  << QString( "" ) // skip bufferID and use GUID instead
419  << buffer.GUID;
420 
421  status = db->statusQuery( q );
422  if ( status != US_DB2::OK )
423  {
424  qDebug() << "MySQL error associating buffer with solution in database:"
425  << db->lastError();
426  return status;
427  }
428  }
429 
430  // Remove analyte associations; we'll create new ones
431  q.clear();
432  q << "delete_solutionAnalytes"
433  << QString::number( solutionID );
434 
435  status = db->statusQuery( q );
436  if ( status != US_DB2::OK )
437  qDebug() << "MySQL error: " << db->lastError();
438 
439  // Now add zero or more analyte associations
440  for ( int i = 0; i < analyteInfo.size(); i++ )
441  {
442  AnalyteInfo newInfo = analyteInfo[ i ];
443 
444  q.clear();
445  q << "new_solutionAnalyte"
446  << QString::number( solutionID )
447  << QString( "" ) // skip analyteID and use GUID instead
448  << newInfo.analyte.analyteGUID
449  << QString::number( newInfo.amount );
450 
451  status = db->statusQuery( q );
452  if ( status != US_DB2::OK )
453  {
454  qDebug() << "MySQL error associating analyte "
455  << newInfo.analyte.analyteGUID
456  << " with solution "
457  << solutionGUID
458  << " in database: "
459  << db->lastError();
460  return status;
461  }
462  }
463 
464  saveStatus = BOTH;
465 
466  return US_DB2::OK;
467 }
468 
469 int US_Solution::readBufferDiskGUID( US_Buffer& buffer, QString& GUID )
470 {
471  // Find the buffer directory on disk
472  QDir dir;
473  QString path = US_Settings::dataDir() + "/buffers";
474 
475  if ( ! dir.exists( path ) )
476  return US_DB2::NO_BUFFER; // So we have some idea of what happened
477 
478  // Try to find the buffer file
479  bool newFile;
480  QString filename = US_Buffer::get_filename( path, GUID, newFile );
481 
482  if ( newFile )
483  return US_DB2::NO_BUFFER;
484 
485  // Then we can add it
486  bool diskStatus = buffer.readFromDisk( filename ); // load it from disk
487 
488  return ( diskStatus ) ? US_DB2::OK : US_DB2::NO_BUFFER;
489 }
490 
492 {
493  if ( buffer.GUID.isEmpty() ) return;
494 
495  // Find the buffer directory on disk
496  QDir dir;
497  QString path = US_Settings::dataDir() + "/buffers";
498 
499  if ( ! dir.exists( path ) )
500  {
501  if ( ! dir.mkpath( path ) )
502  {
503  qDebug() << "Error: Could not create default directory for buffers\n"
504  << path;
505  return ;
506  }
507  }
508 
509  // Find the buffer file, or create a new one
510  bool newFile;
511  QString filename = US_Buffer::get_filename( path, buffer.GUID, newFile );
512 
513  if ( newFile )
514  {
515  bool diskStatus = buffer.writeToDisk( filename );
516 
517  if ( diskStatus == false )
518  qDebug() << "Buffer write to disk error";
519  }
520 }
521 
523 {
524  // Find the analyte directory on disk
525  QDir dir;
526  QString path = US_Settings::dataDir() + "/analytes";
527 
528  if ( ! dir.exists( path ) )
529  {
530  if ( ! dir.mkpath( path ) )
531  {
532  qDebug() << "Error: Could not create default directory for analytes\n"
533  << path;
534  return;
535  }
536  }
537 
538 
539  foreach ( AnalyteInfo ai, analyteInfo )
540  {
541  // Find the analyte file, or create a new one
542  QString filename = US_Analyte::get_filename( path, ai.analyte.analyteGUID );
543  int status = ai.analyte.write( false, filename );
544 
545  if ( status != US_DB2::OK )
546  {
547  qDebug() << "Analyte " << ai.analyte.analyteGUID
548  << " write to disk error " << status;
549  }
550  }
551 }
552 
553 // Function to delete a solution from disk
555 {
556  int status = US_DB2::OK;
557  QString filename;
558  bool found = diskFilename( solutionGUID, filename );
559 
560  if ( ! found )
561  {
562  // No file to delete
563  return US_DB2::NO_SOLUTION;
564  }
565 
566  if ( solutionInUse( solutionGUID ) )
567  return US_DB2::SOLUT_IN_USE;
568 
569  // Delete it
570  QFile file( filename );
571  if ( file.exists() )
572  file.remove();
573 
575  return status;
576 }
577 
578 // Function to delete a solution from db
580 {
581  int status = US_DB2::OK;
582  QStringList q;
583  if ( solutionID == 0 )
584  {
585  // Then probably user selected from disk but is trying to delete from db,
586  // so let's try to get the db solutionID from the GUID
587  q.clear();
588  q << "get_solutionID_from_GUID"
589  << solutionGUID;
590  db->query( q );
591 
592  if ( db->next() )
593  solutionID = db->value( 0 ).toInt();
594 
595  }
596 
597  if ( solutionID > 0 ) // otherwise it's not there to delete
598  {
599  q.clear();
600  q << "delete_solution"
601  << QString::number( solutionID );
602 
603  status = db->statusQuery( q );
604 
605  if ( status == US_DB2::SOLUT_IN_USE )
606  return status;
607 
608  if ( status != US_DB2::OK )
609  qDebug() << "MySQL error: " << db->lastError();
610 
611  }
612 
614  return status;
615 }
616 
617 // Function to find the file name of a solution on disk, if it exists
618 bool US_Solution::diskFilename( const QString& guid, QString& filename )
619 {
620  // Get a path and file name for solution
621  QString path;
622  if ( ! diskPath( path ) )
623  {
624  qDebug() << "Error: could not create the solutions directory";
625  return false;
626  }
627 
628  QDir dir( path );
629  QStringList filter( "S*.xml" );
630  QStringList names = dir.entryList( filter, QDir::Files, QDir::Name );
631  bool found = false;
632 
633  for ( int i = 0; i < names.size(); i++ )
634  {
635  filename = path + "/" + names[ i ];
636  QFile file( filename );
637 
638  if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text) ) continue;
639 
640  QXmlStreamReader xml( &file );
641 
642  while ( ! xml.atEnd() )
643  {
644  xml.readNext();
645 
646  if ( xml.isStartElement() )
647  {
648  if ( xml.name() == "solution" )
649  {
650  QXmlStreamAttributes a = xml.attributes();
651 
652  if ( a.value( "guid" ).toString() == guid ) found = true;
653  break;
654  }
655  }
656  }
657 
658  file.close();
659  if ( found ) break; // Break out of this loop too
660  }
661 
662  if ( ! found )
663  {
664  filename = QString( "" );
665  return false;
666  }
667 
668  return true;
669 }
670 
671 // Get the path to the solutions. Create it if necessary.
672 bool US_Solution::diskPath( QString& path )
673 {
674  QDir dir;
675  path = US_Settings::dataDir() + "/solutions";
676 
677  if ( ! dir.exists( path ) )
678  {
679  if ( ! dir.mkpath( path ) )
680  {
681  qDebug() << "Error: Could not create default directory for solutions\n"
682  << path;
683  return false;
684  }
685  }
686 
687  return true;
688 }
689 
690 // Function to check if filename already exists, and perhaps generate a new one
692  const QString& path, bool& newFile )
693 {
694  QDir f( path );
695  QStringList filter( "S???????.xml" );
696  QStringList f_names = f.entryList( filter, QDir::Files, QDir::Name );
697  QString filename;
698  newFile = true;
699 
700  for ( int i = 0; i < f_names.size(); i++ )
701  {
702  QFile b_file( path + "/" + f_names[ i ] );
703 
704  if ( ! b_file.open( QIODevice::ReadOnly | QIODevice::Text) ) continue;
705 
706  QXmlStreamReader xml( &b_file );
707 
708  while ( ! xml.atEnd() )
709  {
710  xml.readNext();
711 
712  if ( xml.isStartElement() )
713  {
714  if ( xml.name() == "solution" )
715  {
716  QXmlStreamAttributes a = xml.attributes();
717 
718  if ( a.value( "guid" ).toString() == solutionGUID )
719  {
720  newFile = false;
721  filename = path + "/" + f_names[ i ];
722  }
723 
724  break;
725  }
726  }
727  }
728 
729  b_file.close();
730  if ( ! newFile ) return filename;
731  }
732 
733  // If we get here, generate a new filename
734  int number = ( f_names.size() > 0 ) ? f_names.last().mid( 1, 7 ).toInt() : 0;
735 
736  return path + "/S" + QString().sprintf( "%07i", number + 1 ) + ".xml";
737 }
738 
740 {
741  amount = 1;
742 }
743 
745 {
746  if (! ( analyte == rhs.analyte ) ) return false;
747  if ( amount != rhs.amount ) return false;
748 
749  return true;
750 }
751 
753 {
754  if ( this != &rhs ) // guard against self assignment
755  {
756  clear();
757 
758  solutionID = rhs.solutionID;
761  buffer = rhs.buffer;
763  storageTemp = rhs.storageTemp;
764  notes = rhs.notes;
765  saveStatus = rhs.saveStatus;
766 
767  for ( int i = 0; i < rhs.analyteInfo.size(); i++ )
768  analyteInfo << rhs.analyteInfo[ i ];
769  }
770 
771  return *this;
772 }
773 
774 void US_Solution::clear( void )
775 {
776  solutionID = 0;
777  solutionGUID = QString( "" );
778  solutionDesc = QString( "" );
779  buffer.bufferID = QString( "-1" );
780  buffer.GUID = QString( "" );
781  buffer.description = QString( "" );
782  buffer.density = 0.0;
783  buffer.viscosity = 0.0;
784  commonVbar20 = 0.0;
785  storageTemp = 20.0;
786  notes = QString( "" );
788  analyteInfo.clear();
789 }
790 
791 void US_Solution::show( void )
792 {
793  qDebug() << "solutionID = " << solutionID << '\n'
794  << "solutionGUID = " << solutionGUID << '\n'
795  << "solutionDesc = " << solutionDesc << '\n'
796  << "bufferID = " << buffer.bufferID << '\n'
797  << "buffer GUID = " << buffer.GUID << '\n'
798  << "buffer Desc = " << buffer.description << '\n'
799  << "buffer density = " << buffer.density << '\n'
800  << "buffer viscosity = " << buffer.viscosity << '\n'
801  << "commonVbar20 = " << commonVbar20 << '\n'
802  << "storageTemp = " << storageTemp << '\n'
803  << "notes = " << notes << '\n'
804  << "saveStatus = " << saveStatus << '\n';
805 
806  qDebug() << "Analytes...";
807  qDebug() << "Analytes size = " << QString::number( analyteInfo.size() );
808  for ( int i = 0; i < analyteInfo.size(); i++ )
809  {
810  AnalyteInfo ai = analyteInfo[ i ];
811 
812  QString typetext = analyte_typetext( (int)ai.analyte.type );
813 
814  qDebug() << "analyteID = " << ai.analyte.analyteID << '\n'
815  << "analyteGUID = " << ai.analyte.analyteGUID << '\n'
816  << "description = " << ai.analyte.description << '\n'
817  << "vbar20 = " << ai.analyte.vbar20 << '\n'
818  << "type = " << typetext << '\n'
819  << "mw = " << ai.analyte.mw << '\n'
820  << "amount = " << ai.amount << '\n';
821  }
822 }
823 
824 int US_Solution::analyte_type( QString antype )
825 {
827 
828  if ( antype == "Protein" )
829  type = US_Analyte::PROTEIN;
830  else if ( antype == "DNA" )
831  type = US_Analyte::DNA;
832  else if ( antype == "RNA" )
833  type = US_Analyte::RNA;
834  else if ( antype == "Other" )
836 
837  return (int)type;
838 }
839 
840 QString US_Solution::analyte_typetext( int type )
841 {
842  QString antype = "Protein";
843 
844  if ( type == (int)US_Analyte::PROTEIN )
845  antype = "Protein";
846  else if ( type == (int)US_Analyte::DNA )
847  antype = "DNA";
848  else if ( type == (int)US_Analyte::RNA )
849  antype = "RNA";
850  else if ( type == (int)US_Analyte::CARBOHYDRATE )
851  antype = "Other";
852 
853  return antype;
854 }
855 
856 // Function to determine if a solution is used by any experiment
858 {
859  bool in_use = false;
860 
861  QString resdir = US_Settings::resultDir();
862  QStringList expdirs = QDir( resdir )
863  .entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name );
864  resdir = resdir + "/";
865 
866  for ( int ii = 0; ii < expdirs.size(); ii++ )
867  {
868  QString subdir = resdir + expdirs.at( ii );
869  QStringList expfilt;
870  expfilt << expdirs.at( ii ) + ".*.xml";
871  QStringList expfiles = QDir( subdir )
872  .entryList( QDir::Files, QDir::Name );
873  subdir = subdir + "/";
874 
875  for ( int jj = 0; jj < expfiles.size(); jj++ )
876  {
877  QString fname = subdir + expfiles.at( jj );
878  QFile xfile( fname );
879  if ( ! xfile.open( QIODevice::ReadOnly ) )
880  continue;
881 
882  QXmlStreamReader xml( &xfile );
883 
884  while ( ! xml.atEnd() )
885  {
886  xml.readNext();
887 
888  if ( xml.isStartElement() && xml.name() == "solution" )
889  {
890  QXmlStreamAttributes atts = xml.attributes();
891  QString guid = atts.value( "guid" ).toString();
892 
893  if ( guid == solutionGUID )
894  {
895  in_use = true;
896  break;
897  }
898  }
899  }
900 
901  xfile.close();
902 
903  if ( in_use ) break;
904  }
905 
906  if ( in_use ) break;
907  }
908 
909  return in_use;
910 }
911