UltraScan III
us_buffer_gui.cpp
Go to the documentation of this file.
1 #include "us_buffer_gui.h"
3 #include "us_gui_settings.h"
4 #include "us_settings.h"
5 #include "us_db2.h"
6 #include "us_passwd.h"
7 #include "us_constants.h"
8 #include "us_investigator.h"
9 #include "us_table.h"
10 #include "us_util.h"
11 #include "us_math2.h"
12 
14  bool signal_wanted,
15  const US_Buffer& buf,
16  int select_db_disk
17  ) : US_WidgetsDialog( 0, 0 ), signal( signal_wanted ), buffer( buf )
18 {
20  bufferCurrent = false;
21  manualUpdate = false;
22  view_shared = false;
23 
25 
26  setWindowTitle( tr( "Buffer Management" ) );
27  setPalette( US_GuiSettings::frameColor() );
28  setAttribute( Qt::WA_DeleteOnClose );
29 
31 
32  // Very light gray for read only line edit widgets
33  gray = normal;
34  gray.setColor( QPalette::Base, QColor( 0xe0, 0xe0, 0xe0 ) );
35 
36  int row = 0;
37 
38  QGridLayout* main = new QGridLayout( this );
39  main->setSpacing ( 2 );
40  main->setContentsMargins ( 2, 2, 2, 2 );
41 
42  QStringList DB = US_Settings::defaultDB();
43  if ( DB.isEmpty() ) DB << "Undefined";
44  QLabel* lb_DB = us_banner( tr( "Database: " ) + DB.at( 0 ) );
45  lb_DB->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
46  main->addWidget( lb_DB, row++, 0, 1, 3 );
47 
48  QPushButton* pb_investigator = us_pushbutton( tr( "Select Investigator" ) );
49  connect( pb_investigator, SIGNAL( clicked() ), SLOT( sel_investigator() ) );
50  main->addWidget( pb_investigator, row++, 0 );
51 
52  if ( US_Settings::us_inv_level() < 1 )
53  pb_investigator->setEnabled( false );
54 
55  QBoxLayout* lo_search = new QHBoxLayout;
56 
57  // Search
58  QLabel* lb_search = us_label( tr( "Search:" ) );
59  lo_search->addWidget( lb_search );
60 
62  le_search->setReadOnly( true );
63  connect( le_search, SIGNAL( textChanged( const QString& ) ),
64  SLOT ( search ( const QString& ) ) );
65  lo_search->addWidget( le_search );
66  main->addLayout( lo_search, row++, 0 );
67 
68  // Buffer descriptions from DB
69  QLabel* lb_banner1 = us_banner(
70  tr( "Doubleclick on buffer data to select" ), -2 );
71  lb_banner1->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
72  main->addWidget( lb_banner1, row++, 0 );
73 
75  connect( lw_buffer_db, SIGNAL( itemDoubleClicked( QListWidgetItem* ) ),
76  SLOT ( select_buffer ( QListWidgetItem* ) ) );
77 
78  main->addWidget( lw_buffer_db, row, 0, 6, 1 );
79  row += 8;
80 
81  // Labels
82  QHBoxLayout* desc = new QHBoxLayout;
83 
84  QLabel* lb_description = us_label( tr( "Buffer Description:" ) );
85  desc->addWidget( lb_description );
86 
87  QGridLayout* shared = us_checkbox( tr( "Shared" ), cb_shared );
88 
89  // Set up checkbox colors to match label (as set in us_config)
90  QPalette p = US_GuiSettings::labelColor();
91  p.setColor( QPalette::Base, p.color( QPalette::WindowText ) ); // CB BG
92  p.setColor( QPalette::Button, p.color( QPalette::Window ) ); // Text BG
93  p.setColor( QPalette::Text, p.color( QPalette::Window ) ); // CB FG
94 
95  shared->itemAt( 0 )->widget()->setPalette( p );
96  shared->itemAt( 1 )->widget()->setPalette( p );
97 
98  desc->addLayout( shared );
99 
100  main->addLayout( desc, row++, 0 );
101 
102  QLabel* lb_guid = us_label( tr( "Global Identifier:" ) );
103  main->addWidget( lb_guid, row++, 0 );
104 
105  QLabel* lb_buffer1 = us_label( tr( "Please select a Buffer Component:" ) );
106  lb_buffer1->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
107  main->addWidget( lb_buffer1, row++, 0 );
108 
109  lb_selected = us_label( "" );
110  main->addWidget( lb_selected, row++, 0 );
111 
112  // Buffer Components
113  QLabel* lb_banner2 = us_banner( tr( "Click on item to select" ), -2 );
114  lb_banner2->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
115  main->addWidget( lb_banner2, row++, 0 );
116 
118  lw_ingredients-> setSortingEnabled( true );
119 
120  QFontMetrics fm( QFont( US_GuiSettings::fontFamily(),
122  int width = 0;
123 
124  QStringList keys = component_list.keys();
125  qSort( keys );
126 
127  for ( int i = 0; i < keys.size(); i++ )
128  {
129  QString key = keys[ i ];
130  QString s = component_list[ key ].name +
131  " (" + component_list[ key ].range + ")";
132 
133  // Insert the buffer component with it's key
134  new QListWidgetItem( s, lw_ingredients, key.toInt() );
135  width = max( fm.width( s ), width );
136  }
137 
138  // Allow for vertical scroll bar too
139  lw_ingredients->setMinimumWidth( width + 30 );
140  lw_ingredients->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
141 
142  connect( lw_ingredients, SIGNAL( itemSelectionChanged( void ) ),
143  SLOT ( list_component ( void ) ) );
144 
145  main->addWidget( lw_ingredients, row, 0, 5, 1 );
146 
147  row += 5;
148 
149  QPushButton* pb_synch = us_pushbutton( tr( "Synch components with DB" ) );
150  connect( pb_synch, SIGNAL( clicked() ), SLOT( synch_components() ) );
151  main->addWidget( pb_synch, row++, 0 );
152 
153  // Enable/Disable Sync button based on whether components file is writable
154  QString etcdir = US_Settings::appBaseDir() + "/etc/";
155  QString bufcmp = etcdir + "bufferComponents.xml";
156  QFileInfo fi( bufcmp );
157  pb_synch->setEnabled( ( !fi.exists() && QFileInfo( etcdir ).isWritable() )
158  || fi.isWritable() );
159 
160  row = 1;
161 
162  // Investigator
163 
164  QString number = ( personID > 0 )
165  ? QString::number( US_Settings::us_inv_ID() ) + ": "
166  : "";
167 
169  le_investigator->setReadOnly( true );
170  le_investigator->setPalette( gray );
171  main->addWidget( le_investigator, row++, 1, 1, 2 );
172 
173  disk_controls = new US_Disk_DB_Controls( select_db_disk );
174  connect( disk_controls, SIGNAL( changed ( bool ) ),
175  SLOT ( source_changed( bool ) ) );
176  main->addLayout( disk_controls, row++, 1, 1, 2 );
177 
178  QLabel* lb_banner3 = us_banner( tr( "Database/Disk Functions" ), -2 );
179  lb_banner3->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
180  main->addWidget( lb_banner3, row++, 1, 1, 2 );
181 
182  QPushButton* pb_query = us_pushbutton( tr( "Query Descriptions" ) );
183  connect( pb_query, SIGNAL( clicked() ), SLOT( query() ) );
184  main->addWidget( pb_query, row, 1 );
185 
186  pb_save = us_pushbutton( tr( "Save Buffer" ), false );
187  connect( pb_save, SIGNAL( clicked() ), SLOT( save() ) );
188  main->addWidget( pb_save, row++, 2 );
189 
190  pb_update = us_pushbutton( tr( "Update Buffer" ), false );
191  connect( pb_update, SIGNAL( clicked() ), SLOT( update() ) );
192  main->addWidget( pb_update, row, 1 );
193 
194  pb_del = us_pushbutton( tr( "Delete Buffer" ), false );
195  connect( pb_del, SIGNAL( clicked() ), SLOT( delete_buffer() ) );
196  main->addWidget( pb_del, row++, 2 );
197 
198  // Buffer parameters
199  QLabel* lb_density = us_label(
200  tr( "Density (20" ) + DEGC + tr( ", g/cm<sup>3</sup>):" ) );
201  main->addWidget( lb_density, row, 1 );
202 
204  connect( le_density, SIGNAL( textEdited( const QString& ) ),
205  SLOT ( density ( const QString& ) ) );
206  main->addWidget( le_density, row++, 2 );
207 
208  QLabel* lb_viscosity =
209  us_label( tr( "Viscosity (20" ) + DEGC + tr( ", cp):" ) );
210  main->addWidget( lb_viscosity, row, 1 );
211 
213  connect( le_viscosity, SIGNAL( textEdited( const QString& ) ),
214  SLOT ( viscosity ( const QString& ) ) );
215  main->addWidget( le_viscosity, row++, 2 );
216 
217  QLabel* lb_ph = us_label( tr( "pH:" ) );
218  main->addWidget( lb_ph, row, 1 );
219 
220  le_ph = us_lineedit();
221  main->addWidget( le_ph, row++, 2 );
222 
223  QLabel* lb_compressibility = us_label( tr( "Compressibility:" ) );
224  main->addWidget( lb_compressibility, row, 1 );
225 
227  main->addWidget( le_compressibility, row++, 2 );
228 // Make compressibility read-only for now
230 
231  QGridLayout* lo_manual = us_checkbox(
232  tr( "Manual unadjusted Density and Viscosity" ), cb_manual );
233  main->addLayout( lo_manual, row++, 0, 1, 3 );
234 
235  QLabel* lb_optics = us_label( tr( "Optics:" ) );
236 
238  cmb_optics->addItem( tr( "Absorbance" ) );
239  cmb_optics->addItem( tr( "Interference" ) );
240  cmb_optics->addItem( tr( "Fluorescence" ) );
241 
242  QPushButton* pb_spectrum = us_pushbutton( tr( "Manage Spectrum" ) );
243  connect( pb_spectrum, SIGNAL( clicked() ), SLOT( spectrum() ) );
244 
245  main->addWidget( lb_optics, row, 0 );
246  main->addWidget( cmb_optics, row, 1 );
247  main->addWidget( pb_spectrum, row++, 2 );
248 
250  main->addWidget( le_description, row++, 1, 1, 2 );
251  connect( le_description, SIGNAL( editingFinished() ),
252  SLOT ( new_description() ) );
253  le_description->setEnabled( false );
254 
255  le_guid = us_lineedit();
256  le_guid->setReadOnly( true );
257  le_guid->setPalette ( gray );
258  main->addWidget( le_guid, row++, 1, 1, 2 );
259 
260  if ( US_Settings::us_debug() == 0 )
261  {
262  lb_guid->setVisible( false );
263  le_guid->setVisible( false );
264  }
265 
266  lb_units = us_label( "" );
267  p = lb_units->palette();
268  p.setColor( QPalette::WindowText, Qt::red );
269  lb_units->setPalette( p );
270  lb_units->setAlignment( Qt::AlignCenter );
271  main->addWidget( lb_units, row++, 1, 1, 2 );
272 
274  connect( le_concentration, SIGNAL( editingFinished() ),
275  SLOT ( add_component () ) );
276  main->addWidget( le_concentration, row++, 1, 1, 2 );
277 
278  // Current buffer
279  QLabel* lb_buffer = us_banner( tr( "Doubleclick on item to remove" ), -2 );
280  lb_buffer->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
281  main->addWidget( lb_buffer, row++, 1, 1, 2 );
282 
284  connect( lw_buffer, SIGNAL( itemDoubleClicked( QListWidgetItem* ) ),
285  SLOT ( remove_component ( QListWidgetItem* ) ) );
286  main->addWidget( lw_buffer, row, 1, 6, 2 );
287  row += 6;
288 
289  // Standard buttons
290  QBoxLayout* buttons = new QHBoxLayout;
291 
292  QPushButton* pb_reset = us_pushbutton( tr( "Reset" ) );
293  connect( pb_reset, SIGNAL( clicked() ), SLOT( reset() ) );
294  buttons->addWidget( pb_reset );
295 
296  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
297  connect( pb_help, SIGNAL( clicked() ), SLOT( help() ) );
298  buttons->addWidget( pb_help );
299 
300  QPushButton* pb_accept = us_pushbutton( tr( "Close" ) );;
301 
302  if ( signal )
303  {
304  QPushButton* pb_cancel = us_pushbutton( tr( "Cancel" ) );
305  connect( pb_cancel, SIGNAL( clicked() ), SLOT( reject() ) );
306  buttons->addWidget( pb_cancel );
307 
308  pb_accept->setText( tr( "Accept" ) );
309  }
310 
311  connect( pb_accept, SIGNAL( clicked() ), SLOT( accept_buffer() ) );
312  buttons->addWidget( pb_accept );
313 
314  main->addLayout( buttons, row, 0, 1, 3 );
315 
316  init_buffer();
317 }
318 
320 {
321  QStringList DB = US_Settings::defaultDB();
322 
323  if ( DB.size() < 5 )
324  {
325  QMessageBox::warning( this,
326  tr( "Attention" ),
327  tr( "There is no default database set." ) );
328  }
329  else
330  {
332 
333  if ( personID > 0 )
334  le_investigator->setText( QString::number( personID ) + ": "
336  }
337 }
338 
339 void US_BufferGui::density( const QString& d )
340 {
341  buffer.density = d.toDouble();
342 
343  if ( ! manualUpdate )
344  {
345  buffer.component .clear();
346  buffer.concentration.clear();
347  buffer.componentIDs .clear();
348  buffer.GUID .clear();
349  buffer.bufferID .clear();
350  le_guid ->clear();
351  lw_buffer ->clear();
352  lw_buffer ->addItem( tr( "Manual Override" ) );
353 
354  lw_buffer_db->setCurrentRow( -1 );
355  manualUpdate = true;
356  bufferCurrent = false;
357  }
358 }
359 
360 void US_BufferGui::viscosity( const QString& v )
361 {
362  buffer.viscosity = v.toDouble();
363 
364  if ( ! manualUpdate )
365  {
366  buffer.component .clear();
367  buffer.concentration.clear();
368  buffer.componentIDs .clear();
369  buffer.GUID .clear();
370  buffer.bufferID .clear();
371  le_guid ->clear();
372  lw_buffer ->clear();
373  lw_buffer ->addItem( tr( "Manual Override" ) );
374 
375  lw_buffer_db->setCurrentRow( -1 );
376  manualUpdate = true;
377  bufferCurrent = false;
378  }
379 }
380 
382 {
383  query();
384 
385  if ( ! buffer.GUID.isEmpty() )
386  {
387  if ( ! disk_controls->db() ) // Disk access
388  {
389  // Search for GUID
390  for ( int i = 0; i < buffer_metadata.size(); i++ )
391  {
392  if ( buffer.GUID == buffer_metadata[ i ].guid )
393  {
394  lw_buffer_db->setCurrentRow( i );
395  QListWidgetItem* item = lw_buffer_db->item( i );
396  select_buffer( item );
397  manualUpdate = false;
398  break;
399  }
400  }
401  }
402 
403  else // DB access
404  {
405  // Search for bufferID
406  for ( int i = 0; i < buffer_metadata.size(); i++ )
407  {
408  if ( buffer.bufferID == buffer_metadata[ i ].bufferID )
409  {
410  lw_buffer_db->setCurrentRow( i );
411  QListWidgetItem* item = lw_buffer_db->item( i );
412  select_buffer( item );
413  manualUpdate = false;
414  break;
415  }
416  }
417  }
418  }
419  else
420  {
421  le_description->setText( buffer.description );
422  le_density ->setText( QString::number( buffer.density, 'f', 6 ) );
423  le_viscosity ->setText( QString::number( buffer.viscosity, 'f', 5 ) );
424  le_ph ->setText( QString::number( buffer.pH, 'f', 4 ) );
425  le_compressibility->setText(
426  QString::number( buffer.compressibility, 'e', 4 ) );
427  }
428 }
429 
431 // etc/bufferComponents.xml
433 {
434  US_Passwd pw;
435 
436  qApp->processEvents();
437 
438  component_list.clear();
441 
442  // Update the list widget with components from DB
443  lw_ingredients->clear();
444 
445  QStringList keys = component_list.keys();
446  qSort( keys );
447 
448  for ( int i = 0; i < keys.size(); i++ )
449  {
450  QString key = keys[ i ];
451  QString s = component_list[ key ].name +
452  " (" + component_list[ key ].range + ")";
453 
454  // Insert the buffer component with it's key
455  new QListWidgetItem( s, lw_ingredients, key.toInt() );
456  }
457 }
458 
460 {
461  US_Investigator* inv_dialog = new US_Investigator( true, personID );
462 
463  connect( inv_dialog,
464  SIGNAL( investigator_accepted( int ) ),
465  SLOT ( assign_investigator ( int ) ) );
466 
467  inv_dialog->exec();
468 }
469 
471 {
472  personID = invID;
473  view_shared = false;
474 
475  QString number = ( personID > 0 )
476  ? QString::number( invID ) + ": "
477  : "";
478 
479  le_investigator->setText( number + US_Settings::us_inv_name() );
480 
481  if ( disk_controls->db() ) read_db();
482 }
483 
484 // Get the path to the buffers. Create it if necessary.
485 bool US_BufferGui::buffer_path( QString& path )
486 {
487  QDir dir;
488  path = US_Settings::dataDir() + "/buffers";
489 
490  if ( ! dir.exists( path ) )
491  {
492  if ( ! dir.mkpath( path ) )
493  {
494  QMessageBox::critical( this,
495  tr( "Bad Buffer Path" ),
496  tr( "Could not create default directory for buffers\n" )
497  + path );
498  return false;
499  }
500  }
501 
502  return true;
503 }
504 
508 {
509  if ( ! disk_controls->db() ) read_buffer();
510  else read_db();
511 
512  le_description->setEnabled( true );
513 }
514 
517 {
518  QString path;
519  if ( ! buffer_path( path ) ) return;
520 
521  filenames .clear();
522  descriptions.clear();
523  GUIDs .clear();
524  bufferIDs .clear();
525  le_search-> clear();
526  le_search->setPalette( gray );
527  le_search->setReadOnly( true );
528 
529  bool desc_set = le_description->text().size() > 0;
530  pb_save ->setEnabled( desc_set );
531  pb_update->setEnabled( desc_set );
532  pb_del ->setEnabled( false );
533 
534  QDir f( path );
535  QStringList filter( "B*.xml" );
536  QStringList f_names = f.entryList( filter, QDir::Files, QDir::Name );
537 
538  for ( int i = 0; i < f_names.size(); i++ )
539  {
540  QFile b_file( path + "/" + f_names[ i ] );
541 
542  if ( ! b_file.open( QIODevice::ReadOnly | QIODevice::Text) ) continue;
543 
544  QXmlStreamReader xml( &b_file );
545 
546  while ( ! xml.atEnd() )
547  {
548  xml.readNext();
549 
550  if ( xml.isStartElement() )
551  {
552  if ( xml.name() == "buffer" )
553  {
554  QXmlStreamAttributes a = xml.attributes();
555  descriptions << a.value( "description" ).toString();
556  GUIDs << a.value( "guid" ).toString();
557  filenames << path + "/" + f_names[ i ];
558  bufferIDs << "";
559  break;
560  }
561  }
562  }
563  }
564 
565  lw_buffer_db->clear();
566 
567  if ( descriptions.size() == 0 )
568  lw_buffer_db->addItem( "No buffer files found." );
569  else
570  {
571  le_search->setReadOnly( false );
572  le_search->setPalette ( normal );
573  search();
574  }
575 }
576 
578 {
579  US_Passwd pw;
580  US_DB2 db( pw.getPasswd() );
581 
582  if ( db.lastErrno() != US_DB2::OK )
583  {
584  connect_error( db.lastError() );
585  return;
586  }
587 
588  bufferIDs .clear();
589  descriptions.clear();
590  GUIDs .clear();
591  le_search-> clear();
592  le_search->setPalette( gray );
593  le_search->setReadOnly( true );
594 
595  bool desc_set = le_description->text().size() > 0;
596  pb_save ->setEnabled( desc_set );
597  pb_update->setEnabled( desc_set );
598  pb_del ->setEnabled( false );
599 
600  le_search->setText( "" );
601  le_search->setReadOnly( true );
602 
603  view_shared = cb_shared->isChecked();
604  QString person = view_shared ? "0" : QString::number( personID );
605  QStringList q( "get_buffer_desc" );
606  q << person;
607 
608  db.query( q );
609 
610  while ( db.next() )
611  {
612  bufferIDs << db.value( 0 ).toString();
613  descriptions << db.value( 1 ).toString();
614  GUIDs << "";
615  }
616 
617  lw_buffer_db->clear();
618 
619  if ( descriptions.size() == 0 )
620  {
621  lw_buffer_db->addItem( "No buffer files found." );
622  }
623  else
624  {
625  le_search->setReadOnly( false );
626  le_search->setPalette ( normal );
627  search();
628  }
629 }
630 
631 void US_BufferGui::search( const QString& text )
632 {
633  QString sep = ";";
634  QStringList sortdesc;
635  lw_buffer_db ->clear();
636  buffer_metadata.clear();
637  sortdesc .clear();
638 
639  for ( int ii = 0; ii < descriptions.size(); ii++ )
640  { // get list of filtered-description + index strings
641  if ( descriptions[ ii ].contains(
642  QRegExp( ".*" + text + ".*", Qt::CaseInsensitive ) ) &&
643  ! descriptions[ ii].isEmpty() )
644  {
645  sortdesc << descriptions[ ii ] + sep + QString::number( ii );
646  }
647  }
648 
649  // sort the descriptions
650  sortdesc.sort();
651 
652  for ( int jj = 0; jj < sortdesc.size(); jj++ )
653  { // build list of sorted meta data and ListWidget entries
654  int ii = sortdesc[ jj ].section( sep, 1, 1 ).toInt();
655 
656  BufferInfo info;
657  info.index = ii;
658  info.description = descriptions[ ii ];
659  info.guid = GUIDs [ ii ];
660  info.bufferID = bufferIDs [ ii ];
661 
662  buffer_metadata << info;
663 
664  lw_buffer_db->addItem( info.description );
665  }
666 }
667 
668 void US_BufferGui::connect_error( const QString& error )
669 {
670  QMessageBox::warning( this, tr( "Connection Problem" ),
671  tr( "Could not connect to database \n" ) + error );
672 }
673 
675 {
676  QString spectrum_type = cmb_optics->currentText();
677  US_Table* dialog;
678  QString s = tr( "Extinction:" );
679 
680  if ( spectrum_type == tr( "Absorbance" ) )
681  dialog = new US_Table( buffer.extinction, s, bufferCurrent );
682  else if ( spectrum_type == tr( "Interference" ) )
683  dialog = new US_Table( buffer.refraction, s, bufferCurrent );
684  else
685  dialog = new US_Table( buffer.fluorescence, s, bufferCurrent );
686 
687  dialog->setWindowTitle( tr( "Manage %1 Values" ).arg( spectrum_type ) );
688  dialog->exec();
689 }
690 
695 void US_BufferGui::select_buffer( QListWidgetItem* item )
696 {
697  if ( ! disk_controls->db() ) read_from_disk( item );
698  else read_from_db ( item );
699 
700  // Write values to screen
701  le_description->setText( buffer.description );
702  le_guid ->setText( buffer.GUID );
703  le_density ->setText( QString::number( buffer.density, 'f', 6 ) );
704  le_viscosity ->setText( QString::number( buffer.viscosity, 'f', 5 ) );
705  le_ph ->setText( QString::number( buffer.pH, 'f', 4 ) );
706  le_compressibility->setText(
707  QString::number( buffer.compressibility, 'e', 4 ) );
708 
709  lw_buffer->clear();
710 
711  for ( int i = 0; i < buffer.componentIDs.size(); i ++ )
713 
714  // Allow modification of the just selected buffer
715  bufferCurrent = true;
716  pb_save ->setEnabled ( true );
717  pb_update->setEnabled ( true );
718  pb_del ->setEnabled ( true );
719 }
720 
721 void US_BufferGui::read_from_disk( QListWidgetItem* item )
722 {
723  int row = lw_buffer_db->row( item );
724  int buf = buffer_metadata[ row ].index;
725 
726  if ( ! buffer.readFromDisk( filenames[ buf ] ) )
727  qDebug() << "read failed";
728 
729  buffer.component.clear();
730  cb_shared ->setChecked( false );
731  cb_manual ->setChecked( buffer.manual );
732 
733  for ( int i = 0; i < buffer.componentIDs.size(); i++ )
734  {
735  QString index = buffer.componentIDs[ i ];
736  buffer.component << component_list[ index ];
737  }
738 }
739 
740 void US_BufferGui::read_from_db( QListWidgetItem* item )
741 {
742  int row = lw_buffer_db->row( item );
743  QString bufferID = buffer_metadata[ row ].bufferID;
744  read_from_db( bufferID );
745 }
746 
747 void US_BufferGui::read_from_db( const QString& bufferID )
748 {
749  US_Passwd pw;
750  US_DB2 db( pw.getPasswd() );
751 
752  // Get the buffer data from the database
753  if ( db.lastErrno() != US_DB2::OK )
754  {
755  connect_error( db.lastError() );
756  return;
757  }
758 
759  buffer.readFromDB( &db, bufferID );
760 
761  cb_manual->setChecked( buffer.manual );
762 }
763 
764 void US_BufferGui::update_lw_buf( const QString& componentID, double conc )
765 {
766  QString name = component_list[ componentID ].name;
767  QString unit = component_list[ componentID ].unit;
768 
769  QString s = QString::number( conc, 'f', 1 );
770 
771  lw_buffer->addItem( name + " (" + s + " " + unit + ")" );
772 }
773 
775 {
777 
778  buffer.pH = ( le_ph->text().isEmpty() )
779  ? 7.0
780  : le_ph->text().toDouble();
781 
782  buffer.density = le_density ->text().toDouble();
783  buffer.viscosity = le_viscosity ->text().toDouble();
784  buffer.compressibility = le_compressibility->text().toDouble();
785 //hardwire compressibility to zero, for now
786 buffer.compressibility = 0.0;
787  buffer.manual = ( cb_manual->isChecked() );
788  int manx = buffer.description.indexOf( " [M]" );
789  if ( manx > 0 )
790  buffer.description = buffer.description.left( manx ).simplified();
791 
792  // These are updated in other places
793  //buffer.component
794  //buffer.concentration
795  //buffer.bufferID
796  //buffer.personID
797 }
798 
800 {
801  if ( buffer.GUID.size() == 0 || lw_buffer_db->currentRow() < 0 )
802  {
803  QMessageBox::information( this,
804  tr( "Attention" ),
805  tr( "First select the buffer which you "
806  "want to delete." ) );
807  return;
808  }
809 
810  int response = QMessageBox::question( this,
811  tr( "Confirmation" ),
812  tr( "Do you really want to delete this entry?\n"
813  "Clicking 'OK' will delete the selected buffer data." ),
814  QMessageBox::Ok, QMessageBox::Cancel );
815 
816  if ( response != QMessageBox::Ok ) return;
817 
818  if ( disk_controls->db() )
819  delete_db();
820  else
821  delete_disk();
822 
823  reset();
824  query();
825  bufferCurrent = true;
826 }
827 
829 {
830  QString bufGUID = le_guid->text();
831  QString path;
832  if ( ! buffer_path( path ) ) return;
833 
834  bool newFile;
835  QString filename = US_Buffer::get_filename( path, bufGUID, newFile );
836 
837  if ( buffer_in_use( bufGUID ) )
838  {
839  QMessageBox::warning( this,
840  tr( "Buffer Not Deleted" ),
841  tr( "The buffer could not be deleted,\n"
842  "since it is in use in one or more solutions." ) );
843  return;
844  }
845 
846  if ( ! newFile )
847  {
848  QFile f( filename );
849  f.remove();
850  }
851 }
852 
853 // Delete the buffer data from the database
855 {
856  US_Passwd pw;
857  US_DB2 db( pw.getPasswd() );
858 
859  if ( db.lastErrno() != US_DB2::OK )
860  {
861  connect_error( db.lastError() );
862  return;
863  }
864 
865  QStringList q( "get_bufferID" );
866  q << le_guid->text();
867 
868  db.query( q );
869 
870  int status = db.lastErrno();
871 
872  if ( status == US_DB2::OK )
873  {
874  db.next();
875  QString bufferID = db.value( 0 ).toString();
876 
877  q[ 0 ] = "delete_buffer";
878  q[ 1 ] = bufferID;
879  status = db.statusQuery( q );
880  }
881 
882  if ( status == US_DB2::BUFFR_IN_USE )
883  {
884  QMessageBox::warning( this,
885  tr( "Buffer Not Deleted" ),
886  tr( "The buffer could not be deleted,\n"
887  "since it is in use in one or more solutions." ) );
888  return;
889  }
890 
891  if ( status != US_DB2::OK )
892  {
893  QMessageBox::warning( this,
894  tr( "Attention" ),
895  tr( "Delete failed.\n\n" ) + db.lastError() );
896  }
897 }
898 
899 void US_BufferGui::save( void )
900 {
901  if ( le_description->text().isEmpty() )
902  {
903  QMessageBox::information( this,
904  tr( "Attention" ),
905  tr( "Please enter a description for\n"
906  "your buffer before saving it!" ) );
907  return;
908  }
909 
910  update_buffer();
911 
912  if ( le_guid->text().size() != 36 )
913  le_guid->setText( US_Util::new_guid() );
914 
915  buffer.GUID = le_guid->text();
916 
917  if ( ! disk_controls->db() ) save_disk();
918  else save_db();
919 
920  bufferCurrent = true;
921 }
922 
924 {
925  QString path;
926  if ( ! buffer_path( path ) ) return;
927 
928  if ( buffer.GUID.isEmpty() || buffer.description.isEmpty() )
929  {
930  QMessageBox::information( this,
931  tr( "NO Save of Results" ),
932  tr( "The buffer with an empty GUID and/or description\n"
933  "was not saved." ) );
934  return;
935  }
936 
937  buffer.manual = ( cb_manual->isChecked() );
938 
939  bool newFile;
940  QString filename = US_Buffer::get_filename( path, buffer.GUID, newFile );
941  buffer.writeToDisk( filename );
942 
943  QString s = ( newFile ) ? tr( "saved" ) : tr( "updated" );
944 
945  QMessageBox::information( this,
946  tr( "Save results" ),
947  tr( "Buffer " ) + s );
948 
949  read_buffer();
950 }
951 
953 {
954  if ( personID < 0 )
955  {
956  QMessageBox::information( this,
957  tr( "Attention" ),
958  tr( "Please select an investigator first!" ) );
959  return;
960  }
961 
962  US_Passwd pw;
963  US_DB2 db( pw.getPasswd() );
964 
965  if ( db.lastErrno() != US_DB2::OK )
966  {
967  connect_error( db.lastError() );
968  return;
969  }
970 
971  buffer.manual = cb_manual->isChecked();
972  QString private_buffer = ( cb_shared->isChecked() ) ? "0" : "1";
973 
974  int idBuf = buffer.saveToDB( &db, private_buffer );
975 
976  if ( idBuf < 0 )
977  {
978  QString msg = tr( "( Return Code = %1 ) " ).arg( idBuf )
979  + db.lastError();
980 
981  QMessageBox::information( this,
982  tr( "Attention" ),
983  tr( "Error updating buffer in the database:\n" )
984  + msg );
985 
986  return;
987  }
988 
989  //reset();
990  read_db();
991 }
992 
994 {
995  update_buffer();
996  buffer.GUID = le_guid->text();
997 
998  if ( ! disk_controls->db() ) save_disk();
999  else update_db();
1000 
1001  bufferCurrent = true;
1002 }
1003 
1006 {
1007  if ( buffer.bufferID.toInt() <= 0 )
1008  {
1009  QMessageBox::information( this,
1010  tr( "Attention" ),
1011  tr( "Please select an existing Buffer first!" ) );
1012  return;
1013  }
1014 
1015  //if ( buffer.personID <= 0 )
1016  if ( personID <= 0 )
1017  {
1018  QMessageBox::information( this,
1019  tr( "Attention" ),
1020  tr( "Please select an investigator first!" ) );
1021  return;
1022  }
1023 
1024  if ( le_description->text().isEmpty() )
1025  {
1026  QMessageBox::information( this,
1027  tr( "Attention" ),
1028  tr( "Please enter a buffer description first!" ) );
1029  return;
1030  }
1031 
1032  int response = QMessageBox::question( this,
1033  tr( "Confirmation" ),
1034  tr( "Do you really want to update this entry in the database?\n" ),
1035  QMessageBox::Ok, QMessageBox::Cancel );
1036 
1037  if ( response == QMessageBox::Ok )
1038  {
1039  US_Passwd pw;
1040  US_DB2 db( pw.getPasswd() );
1041 
1042  // Delete the buffer data from the database
1043  if ( db.lastErrno() != US_DB2::OK )
1044  {
1045  connect_error( db.lastError() );
1046  return;
1047  }
1048 
1049  QString private_buffer = ( cb_shared->isChecked() ) ? "0" : "1";
1050  int idBuf = buffer.saveToDB( &db, private_buffer );
1051 
1052  if ( idBuf < 0 )
1053  {
1054  QString msg = tr( "( Return Code = %1 ) " ).arg( idBuf )
1055  + db.lastError();
1056 
1057  QMessageBox::information( this,
1058  tr( "Attention" ),
1059  tr( "Error updating buffer in the database:\n" )
1060  + msg );
1061  return;
1062  }
1063 
1064  QMessageBox::information( this,
1065  tr( "Success" ),
1066  tr( "The database has been updated\n" ) );
1067  }
1068 }
1069 
1074 {
1075  // We are modifying the buffer, nothing should be selected in the DB list
1076  lw_buffer_db->clearSelection();
1077  int row = lw_ingredients->currentRow();
1078 
1079  if ( row < 0 )
1080  {
1081  QMessageBox::information( this,
1082  tr( "Attention" ),
1083  tr( "First select a buffer component!\n" ) );
1084  return;
1085  }
1086 
1087  double partial_concentration = le_concentration->text().toDouble();
1088  if ( partial_concentration <= 0.0 ) return;
1089 
1090  if ( manualUpdate ) lw_buffer->clear();
1091 
1092  QString s;
1093  bool newItem = true;
1094  QListWidgetItem* item = lw_ingredients->item( row );
1095  QString index = QString::number( item->type() );
1096 
1097  US_BufferComponent std_bc = component_list[ index ];
1098 
1099  // Find out if this inredient already exists, otherwise add a new component
1100  for ( int i = 0; i < buffer.component.size(); i++ )
1101  {
1102  US_BufferComponent* bc = &buffer.component[ i ];
1103 
1104  if ( std_bc.name == bc->name )
1105  {
1106  // Simply update the partial concentration of the existing ingredient
1107  buffer.concentration[ i ] = partial_concentration;
1108 
1109  s.sprintf( " (%.1f ", partial_concentration );
1110 
1111  lw_buffer->item( i )->setText( std_bc.name + s + std_bc.unit + ")" );
1112  newItem = false;
1113  break;
1114  }
1115  }
1116 
1117  // Add a new ingredient to this buffer
1118  if ( newItem )
1119  {
1120  buffer.concentration << partial_concentration;
1121  buffer.component << std_bc;
1122  buffer.componentIDs << std_bc.componentID;
1123 
1124  s.sprintf( " (%.1f ", partial_concentration );
1125  lw_buffer->addItem( std_bc.name + s + std_bc.unit + ")" );
1126  }
1127 
1128  recalc_density();
1129  recalc_viscosity();
1130 
1131  le_density ->setText( QString::number( buffer.density, 'f', 6 ) );
1132  le_viscosity ->setText( QString::number( buffer.viscosity, 'f', 5 ) );
1133  le_concentration->setText( "" );
1135  ->setText( QString::number( buffer.compressibility, 'e', 4));
1136 
1137  pb_save->setEnabled( true );
1138  bufferCurrent = false;
1139  manualUpdate = false;
1140 }
1141 
1145 {
1146  QString id = QString::number( lw_ingredients->currentRow() );
1147 
1148  lb_selected->setText( lw_ingredients->currentItem()->text() );
1149  lb_units->setText( tr( "Please enter with units in: " ) +
1150  component_list[ id ].unit );
1151 
1152  le_concentration->setFocus();
1153 }
1154 
1157 void US_BufferGui::remove_component( QListWidgetItem* item )
1158 {
1159  if ( manualUpdate ) return;
1160  int row = lw_buffer->row( item );
1161 
1162  buffer.component .removeAt( row );
1163  buffer.concentration.removeAt( row );
1164  buffer.componentIDs .removeAt( row );
1165 
1166  recalc_viscosity();
1167  recalc_density();
1168 
1169  le_density ->setText( QString::number( buffer.density, 'f', 6 ) );
1170  le_viscosity->setText( QString::number( buffer.viscosity, 'f', 5 ) );
1171 
1172  QListWidgetItem* oldItem = lw_buffer->takeItem( row );
1173  delete oldItem;
1174 
1175  bufferCurrent = false;
1176 }
1177 
1179 {
1180  if ( ! bufferCurrent ||
1181  le_description ->text() != buffer.description ||
1182  le_compressibility->text().toDouble() != buffer.compressibility ||
1183  le_ph ->text().toDouble() != buffer.pH )
1184  return false;
1185 
1186  return true;
1187 }
1188 
1190 {
1191  if ( ! up_to_date() && signal )
1192  {
1193  int response = QMessageBox::question( this,
1194  tr( "Buffer changed" ),
1195  tr( "Changes have not been saved.\n\nContinue?" ),
1196  QMessageBox::Yes, QMessageBox::Cancel );
1197 
1198  if ( response != QMessageBox::Yes ) return;
1199  }
1200 
1201  if ( signal )
1202  {
1203  update_buffer();
1204  buffer.GUID = le_guid->text();
1206  emit valueChanged ( buffer );
1207  emit valueBufferID( buffer.bufferID );
1208  }
1209 
1210  accept();
1211 }
1212 
1215 {
1216  buffer = US_Buffer();
1217 
1218  view_shared = false;
1219  le_search ->clear();;
1220  le_search ->setReadOnly( false );
1221 
1222  le_guid ->clear();
1223 
1224  lw_buffer_db ->clear();
1225  lw_buffer ->clear();
1226 
1227  lb_selected ->setText( "" );
1228 
1229  le_density ->setText( "0.0" );
1230  le_viscosity ->setText( "0.0" );
1231 
1232  le_description ->clear();
1233  le_compressibility->clear();
1234 
1235  le_ph ->setText( "7.0" );
1236 
1237  pb_save ->setEnabled( false );
1238  pb_update ->setEnabled( false );
1239  pb_del ->setEnabled( false );
1240  cb_shared ->setChecked( false );
1241  cb_manual ->setChecked( false );
1242 
1243  lb_units ->setText( "" );
1244  le_concentration ->clear();
1245 
1246  int id = US_Settings::us_inv_ID();
1247  QString number = ( id > 0 ) ? QString::number( id ) + ": " : "";
1248  le_investigator->setText( number + US_Settings::us_inv_name() );
1249 }
1250 
1254 {
1256 
1257  // Iterate over all components in this buffer
1258  for ( int i = 0; i < buffer.component.size(); i++ )
1259  {
1260  US_BufferComponent* bc = &buffer.component[ i ];
1261 
1262  double c1 = buffer.concentration[ i ];
1263  if ( bc->unit == "mM" ) c1 /= 1000;
1264 
1265  double c2 = c1 * c1; // c1^2
1266  double c3 = c2 * c1; // c1^3
1267  double c4 = c3 * c1; // c1^4
1268 
1269  if ( c1 > 0.0 )
1270  {
1271  buffer.density +=
1272  bc->dens_coeff[ 0 ] +
1273  bc->dens_coeff[ 1 ] * 1.0e-3 * sqrt( c1 )
1274  + bc->dens_coeff[ 2 ] * 1.0e-2 * c1
1275  + bc->dens_coeff[ 3 ] * 1.0e-3 * c2
1276  + bc->dens_coeff[ 4 ] * 1.0e-4 * c3
1277  + bc->dens_coeff[ 5 ] * 1.0e-6 * c4
1278  - DENS_20W;
1279  }
1280  }
1281 }
1282 
1286 {
1288 
1289  // Iterate over all components in this buffer
1290  for ( int i = 0; i < buffer.component.size(); i++)
1291  {
1292  US_BufferComponent* bc = &buffer.component[ i ];
1293 
1294  double c1 = buffer.concentration[ i ];
1295  if ( bc->unit == "mM" ) c1 /= 1000;
1296 
1297  double c2 = c1 * c1; // c1^2
1298  double c3 = c2 * c1; // c1^3
1299  double c4 = c3 * c1; // c1^4
1300 
1301  if ( c1 > 0.0 )
1302  {
1303  buffer.viscosity +=
1304  bc->visc_coeff[ 0 ]
1305  + bc->visc_coeff[ 1 ] * 1.0e-3 * sqrt( c1 )
1306  + bc->visc_coeff[ 2 ] * 1.0e-2 * c1
1307  + bc->visc_coeff[ 3 ] * 1.0e-3 * c2
1308  + bc->visc_coeff[ 4 ] * 1.0e-4 * c3
1309  + bc->visc_coeff[ 5 ] * 1.0e-6 * c4
1310  - VISC_20W;
1311  }
1312  }
1313 }
1314 
1315 // slot to handle an entered buffer description
1317 {
1318  buffer.description = le_description->text();
1319 
1320  int row = -1;
1321 
1322  for ( int ii = 0; ii < descriptions.size(); ii++ )
1323  {
1324  if ( buffer.description == descriptions.at( ii ) )
1325  {
1326  row = ii;
1327  break;
1328  }
1329  }
1330 
1331  pb_update->setEnabled( row >= 0 );
1332  pb_save ->setEnabled( row < 0 );
1333 
1334  if ( row < 0 )
1335  { // no match to description: clear GUID, de-select any list item
1336  le_guid->clear();
1337  lw_buffer_db->setCurrentRow( -1 );
1338  }
1339 
1340  else
1341  { // matching description: get GUID, but ask user if new or update
1342  buffer.GUID = GUIDs[ row ];
1343 
1344  if ( buffer.GUID.isEmpty() && disk_controls->db() )
1345  { // if no GUID yet and from DB, read GUID
1346  QString bufferID = bufferIDs[ row ];
1347  US_Passwd pw;
1348  US_DB2 db( pw.getPasswd() );
1349 
1350  if ( db.lastErrno() != US_DB2::OK )
1351  connect_error( db.lastError() );
1352 
1353  QStringList q( "get_buffer_info" );
1354  q << bufferID;
1355 
1356  db.query( q );
1357  db.next();
1358 
1359  buffer.bufferID = bufferID;
1360  buffer.GUID = db.value( 0 ).toString();
1361  }
1362 
1363  int response = QMessageBox::question( this,
1364  tr( "Update Buffer?" ),
1365  tr( "The buffer description is already used.\n"
1366  "Do you wish to replace that buffer?\n\n"
1367  "Click \"No\" to create a new buffer;\n"
1368  "Click \"Yes\" to update the existing buffer.\n" ),
1369  QMessageBox::Yes, QMessageBox::No );
1370 
1371  row = -1;
1372 
1373  if ( response == QMessageBox::No )
1374  { // new description (even if duplicate)
1375  buffer.GUID.clear();
1376  pb_update->setEnabled( false );
1377  pb_save ->setEnabled( true );
1378  }
1379 
1380  else
1381  { // find description in list if possible
1382  for ( int ii = 0; ii < lw_buffer_db->count(); ii++ )
1383  {
1384  if ( buffer.description == lw_buffer_db->item( ii )->text() )
1385  {
1386  row = ii;
1387  break;
1388  }
1389  }
1390  }
1391 
1392  // select any match in list; set existing GUID
1393  lw_buffer_db->setCurrentRow( row );
1394  le_guid->setText( buffer.GUID );
1395  }
1396 }
1397 
1399 {
1400  emit use_db( db );
1401  query();
1402  qApp->processEvents();
1403 }
1404 
1405 // Determine by GUID whether a buffer is in use in any solution on disk
1406 bool US_BufferGui::buffer_in_use( QString& bufferGUID )
1407 {
1408  bool in_use = false;
1409  QString soldir = US_Settings::dataDir() + "/solutions/";
1410  QStringList sfilt( "S*.xml" );
1411  QStringList snames = QDir( soldir )
1412  .entryList( sfilt, QDir::Files, QDir::Name );
1413 
1414  for ( int ii = 0; ii < snames.size(); ii++ )
1415  {
1416  QString sfname = soldir + snames.at( ii );
1417  QFile sfile( sfname );
1418 
1419  if ( ! sfile.open( QIODevice::ReadOnly | QIODevice::Text ) ) continue;
1420 
1421  QXmlStreamReader xml( &sfile );
1422 
1423  while ( ! xml.atEnd() )
1424  {
1425  xml.readNext();
1426 
1427  if ( xml.isStartElement() && xml.name() == "buffer" )
1428  {
1429  QXmlStreamAttributes atts = xml.attributes();
1430 
1431  if ( atts.value( "guid" ).toString() == bufferGUID )
1432  {
1433  in_use = true;
1434  break;
1435  }
1436  }
1437  }
1438 
1439  sfile.close();
1440 
1441  if ( in_use ) break;
1442  }
1443 
1444  return in_use;
1445 }
1446