UltraScan III
us_properties.cpp
Go to the documentation of this file.
1 
3 #include "us_properties.h"
4 #include "us_settings.h"
5 #include "us_gui_settings.h"
6 #include "us_constants.h"
7 #include "us_model.h"
8 
9 #include "qwt_arrow_button.h"
10 
12  : US_WidgetsDialog( 0, 0 ),
13  model ( mod ),
14  db_access ( access )
15 {
16  setPalette ( US_GuiSettings::frameColor() );
17  setWindowTitle( tr( "Set Analyte Properties" ) );
18  setAttribute ( Qt::WA_DeleteOnClose );
19 
20  oldRow = -2;
21  inUpdate = false;
22  chgStoi = false;
23 
25 
26  // Initialize the check icon
27  check = QIcon( US_Settings::appBaseDir() + "/etc/check.png" );
28 
29  // Grid
30  QGridLayout* main = new QGridLayout( this );
31  main->setSpacing( 2 );
32  main->setContentsMargins( 2, 2, 2, 2 );
33 
34  QPushButton* pb_new = us_pushbutton( tr( "New Analyte" ) );
35  QPushButton* pb_delete = us_pushbutton( tr( "Remove Current Analyte" ) );
36  QPushButton* pb_edit = us_pushbutton( tr( "Edit Current Analyte" ) );
37  QLabel* lb_desc = us_label( tr( "Analyte Description:" ) );
39 
40  // Components List Box
42 
43  // Row
44  QLabel* lb_guid = us_label( tr( "Global Identifier:" ) );
45  le_guid = us_lineedit( "" );
46  us_setReadOnly( le_guid, true );
47 
48  if ( US_Settings::us_debug() == 0 )
49  {
50  lb_guid->setVisible( false );
51  le_guid->setVisible( false );
52  }
53 
54  // Row
55  QLabel* lb_vbar = us_label( tr( "Vbar at 20 " ) + DEGC + " (ml/g):" );
56  le_vbar = us_lineedit( "" );
57 
58  // Row
59  QLabel* lb_extinction = us_label( tr( "Extinction (OD/(mol*cm)):" ) );
60  QLabel* lb_wavelength = us_label( tr( "Wavelength (nm):" ) );
61 
62  le_extinction = us_lineedit( "" );
63 
64  le_wavelength = us_lineedit( QString::number( model.wavelength, 'f', 1 ) );
65  le_wavelength->setMinimumWidth( 80 );
66  le_wavelength->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
68 
69  // Row
70  QGridLayout* lo_sigConc = us_checkbox(
71  tr( "Signal Concentration:" ), ck_sigConc, true );
72  le_sigConc = us_lineedit( "" );
73  QGridLayout* lo_isProd = us_checkbox(
74  tr( "Analyte is a Product" ), ck_isProd, false );
75 
76  // Row
77  QGridLayout* lo_molConc = us_checkbox(
78  tr( "Molar Concentration:" ), ck_molConc, false );
79  le_molConc = us_lineedit( "", 0, true );
80  ck_sigConc->setChecked( true );
81  ck_molConc->setChecked( false );
82 
83  // Row
84  QPushButton* pb_sim = us_pushbutton( tr( "Simulate s and D" ) );
85 
87  cb_shape->addItem( tr( "Sphere" ), US_Model::SPHERE );
88  cb_shape->addItem( tr( "Prolate Ellipsoid" ), US_Model::PROLATE );
89  cb_shape->addItem( tr( "Oblate Ellipsoid" ), US_Model::OBLATE );
90  cb_shape->addItem( tr( "Rod" ), US_Model::ROD );
91 
92  // Row
93  QGridLayout* lo_mw = us_checkbox(
94  tr( "Molecular Wt. (mw,S20W)" ), ck_mw, true );
95 
96  QLabel* lb_oligomer = us_label( tr( "Oligomer:" ) );
97 
98  le_mw = us_lineedit( "" );
99  us_setReadOnly( le_mw, true );
100 
101  ct_oligomer = us_counter( 1, 1.0, 9.0, 1.0 );
102  ct_oligomer->setStep( 1.0 );
103  QFontMetrics fmet( font() );
104  int fwid = fmet.maxWidth();
105  int rhgt = ct_oligomer->height();
106  int cminw = fwid;
107  int csizw = cminw + fwid * 2;
108  ct_oligomer->setMinimumWidth( cminw );
109  ct_oligomer->resize( csizw, rhgt );
110 
111  // Row
112  QGridLayout* lo_f_f0 =
113  us_checkbox( tr( "Frictional Ratio (f/f0,20W)" ), ck_f_f0, true );
114 
115  le_f_f0 = us_lineedit( "n/a" );
116  us_setReadOnly( le_f_f0, true );
117 
118  // Row
119  QGridLayout* lo_s = us_checkbox(
120  tr( "Sedimentation Coeff. (s,20W)" ), ck_s );
121  le_s = us_lineedit( "1e-13" );
122 
123  // Row
124  QGridLayout* lo_D = us_checkbox(
125  tr( "Diffusion Coeff. (D,20W)" ), ck_D );
126 
127  le_D = us_lineedit( "2e-7" );
128 
129  // Row
130  QGridLayout* lo_f = us_checkbox(
131  tr( "Frictional Coeff. (f,20W)" ), ck_f );
132  le_f = us_lineedit( "n/a" );
133  us_setReadOnly( le_f, true );
134 
135  // Row
136  QLabel* lb_sigma = us_label(
137  tr( "Conc. Dependency of s (<span>&sigma;</span>):" ) );
138 
139  le_sigma = us_lineedit( "" );
140 
141  // Row
142  QLabel* lb_delta = us_label(
143  tr( "Conc. Dependency of D (<span>&delta;</span>):" ) );
144  le_delta = us_lineedit( "" );
145 
146  // Row
147  pb_load_c0 = us_pushbutton( tr( "Load C0 from File" ) );
148 
149  QGridLayout* lo_co_sed = us_checkbox(
150  tr( "Co-sedimenting Solute" ), ck_co_sed );
151 
152  // Pushbuttons
153  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
154  QPushButton* pb_close = us_pushbutton( tr( "Cancel" ) );
155  QPushButton* pb_accept = us_pushbutton( tr( "Accept" ) );
156 
157  // Main layout
158  int row = 0;
159  main->addWidget( pb_new, row, 0, 1, 2 );
160  main->addWidget( pb_delete, row, 2, 1, 2 );
161  main->addWidget( pb_edit, row++, 4, 1, 2 );
162  main->addWidget( lb_desc, row, 0, 1, 2 );
163  main->addWidget( le_description, row++, 2, 1, 4 );
164  main->addWidget( lw_components, row, 0, 4, 6 ); row += 4;
165  main->addWidget( lb_guid, row, 0, 1, 2 );
166  main->addWidget( le_guid, row++, 2, 1, 4 );
167  main->addWidget( lb_vbar, row, 0, 1, 2 );
168  main->addWidget( le_vbar, row++, 2, 1, 1 );
169  main->addWidget( lb_extinction, row, 0, 1, 2 );
170  main->addWidget( le_extinction, row, 2, 1, 1 );
171  main->addWidget( lb_wavelength, row, 3, 1, 2 );
172  main->addWidget( le_wavelength, row++, 5, 1, 1 );
173  main->addLayout( lo_molConc, row, 0, 1, 2 );
174  main->addWidget( le_molConc, row++, 2, 1, 1 );
175  main->addLayout( lo_sigConc, row, 0, 1, 2 );
176  main->addWidget( le_sigConc, row, 2, 1, 1 );
177  main->addLayout( lo_isProd, row++, 3, 1, 3 );
178  main->addWidget( pb_sim, row, 0, 1, 2 );
179  main->addWidget( cb_shape, row++, 2, 1, 4 );
180  main->addLayout( lo_mw, row, 0, 1, 2 );
181  main->addWidget( le_mw, row, 2, 1, 1 );
182  main->addWidget( lb_oligomer, row, 3, 1, 2 );
183  main->addWidget( ct_oligomer, row++, 5, 1, 1 );
184  main->addLayout( lo_f_f0, row, 0, 1, 2 );
185  main->addWidget( le_f_f0, row++, 2, 1, 1 );
186  main->addLayout( lo_s, row, 0, 1, 2 );
187  main->addWidget( le_s, row++, 2, 1, 1 );
188  main->addLayout( lo_D, row, 0, 1, 2 );
189  main->addWidget( le_D, row++, 2, 1, 1 );
190  main->addLayout( lo_f, row, 0, 1, 2 );
191  main->addWidget( le_f, row++, 2, 1, 1 );
192  main->addWidget( lb_sigma, row, 0, 1, 2 );
193  main->addWidget( le_sigma, row, 2, 1, 1 );
194  main->addWidget( lb_delta, row, 3, 1, 2 );
195  main->addWidget( le_delta, row++, 5, 1, 1 );
196  main->addWidget( pb_load_c0, row, 0, 1, 3 );
197  main->addLayout( lo_co_sed, row++, 3, 1, 3 );
198  main->addWidget( pb_help, row, 0, 1, 2 );
199  main->addWidget( pb_close, row, 2, 1, 2 );
200  main->addWidget( pb_accept, row++, 4, 1, 2 );
201 
202  // Signal-Slot connections
203  connect( pb_new, SIGNAL( clicked() ),
204  SLOT( newAnalyte() ) );
205  connect( pb_delete, SIGNAL( clicked() ),
206  SLOT( del_component() ) );
207  connect( pb_edit, SIGNAL( clicked() ),
208  SLOT( edit_analyte() ) );
209  connect( le_description, SIGNAL( editingFinished() ),
210  SLOT ( edit_component () ) );
211  connect( lw_components, SIGNAL( currentRowChanged( int ) ),
212  SLOT ( update ( int ) ) );
213  connect( le_vbar, SIGNAL( editingFinished() ),
214  SLOT ( edit_vbar () ) );
215  connect( le_extinction, SIGNAL( editingFinished() ),
216  SLOT( set_molar() ) );
217  connect( ck_molConc, SIGNAL( toggled( bool ) ),
218  SLOT( check_molar( bool ) ) );
219  connect( ck_sigConc, SIGNAL( toggled( bool ) ),
220  SLOT( check_signal( bool ) ) );
221  connect( le_sigConc, SIGNAL( editingFinished() ),
222  SLOT( set_molar() ) );
223  connect( pb_sim, SIGNAL( clicked() ),
224  SLOT( simulate() ) );
225  connect( cb_shape, SIGNAL( currentIndexChanged( int ) ),
226  SLOT ( select_shape ( int ) ) );
227  connect( ck_mw, SIGNAL( toggled( bool ) ),
228  SLOT( calculate( bool ) ) );
229  connect( le_mw, SIGNAL( editingFinished() ),
230  SLOT( calculate() ) );
231  connect( ct_oligomer, SIGNAL( valueChanged ( double ) ),
232  SLOT ( set_oligomer ( double ) ) );
233  connect( ck_f_f0, SIGNAL( toggled( bool ) ),
234  SLOT( calculate( bool ) ) );
235  connect( le_f_f0, SIGNAL( editingFinished () ),
236  SLOT( calculate() ) );
237  connect( ck_s, SIGNAL( toggled( bool ) ),
238  SLOT( calculate( bool) ) );
239  connect( le_s, SIGNAL( editingFinished() ),
240  SLOT( calculate() ) );
241  connect( ck_D, SIGNAL( toggled( bool ) ),
242  SLOT( calculate( bool ) ) );
243  connect( le_D, SIGNAL( editingFinished() ),
244  SLOT( calculate() ) );
245  connect( ck_f, SIGNAL( toggled( bool ) ),
246  SLOT( calculate( bool ) ) );
247  connect( le_f, SIGNAL( editingFinished () ),
248  SLOT( calculate() ) );
249  connect( pb_load_c0, SIGNAL( clicked() ),
250  SLOT( load_c0() ) );
251  connect( ck_co_sed, SIGNAL( stateChanged( int ) ),
252  SLOT( co_sed( int ) ) );
253  connect( pb_help, SIGNAL( clicked() ),
254  SLOT( help() ) );
255  connect( pb_close, SIGNAL( clicked() ),
256  SLOT( close() ) );
257  connect( pb_accept, SIGNAL( clicked() ),
258  SLOT( acceptProp() ) );
259 
260  clear_entries();
261  update_lw();
262  checkbox();
263 }
264 
266 {
267  le_guid ->clear();
268  le_vbar ->clear();
269  le_extinction->clear();
270  le_molConc ->clear();
271  le_sigConc ->clear();
272  le_mw ->clear();
273  le_s ->clear();
274  le_D ->clear();
275  le_f ->clear();
276  le_f_f0 ->clear();
277  le_sigma ->clear();
278  le_delta ->clear();
279 
280  cb_shape ->setCurrentIndex( 0 );
281  ct_oligomer->setValue( 1.0 );
282  pb_load_c0 ->setIcon( QIcon() );
283  ck_co_sed ->setChecked( false );
284 
285  if ( oldRow == (-2) )
286  {
287  le_vbar ->setEnabled( false );
288  le_extinction->setEnabled( false );
289  le_sigConc ->setEnabled( false );
290  le_mw ->setEnabled( false );
291  le_f_f0 ->setEnabled( false );
292  le_s ->setEnabled( false );
293  le_D ->setEnabled( false );
294  le_f ->setEnabled( false );
295  le_sigma ->setEnabled( false );
296  le_delta ->setEnabled( false );
297  ct_oligomer ->setEnabled( false );
298  ck_co_sed ->setEnabled( false );
299  ck_mw ->setEnabled( false );
300  ck_f_f0 ->setEnabled( false );
301  ck_s ->setEnabled( false );
302  ck_D ->setEnabled( false );
303  ck_f ->setEnabled( false );
304  }
305 }
306 
308 {
309  update( 0 );
310 
311  save_changes( lw_components->currentRow() );
312  oldRow = -1;
313 
315  model.components << sc;
316  int last = model.components.size() - 1;
317  lw_components->setCurrentRow( last );
318 
319  US_AnalyteGui* dialog =
320  new US_AnalyteGui( true, QString(), db_access );
321 
322  connect( dialog, SIGNAL( valueChanged ( US_Analyte ) ),
323  SLOT ( update_analyte( US_Analyte ) ) );
324 
325  connect( dialog, SIGNAL( use_db ( bool ) ),
326  SLOT ( source_changed( bool ) ) );
327 
328  // If accepted, work is done by update_analyte
329  if ( dialog->exec() == QDialog::Rejected )
330  {
331  update_lw();
332 
333  lw_components->setCurrentRow( last ); // Runs update() via signal
334  calculate();
335  }
336 }
337 
339 {
340  analyte = new_analyte;
341  int last = lw_components->currentRow();
342 
343  if ( last < 0 )
344  last = model.components.count() - 1;
345 
346  update( 0 );
347 
348  if ( model.wavelength == 0.0 )
349  { // If model has no wavelength, set it from the analyte
350  QList< double > keys = analyte.extinction.keys();
351  if ( keys.length() > 0 )
352  model.wavelength = keys[ 0 ];
353  }
354 
356 
357  sc->name = analyte.description;
359  sc->mw = analyte.mw;
360  sc->vbar20 = analyte.vbar20;
362 qDebug() << "Prop: updAna: extinc" << sc->extinction;
363 
364  le_extinction->setText( QString::number( sc->extinction ) );
365  set_molar();
366 
367  le_guid ->setText( sc->analyteGUID );
368  update_lw();
369 
370  lw_components->setCurrentRow( last ); // Runs update() via signal
371  calculate();
372 }
373 
375 {
376  int row = lw_components->currentRow();
377  if ( row < 0 ) return;
378 
379  QListWidgetItem* item = lw_components->item( row );
380  int response = QMessageBox::question( this,
381  tr( "Delete Analyte?" ),
382  tr( "Delete the following analyte?\n" ) + item->text(),
383  QMessageBox::Yes, QMessageBox::No );
384 
385  if ( response == QMessageBox::No ) return;
386 
387  if ( model.coSedSolute == row ) model.coSedSolute = -1;
388 
389  model.components.remove( row );
390  lw_components->setCurrentRow( -1 );
391  delete lw_components->takeItem( row );
392 
393  oldRow = -1;
394  clear_entries();
395  le_description->clear();
396 }
397 
399 {
400  lw_components->clear();
401 
402  for ( int i = 0; i < model.components.size(); i++ )
403  lw_components->addItem( model.components[ i ].name );
404 }
405 
406 void US_Properties::set_oligomer( double oligomer )
407 {
408  int row = lw_components->currentRow();
409  if ( row < 0 ) return;
410 
412 
413  inUpdate = true;
414 
415  sc->mw /= sc->oligomer; // Get monomer mw
416  sc->mw *= oligomer; // Now adjust for new oligomer count
417  le_mw->setText( QString::number( sc->mw, 'e', 3 ) );
418 
419  us_setReadOnly( le_mw, !ck_mw->isChecked() );
420 
421  sc->extinction /= sc->oligomer;
422  sc->extinction *= oligomer;
423  le_extinction->setText( QString::number( sc->extinction, 'e', 4 ) );
424 
425  sc->oligomer = (int) oligomer;
426 
427  //hydro_data.mw = sc->mw;
428  hydro_data.mw = le_mw->text().toDouble();
431  hydro_data.vbar = sc->vbar20;
433 
435 
436  set_molar();
437  //inUpdate = false;
438  //select_shape( sc->shape );
439 
440  if ( oligomer > 1.0 )
441  { // if oligomer count greater than 1, must check MW and frictional ratio
442  if ( ! ( ck_mw->isChecked() && ck_f_f0->isChecked() ) )
443  { // mw,f_f0 not both checked, so make it so
444  ck_mw ->setChecked( true );
445  ck_f_f0->setChecked( true );
446  ck_s ->setChecked( false );
447  ck_D ->setChecked( false );
448  ck_f ->setChecked( false );
449  checkbox();
450  }
451 
452  us_setReadOnly( le_mw, true); // MW entry always disabled w oligomer > 1
453  }
454 
455  bool mwuck = ! ck_mw->isChecked();
456  bool scck = ck_s ->isChecked();
457 
458  if ( mwuck )
459  { // if MW unchecked, fake it for re-calculate coeffs phase
460  ck_mw->setChecked( true );
461  ck_s ->setChecked( false );
462  }
463 
464  inUpdate = false;
465  chgStoi = true;
466 
467  // re-calculate coefficients based on oligomer,mw changes
468  calculate();
469 
470  chgStoi = false;
471  if ( mwuck )
472  { // if MW was unchecked, restore check state to pre-calc state
473  inUpdate = true;
474  ck_mw->setChecked( false );
475  ck_s ->setChecked( scck );
476  checkbox();
477  inUpdate = false;
478  }
479 }
480 
482 {
483  int row = lw_components->currentRow();
484  if ( row < 0 ) return;
485 
486  QString desc = le_description->text().trimmed();
487  if ( desc.isEmpty() ) return;
488 
489  if ( desc == lw_components->item( row )->text() ) return;
490 
491  if ( keep_standard() ) // Do we want to change from the standard values?
492  {
493  // Restore the description
494  le_description->setText( lw_components->item( row )->text() );
495  return;
496  }
497 
498  lw_components->disconnect( SIGNAL( currentRowChanged( int ) ) );
499  delete lw_components->currentItem();
500 
501  lw_components->insertItem( row, new QListWidgetItem( desc ) );
502  lw_components->setCurrentRow( row );
503 
505  sc->name = desc;
506 
507  connect( lw_components, SIGNAL( currentRowChanged( int ) ),
508  SLOT ( update ( int ) ) );
509  clear_guid();
510 }
511 
513 {
514  int row = lw_components->currentRow();
515  if ( row < 0 ) return;
516 
518 
519  if ( keep_standard() ) // Change from standard values?
520  {
521  le_vbar->setText( QString::number( sc->vbar20, 'e', 4 ) );
522  return;
523  }
524 
525  sc->vbar20 = le_vbar->text().toDouble();
526 
527  clear_guid();
528  calculate();
529 }
530 
532 {
533  int row = lw_components->currentRow();
534 
535  if ( row < 0 ) return;
536 
537  // See if the initialization vector is already loaded.
538  if ( ! pb_load_c0->icon().isNull() )
539  {
540  int response = QMessageBox::question( this,
541  tr( "Remove C0 Data?" ),
542  tr( "The C0 infomation is loaded.\n"
543  "Remove it?" ),
544  QMessageBox::Yes, QMessageBox::No );
545 
546  if ( response == QMessageBox::Yes )
547  {
549 
550  sc->c0.radius .clear();
551  sc->c0.concentration.clear();
552  pb_load_c0->setIcon( QIcon() );
553  }
554 
555  return;
556  }
557 
558  QMessageBox::information( this,
559  tr( "UltraScan Information" ),
560  tr( "Please note:\n\n"
561  "The initial concentration file should have\n"
562  "the following format:\n\n"
563  "radius_value1 concentration_value1\n"
564  "radius_value2 concentration_value2\n"
565  "radius_value3 concentration_value3\n"
566  "etc...\n\n"
567  "radius values smaller than the meniscus or\n"
568  "larger than the bottom of the cell will be\n"
569  "excluded from the concentration vector." ) );
570 
571  QString fn = QFileDialog::getOpenFileName(
572  this, tr( "Load initial concentration" ), US_Settings::resultDir(), "*" );
573 
574  if ( ! fn.isEmpty() )
575  {
576  QFile f( fn );;
577 
578  if ( f.open( QIODevice::ReadOnly | QIODevice::Text ) )
579  {
580  QTextStream ts( &f );
581 
582  int row = lw_components->currentRow();
583 
585 
586  sc->c0.radius .clear();
587  sc->c0.concentration.clear();
588 
589  // Sets concentration for this component to -1 to signal that we are
590  // using a concentration vector
591  double val1;
592  double val2;
593 
594  while ( ! ts.atEnd() )
595  {
596  ts >> val1;
597  ts >> val2;
598 
599  if ( val1 > 0.0 ) // Ignore radius pairs that aren't positive
600  {
601  sc->c0.radius .push_back( val1 );
602  sc->c0.concentration .push_back( val2 );
603  }
604  }
605 
606  f.close();
607  pb_load_c0->setIcon( check );
608  }
609  else
610  {
611  QMessageBox::warning( this,
612  tr( "UltraScan Warning" ),
613  tr( "UltraScan could not open the file specified\n" ) + fn );
614  }
615  }
616 }
617 
619 {
620  if ( inUpdate ) return;
621 
622  int row = lw_components->currentRow();
623  if ( row < 0 ) return;
624 
626 
627  switch ( shape )
628  {
629  case US_Model::PROLATE:
630  le_f_f0->setText( QString::number( hydro_data.prolate.f_f0, 'e', 3 ));
631  le_s ->setText( QString::number( hydro_data.prolate.s, 'e', 4 ));
632  le_D ->setText( QString::number( hydro_data.prolate.D, 'e', 4 ));
633  le_f ->setText( QString::number( hydro_data.prolate.f, 'e', 4 ));
634  break;
635 
636  case US_Model::OBLATE:
637  le_f_f0->setText( QString::number( hydro_data.oblate.f_f0, 'e', 3 ) );
638  le_s ->setText( QString::number( hydro_data.oblate.s, 'e', 4 ) );
639  le_D ->setText( QString::number( hydro_data.oblate.D, 'e', 4 ) );
640  le_f ->setText( QString::number( hydro_data.oblate.f, 'e', 4 ) );
641  break;
642 
643  case US_Model::ROD:
644  le_f_f0->setText( QString::number( hydro_data.rod.f_f0, 'e', 3 ) );
645  le_s ->setText( QString::number( hydro_data.rod.s, 'e', 4 ) );
646  le_D ->setText( QString::number( hydro_data.rod.D, 'e', 4 ) );
647  le_f ->setText( QString::number( hydro_data.rod.f, 'e', 4 ) );
648  break;
649 
650  default: //SPHERE
651  le_f_f0->setText( QString::number( hydro_data.sphere.f_f0, 'e', 3 ) );
652  le_s ->setText( QString::number( hydro_data.sphere.s, 'e', 4 ) );
653  le_D ->setText( QString::number( hydro_data.sphere.D, 'e', 4 ) );
654  le_f ->setText( QString::number( hydro_data.sphere.f, 'e', 4 ) );
655  break;
656  }
657 
658  sc->f_f0 = le_f_f0->text().toDouble();
659  sc->f = le_f ->text().toDouble();
660  sc->s = le_s ->text().toDouble();
661  sc->D = le_D ->text().toDouble();
662 }
663 
665 {
666  int row = lw_components->currentRow();
667  if ( row < 0 ) return;
668 
670 
671  double extinction = le_extinction ->text().toDouble();
672  double signalConc = le_sigConc ->text().toDouble();
673 
674  if ( extinction > 0.0 )
675  sc->molar_concentration = signalConc / extinction;
676  else
677  sc->molar_concentration = 0.0;
678 
679  le_molConc->setText( QString::number( sc->molar_concentration, 'e', 4 ) );
680 }
681 
683 {
684  int row = lw_components->currentRow();
685  if ( row < 0 ) return;
686 
688 
689  sc->analyteGUID.clear();
690  le_guid->clear();
691 }
692 
694 {
695  if ( row < 0 ) return;
696 
698 
699  // Description
700  sc->name = lw_components->item( row )->text();
701 
702  // guid
703  if ( le_guid->text().isEmpty() )
704  sc->analyteGUID.clear();
705  else
706  sc->analyteGUID = le_guid->text();
707 
708  // vbar
709  sc->vbar20 = le_vbar->text().toDouble();
710 
711  // Extinction
712  sc->extinction = le_extinction->text().toDouble();
713 
714  // Molar concentration
715  sc->molar_concentration = le_molConc->text().toDouble();
716 
717  // Signal concentration
718  sc->signal_concentration = le_sigConc->text().toDouble();
719 
720  // Shape
721  switch ( cb_shape->currentIndex() )
722  {
723  case US_Model::SPHERE :
724  sc->shape = US_Model::SPHERE; break;
725 
726  case US_Model::PROLATE:
727  sc->shape = US_Model::PROLATE; break;
728 
729  case US_Model::OBLATE :
730  sc->shape = US_Model::OBLATE; break;
731 
732  default:
733  sc->shape = US_Model::ROD; break;
734  }
735 
736  int shape = cb_shape->itemData( cb_shape->currentIndex() ).toInt();
737  sc->shape = ( US_Model::ShapeType ) shape;
738 
739  // Characteristics
740  sc->mw = le_mw ->text().toDouble();
741  sc->s = le_s ->text().toDouble();
742  sc->D = le_D ->text().toDouble();
743  sc->f = le_f ->text().toDouble();
744  sc->f_f0 = le_f_f0 ->text().toDouble();
745  sc->sigma = le_sigma->text().toDouble();
746  sc->delta = le_delta->text().toDouble();
747 
748  // c0 values are already set
749  // co-sed is already set
750 }
751 
752 void US_Properties::update( int /* row */ )
753 {
754  if ( oldRow == (-2) )
755  {
756  le_vbar ->setEnabled( true );
757  le_extinction ->setEnabled( true );
758  le_sigConc ->setEnabled( true );
759  le_mw ->setEnabled( true );
760  le_f_f0 ->setEnabled( true );
761  le_s ->setEnabled( true );
762  le_D ->setEnabled( true );
763  le_f ->setEnabled( true );
764  le_sigma ->setEnabled( true );
765  le_delta ->setEnabled( true );
766  ct_oligomer ->setEnabled( true );
767  ck_co_sed ->setEnabled( true );
768  ck_mw ->setEnabled( true );
769  ck_f_f0 ->setEnabled( true );
770  oldRow = -1;
771  }
772 
773  int row = lw_components->currentRow();
774  if ( row < 0 ) return;
775 
776  // Save current data
777  save_changes( oldRow );
778  oldRow = row;
779 
780  // Update to current data
782 
783  le_description->setText( sc->name );
784 
785  // Set guid
786  if ( sc->analyteGUID.isEmpty() )
787  le_guid->clear();
788  else
789  {
790  le_guid->setText( sc->analyteGUID );
791  }
792 
793  inUpdate = true;
794 
795  // Set vbar
796  le_vbar->setText( QString::number( sc->vbar20, 'e', 4 ) );
797 
798  // Set extinction and concentration
799  le_extinction ->setText( QString::number( sc->extinction, 'e', 4 ));
800 
801  le_molConc ->setText( QString::number( sc->molar_concentration, 'e', 4 ));
802  le_sigConc ->setText( QString::number( sc->signal_concentration,'e', 4 ));
803 
804  // Update hydro data
805  hydro_data.mw = sc->mw;
808  hydro_data.vbar = sc->vbar20;
810 
812 
813  // Set shape
814  switch ( sc->shape )
815  {
816  case US_Model::SPHERE : cb_shape->setCurrentIndex( 0 ); break;
817  case US_Model::PROLATE: cb_shape->setCurrentIndex( 1 ); break;
818  case US_Model::OBLATE : cb_shape->setCurrentIndex( 2 ); break;
819  default: cb_shape->setCurrentIndex( 3 ); break;
820  }
821 
822  // Set characteristics
823  le_mw ->setText( QString::number( sc->mw , 'e', 3 ) );
824  le_f_f0 ->setText( QString::number( sc->f_f0 , 'e', 3 ) );
825  le_s ->setText( QString::number( sc->s , 'e', 4 ) );
826  le_D ->setText( QString::number( sc->D , 'e', 4 ) );
827  le_f ->setText( QString::number( sc->f , 'e', 4 ) );
828  le_sigma->setText( QString::number( sc->sigma, 'e', 4 ) );
829  le_delta->setText( QString::number( sc->delta, 'e', 4 ) );
830 
831  // Set load_co indication
832  ( sc->c0.radius.size() > 0 ) ? pb_load_c0->setIcon( check )
833  : pb_load_c0->setIcon( QIcon() );
834  // Set co-sedimenting solute
835  ( row == model.coSedSolute ) ? ck_co_sed->setChecked( true )
836  : ck_co_sed->setChecked( false );
837 
838  ct_oligomer->setValue( sc->oligomer );
839  inUpdate = false;
840 }
841 
843 {
844  int row = lw_components->currentRow();
845  if ( row < 0 ) return;
847 
848  if ( sc->analyteGUID.isEmpty() )
849  analyte.analyteGUID.clear();
850  else
852 
853  if ( sc->name.isEmpty() )
854  analyte.description.clear();
855  else
856  analyte.description = sc->name;
857 
858  //hydro_data.density = DENS_20W;
859  //hydro_data.viscosity = VISC_20W;
860  //hydro_data.vbar = analyte.vbar20;
861  //hydro_data.temperature = NORMAL_TEMP;
862  //hydro_data.mw = analyte.mw;
863  //hydro_data.axial_ration = ??
864  //hydro_data.guid = analyte.guid;
865 
866 
867  working_data = hydro_data; // working_data will be updated
868 
869  US_Predict1* dialog = new US_Predict1(
870  working_data, analyte, db_access, true );
871 
872  connect( dialog, SIGNAL( changed ( US_Analyte ) ),
873  SLOT ( new_hydro ( US_Analyte ) ) );
874 
875  connect( dialog, SIGNAL( use_db ( bool ) ),
876  SLOT ( source_changed( bool ) ) );
877  dialog->exec();
878 }
879 
881 {
882  int row = lw_components->currentRow();
883  if ( row < 0 ) return; // Should never happen
884 
886 
888  //working_data.mw *= sc->oligomer;
889  analyte = ad;
890 
892 
893  // Set the name of the component
894  if ( ! ad.description.isEmpty() )
895  {
896  lw_components->disconnect( SIGNAL( currentRowChanged( int ) ) );
897  delete lw_components->currentItem();
898  lw_components->insertItem( row, new QListWidgetItem( ad.description ) );
899  lw_components->setCurrentRow( row );
900 
901  connect( lw_components, SIGNAL( currentRowChanged( int ) ),
902  SLOT ( update ( int ) ) );
903 
904  sc->name = ad.description;
905  le_description->setText( ad.description );
906  }
907 
908  // Set guid
909  le_guid->setText( ad.analyteGUID );
910  sc->analyteGUID = ad.analyteGUID;
911 
912  // Set extinction
913  double exval = sc->extinction;
914  //QList< double > keys;
915 
916  switch ( model.optics )
917  {
919  if ( analyte.extinction.size() > 0 )
920  exval = analyte.extinction[ model.wavelength ] * sc->oligomer;
921  break;
922 
924  if ( analyte.refraction.size() > 0 )
925  exval = analyte.refraction[ model.wavelength ] * sc->oligomer;
926  break;
927 
929  if ( analyte.fluorescence.size() > 0 )
930  exval = analyte.fluorescence[ model.wavelength ] * sc->oligomer;
931  break;
932  }
933 
934  le_extinction->setText( QString::number( exval, 'e', 4 ) );
935  sc->extinction = exval;
936 
937  // Set vbar(20), mw
938  le_mw ->setText( QString::number( hydro_data.mw, 'e', 3 ) );
939  le_vbar->setText( QString::number( hydro_data.vbar, 'e', 4 ) );
940 
941  sc->mw = hydro_data.mw;
942  sc->vbar20 = hydro_data.vbar;
944 
945  // Set f/f0, s, D, and f for shape
946  cb_shape->setEnabled( true );
947  int shape = cb_shape->itemData( cb_shape->currentIndex() ).toInt();
948  select_shape( shape );
949 
950  inUpdate = true;
951  set_molar();
952  inUpdate = false;
953 }
954 
956 {
957  update( 0 ); // Parameter is ignored
958  emit done();
959  accept();
960 }
961 
963 {
964  if ( countChecks() != 2 )
965  {
966  us_setReadOnly( le_mw , false );
967  us_setReadOnly( le_s , false );
968  us_setReadOnly( le_D , false );
969  us_setReadOnly( le_f , false );
970  us_setReadOnly( le_f_f0, false );
971  return;
972  }
973 
974  us_setReadOnly( le_mw , !ck_mw ->isChecked() );
975  us_setReadOnly( le_s , !ck_s ->isChecked() );
976  us_setReadOnly( le_D , !ck_D ->isChecked() );
977  us_setReadOnly( le_f , !ck_f ->isChecked() );
978  us_setReadOnly( le_f_f0, !ck_f_f0->isChecked() );
979 
980  if ( (int)ct_oligomer->value() > 1 )
981  us_setReadOnly( le_mw , true );
982 }
983 
984 void US_Properties::enable( QLineEdit* le, bool status, const QPalette& p )
985 {
986  le->setReadOnly( status );
987  le->setPalette ( p );
988 }
989 
991 {
992  int checked = 0;
993  if ( ck_mw ->isChecked() ) checked++;
994  if ( ck_s ->isChecked() ) checked++;
995  if ( ck_D ->isChecked() ) checked++;
996  if ( ck_f ->isChecked() ) checked++;
997  if ( ck_f_f0->isChecked() ) checked++;
998  return checked;
999 }
1000 
1002 {
1003  if ( ! ck_mw ->isChecked() ) le_mw ->setText( tr( "n/a" ) );
1004  if ( ! ck_s ->isChecked() ) le_s ->setText( tr( "n/a" ) );
1005  if ( ! ck_D ->isChecked() ) le_D ->setText( tr( "n/a" ) );
1006  if ( ! ck_f ->isChecked() ) le_f ->setText( tr( "n/a" ) );
1007  if ( ! ck_f_f0->isChecked() ) le_f_f0->setText( tr( "n/a" ) );
1008  checkbox();
1009 }
1010 
1011 void US_Properties::co_sed( int new_state )
1012 {
1013  if ( inUpdate ) return;
1014 
1015  if ( new_state == Qt::Checked )
1016  {
1017  int row = lw_components->currentRow();
1018 
1019  if ( model.coSedSolute != -1 )
1020  {
1021  int response = QMessageBox::question( this,
1022  tr( "Change co-sedimenting solute?" ),
1023  tr( "Another component is marked as the co-sedimenting solute.\n"
1024  "Change it to the current analyte?" ),
1025  QMessageBox::Yes, QMessageBox::No );
1026 
1027  if ( response == QMessageBox::No )
1028  {
1029  ck_co_sed->disconnect();
1030  ck_co_sed->setChecked( false );
1031  connect( ck_co_sed, SIGNAL( stateChanged( int ) ),
1032  SLOT ( co_sed ( int ) ) );
1033  return;
1034  }
1035  }
1036  model.coSedSolute = row;
1037  }
1038  else
1039  model.coSedSolute = -1;
1040 }
1041 
1043 {
1044  if ( le_guid->text().isEmpty() ) return false;
1045 
1046  int response = QMessageBox::question( this,
1047  tr( "Changing Standard Value" ),
1048  tr( "You are changing a value that does not correspond\n"
1049  "with a saved analyte.\n\n"
1050  "Continue?" ),
1051  QMessageBox::Yes, QMessageBox::No );
1052 
1053  if ( response == QMessageBox::Yes )
1054  {
1055  clear_guid();
1056  //le_wavelength->clear();
1057  analyte.extinction .clear();
1058  analyte.refraction .clear();
1059  analyte.fluorescence.clear();
1060  cb_shape->setEnabled( false );
1061  return false;
1062  }
1063 
1064  return true;
1065 }
1066 
1068 {
1069  int row = lw_components->currentRow();
1070 
1071  if ( inUpdate || row < 0 )
1072  return;
1073 
1075 
1076  checkbox();
1077 
1078  // First do some sanity checking
1079  double vbar = le_vbar->text().toDouble();
1080 
1081  if ( row < 0 || vbar <= 0.0 )
1082  return;
1083 
1084  // Exactly two checkboxes must be set
1085  if ( countChecks() < 2 )
1086  {
1087  ck_mw ->setEnabled( true );
1088  ck_f_f0->setEnabled( true );
1089  ck_f ->setEnabled( true );
1090  ck_s ->setEnabled( true );
1091  ck_D ->setEnabled( true );
1092  return;
1093  }
1094 
1095  // disable all check boxes except for the two set
1096  ck_mw ->setEnabled( ck_mw ->isChecked() );
1097  ck_f_f0->setEnabled( ck_f_f0->isChecked() );
1098  ck_f ->setEnabled( ck_f ->isChecked() );
1099  ck_s ->setEnabled( ck_s ->isChecked() );
1100  ck_D ->setEnabled( ck_D ->isChecked() );
1101 
1102  // set values for checked boxes; clear others
1103  sc->mw = ck_mw ->isChecked() ? le_mw ->text().toDouble() :
1104  ( chgStoi ? sc->mw : 0.0 );
1105  sc->f_f0 = ck_f_f0->isChecked() ? le_f_f0->text().toDouble() : 0.0;
1106  sc->f = ck_f ->isChecked() ? le_f ->text().toDouble() : 0.0;
1107  sc->s = ck_s ->isChecked() ? le_s ->text().toDouble() : 0.0;
1108  sc->D = ck_D ->isChecked() ? le_D ->text().toDouble() : 0.0;
1109 
1110  // re-calculate coefficients based on the two that are set
1112 
1113  // fill in text boxes with given and calculated coefficients
1114  le_mw ->setText( QString::number( sc->mw , 'e', 3 ) );
1115  le_f_f0->setText( QString::number( sc->f_f0, 'e', 3 ) );
1116  le_s ->setText( QString::number( sc->s , 'e', 4 ) );
1117  le_D ->setText( QString::number( sc->D , 'e', 4 ) );
1118  le_f ->setText( QString::number( sc->f , 'e', 4 ) );
1119 
1120  // search to see if present component is a product
1121  bool is_prod = false;
1122 
1123  for ( int ii = 0; ii < model.associations.count(); ii++ )
1124  {
1126 
1127  for ( int jj = 0; jj < as->rcomps.count(); jj++ )
1128  {
1129  if ( as->rcomps[ jj ] == row && as->stoichs[ jj ] < 0 )
1130  {
1131  is_prod = true;
1132  le_sigConc->setText( "0.0" );
1133  break;
1134  }
1135  }
1136  }
1137 
1138  ck_isProd ->setChecked( is_prod );
1139  le_sigConc->setEnabled( ! is_prod );
1140  us_setReadOnly( le_sigConc, is_prod );
1141 }
1142 
1144 {
1145  emit use_db( db ); // Just pass on the signal
1146  qApp->processEvents();
1147 }
1148 
1149 // Slot to edit the currently selected analyte
1151 {
1152  int row = lw_components->currentRow();
1153  QString aguid = le_guid->text();
1154  if ( aguid.isEmpty() )
1155  aguid = model.components[ row ].analyteGUID;
1156 
1157  US_AnalyteGui* dialog = new US_AnalyteGui( true, aguid, db_access );
1158 
1159  connect( dialog, SIGNAL( valueChanged ( US_Analyte ) ),
1160  SLOT ( update_analyte( US_Analyte ) ) );
1161 
1162  connect( dialog, SIGNAL( use_db ( bool ) ),
1163  SLOT ( source_changed( bool ) ) );
1164 
1165  // If accepted, work is done by update_analyte
1166  dialog->exec();
1167 }
1168 
1169 // Slot to make adjustments with molar check changed
1171 {
1172  // Set read-only states of concentration edits
1173  us_setReadOnly( le_molConc, !chkd );
1174  us_setReadOnly( le_sigConc, chkd );
1175 
1176  // Flip check state of signal to opposite of molar
1177  ck_sigConc->disconnect();
1178  ck_sigConc->setChecked( !chkd );
1179  connect( ck_sigConc, SIGNAL( toggled( bool ) ),
1180  SLOT( check_signal( bool ) ) );
1181 }
1182 
1183 // Slot to make adjustments with signal check changed
1185 {
1186  // Set read-only states of concentration edits
1187  us_setReadOnly( le_sigConc, !chkd );
1188  us_setReadOnly( le_molConc, chkd );
1189 
1190  // Flip check state of molar to opposite of signal
1191  ck_molConc->disconnect();
1192  ck_molConc->setChecked( !chkd );
1193  connect( ck_molConc, SIGNAL( toggled( bool ) ),
1194  SLOT( check_molar( bool ) ) );
1195 }
1196