source: trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.cpp @ 2825

Last change on this file since 2825 was 2825, checked in by alexey, 5 months ago

A seemingly stable solution is finally found for arbitrary switching to Manage Optima Runs from actively on-going LIVE UPDATE phase:

  • tested transition from all stages of data acqusition (beginning, reloading, updating, together with/without sysdata update)
  • all processes are properly finished (sysdata thread/timer, data retrieval/update timers)
  • tested from home machine (long DB interaction times) and from demeler3 (short DB interaction times)
  • tested on infinitely looped initial data retreival/ data update processes for selected runs; NEEDS testing on real-time experiments
  • Property svn:keywords set to LastChangedDate Author
File size: 159.0 KB
Line 
1#include <QApplication>
2#include <QtSql>
3
4#include "us_xpn_viewer_gui.h"
5#include "us_tmst_plot.h"
6#include "us_license_t.h"
7#include "us_license.h"
8#include "us_util.h"
9#include "us_settings.h"
10#include "us_gui_settings.h"
11#include "us_plot.h"
12#include "us_math2.h"
13#include "us_db2.h"
14#include "us_passwd.h"
15#include "us_investigator.h"
16#include "us_constants.h"
17#include "us_report.h"
18#include "us_gui_util.h"
19#include "us_util.h"
20#include "us_crypto.h"
21#include "us_editor.h"
22#include "us_images.h"
23#include "us_colorgradIO.h"
24#include "qwt_legend.h"
25
26#if QT_VERSION < 0x050000
27#define setSamples(a,b,c)  setData(a,b,c)
28#define setMinimum(a)      setMinValue(a)
29#define setMaximum(a)      setMaxValue(a)
30#define setSymbol(a)       setSymbol(*a)
31#define AXISSCALEDIV(a)    data_plot->axisScaleDiv(a)
32#define dPlotClearAll(a) a->clear()
33#else
34#include "qwt_picker_machine.h"
35#define AXISSCALEDIV(a)    (QwtScaleDiv*)&data_plot->axisScaleDiv(a)
36#define dPlotClearAll(a) a->detachItems(QwtPlotItem::Rtti_PlotItem,true)
37#endif
38
39#ifdef WIN32
40#include <float.h>
41#define isnan _isnan
42#endif
43
44#ifndef DbgLv
45#define DbgLv(a) if(dbg_level>=a)qDebug()
46#endif
47
48// DialBox
49DialBox::DialBox( QWidget *parent ):
50  QWidget( parent )
51{
52    d_dial = createDial();
53    d_label = new QLabel( this );
54    d_label->setAlignment( Qt::AlignCenter );
55    d_label->setStyleSheet("font: bold;color: black;");
56   
57    QVBoxLayout *layout = new QVBoxLayout( this );;
58    layout->setSpacing( 0 );
59    layout->addWidget( d_dial, 15 );
60    layout->addWidget( d_label );
61
62    connect( d_dial, SIGNAL( valueChanged( double ) ), this, SLOT( setNum( double ) ) );
63   
64    setNum( d_dial->value() );
65}
66
67void DialBox::setSpeed( double v )
68{
69  d_dial->setValue( v );
70}
71
72void DialBox::setNum( double v )
73{
74    QString text;
75    //text.setNum( v, 'f', 2 );
76    text = "Rotor Speed: " + QString::number(v*1000) + " rpm";
77
78    d_label->setText( text );
79}
80
81SpeedoMeter *DialBox::createDial( void ) const 
82{
83  SpeedoMeter *dial = new SpeedoMeter;
84
85  dial->setScaleStepSize( 5 );
86  dial->setScale( 0, 60 );
87  dial->scaleDraw()->setPenWidth( 2 );
88  dial->setValue(0);
89
90  return dial;
91}
92
93// END of Dial box
94
95
96// Speedometer
97SpeedoMeter::SpeedoMeter( QWidget *parent ):
98    QwtDial( parent ),
99    d_label( "RPM" )
100{
101    QwtRoundScaleDraw *scaleDraw = new QwtRoundScaleDraw();
102    scaleDraw->setSpacing( 8 );
103    scaleDraw->enableComponent( QwtAbstractScaleDraw::Backbone, false );
104    scaleDraw->setTickLength( QwtScaleDiv::MinorTick, 0 );
105    scaleDraw->setTickLength( QwtScaleDiv::MediumTick, 4 );
106    scaleDraw->setTickLength( QwtScaleDiv::MajorTick, 8 );
107    setScaleDraw( scaleDraw );
108
109    setWrapping( false );
110    setReadOnly( true );
111
112    setOrigin( 135.0 );
113    setScaleArc( 0.0, 270.0 );
114
115   
116    QwtDialSimpleNeedle *needle = new QwtDialSimpleNeedle(
117        QwtDialSimpleNeedle::Arrow, true, Qt::red,
118        QColor( Qt::gray ).light( 130 ) );
119    setNeedle( needle );
120}
121
122void SpeedoMeter::setLabel( const QString &label )
123{
124    d_label = label;
125    update();
126}
127
128QString SpeedoMeter::label() const
129{
130    return d_label;
131}
132
133// Reloaded virtual function - needed to display units label (RPM)
134void SpeedoMeter::drawScaleContents( QPainter *painter,
135    const QPointF &center, double radius ) const
136{
137    QRectF rect( 0.0, 0.0, 2.0 * radius, 2.0 * radius - 10.0 );
138    rect.moveCenter( center );
139
140    const QColor color = palette().color( QPalette::Text );
141    painter->setPen( color );
142
143    const int flags = Qt::AlignBottom | Qt::AlignHCenter;
144    painter->drawText( rect, flags, d_label );
145}
146// END of Speedometer calss
147
148// WheelBox
149WheelBox::WheelBox( Qt::Orientation orientation, QWidget *parent ): QWidget( parent )
150{
151    QWidget *box = createBox( orientation );
152    d_label = new QLabel( this );
153    d_label->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
154    d_label->setStyleSheet("font: bold;color: black;");
155
156    QVBoxLayout *layout       = new QVBoxLayout( this );
157    layout->addWidget( box, 15 );
158    layout->addWidget( d_label );
159
160    //connect( d_thermo, SIGNAL( valueChanged( double ) ), this, SLOT( setNum( double ) ) );
161   
162    setNum( d_thermo->value() );
163}
164
165QWidget *WheelBox::createBox( Qt::Orientation orientation ) 
166{
167    d_thermo = new QwtThermo();
168    d_thermo->setOrientation( orientation );
169
170    d_thermo->setScalePosition( QwtThermo::TrailingScale );
171
172    QwtLinearColorMap *colorMap = new QwtLinearColorMap(); 
173    colorMap->setColorInterval( Qt::blue, Qt::red );
174    d_thermo->setColorMap( colorMap );
175
176    double min = 0;
177    double max = 40;
178
179    d_thermo->setScale( min, max );
180    d_thermo->setValue( min );
181
182    QWidget *box = new QWidget();
183    QBoxLayout *layout;
184    layout = new QVBoxLayout( box );
185
186    layout->addWidget( d_thermo, Qt::AlignCenter );
187   
188    return box;
189}
190
191void WheelBox::setTemp( double v )
192{
193  qDebug() << "Setting Temperature!!! Value: " << v ;
194  d_thermo->setValue( v );
195
196  setNum( v );
197}
198
199void WheelBox::setNum( double v )
200{
201 
202    QString text;
203    //text.setNum( v, 'f', 2 );
204
205    text = "Temp.: " + QString::number( v, 'f', 1 ) + QChar(0x2103);
206    d_label->setText( text );
207}
208
209//END of WheelBox
210
211
212// Constructor for use in automated app
213US_XpnDataViewer::US_XpnDataViewer(QString auto_mode) : US_Widgets()
214{
215   const QChar chlamb( 955 );
216
217   setWindowTitle( tr( "Beckman Optima Data Viewer" ) );
218   setPalette( US_GuiSettings::frameColor() );
219
220   QGridLayout* settings    = new QGridLayout;
221   QGridLayout* live_params = new QGridLayout;
222   QGridLayout* time_params = new QGridLayout;
223
224   auto_mode_bool     = true;
225   experimentAborted  = false;
226   
227   navgrec      = 10;
228   dbg_level    = US_Settings::us_debug();
229   QFont sfont( US_GuiSettings::fontFamily(), US_GuiSettings::fontSize() - 1 );
230   QFontMetrics fmet( sfont );
231   int fwid     = fmet.maxWidth();
232   int lwid     = fwid * 4;
233   int swid     = lwid + fwid;
234   isMWL        = false;
235   isRaw        = true;
236   haveData     = false;
237   haveTmst     = false;
238   xpn_data     = NULL;
239   runID        = "";
240   runType      = "RI";
241   rlt_id       = 0;
242   currentDir   = "";
243   in_reload_auto    = false;
244   finishing_live_update = false;
245   in_reload_all_data  = false;
246   in_reload_data_init = false;
247   in_reload_check_sysdata  = false;
248   in_reload_end_processes  = false;
249   
250   ElapsedTimeOffset = 0;
251
252   //ALEXEY: new way
253   US_Passwd pw;
254   US_DB2*   dbP = new US_DB2( pw.getPasswd() );
255   if ( dbP != NULL )
256     read_optima_machines( dbP );
257
258   // for ( int ii = 0; ii < instruments.count(); ii++ )
259   //   sl_optimas << QString::number( instruments[ ii ].ID )
260   //     + ": " + instruments[ ii ].name;
261   
262   // cb_optima->clear();
263   // cb_optima->addItems( sl_optimas );
264   
265   // connect( cb_optima,    SIGNAL( activated      ( int ) ),
266   //          this,         SLOT  ( changeOptima   ( int ) ) );
267   
268   // changeOptima(0);
269   // /* End of Optima machines read */
270   
271   // Load controls     
272   QLabel*      lb_run      = us_banner( tr( "Load the Run" ) );
273   
274                 pb_loadXpn  = us_pushbutton( tr( "Load Raw Optima Data" ) );
275                 pb_loadAUC  = us_pushbutton( tr( "Load US3 AUC Data" ) );
276                 pb_reset    = us_pushbutton( tr( "Reset Data" ) );
277                 pb_details  = us_pushbutton( tr( "Data Details" ), true  );
278                 pb_plot2d   = us_pushbutton( tr( "Refresh Plot" ) );
279                 pb_saveauc  = us_pushbutton( tr( "Export openAUC" )  );
280                 pb_showtmst = us_pushbutton( tr( "Show Time State" )  );
281                 pb_reload   = us_pushbutton( tr( "Update Data" )      );
282                 pb_colmap   = us_pushbutton( tr( "Color Map" )        );
283
284   QLabel*      lb_dir      = us_label( tr( "Directory" ), -1 );
285                 le_dir      = us_lineedit( "", -1, true );
286
287   QLabel*      lb_dbhost   = us_label( tr( "DB Host" ), -1 );
288                 le_dbhost   = us_lineedit( "", -1, true );
289
290   QLabel*      lb_runID    = us_label( tr( "Run ID:" ), -1 );
291                 le_runID    = us_lineedit( "", -1, false );
292
293   QLabel*      lb_cellchn  = us_label( tr( "Cell/Channel:" ), -1 );
294                cb_cellchn  = us_comboBox();
295
296                le_colmap   = us_lineedit( "cm-rainbow", -1, true );
297
298   int rhgt     = le_runID->height();
299
300   // Plot controls     
301   QLabel*      lb_prcntls  = us_banner( tr( "Plot Controls" ) );
302   lb_prcntls->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
303
304   QLabel*      lb_rstart   = us_label( tr( "Radius Start:"   ), -1 );
305                 cb_rstart   = us_comboBox();
306   QLabel*      lb_rend     = us_label( tr( "Radius End:"     ), -1 );
307                 cb_rend     = us_comboBox();
308   QLabel*      lb_lrange    = us_label( tr( "%1 Range:"   ).arg( chlamb ), -1 );
309                le_lrange    = us_lineedit( "280 only", -1, true );
310    ptype_mw     = tr( "Plot %1:"    ).arg( chlamb );
311    ptype_tr     = tr( "Wavelength:" );
312    prectype     = ptype_tr;
313
314                lb_pltrec   = us_label( prectype, -1 );
315                cb_pltrec   = us_comboBox();
316   QLabel*      lb_optsys   = us_label( tr( "Optical System:" ), -1 );
317                cb_optsys   = us_comboBox();
318
319                pb_prev     = us_pushbutton( tr( "Previous" ) );
320                pb_next     = us_pushbutton( tr( "Next" ) );
321   us_checkbox( tr( "Always Auto-scale Y Axis" ), ck_autoscy, true );
322   us_checkbox( tr( "Auto Update" ),              ck_autorld, false );
323   pb_prev->setIcon( US_Images::getIcon( US_Images::ARROW_LEFT  ) );
324   pb_next->setIcon( US_Images::getIcon( US_Images::ARROW_RIGHT ) );
325
326
327   QLabel*      lb_rinterv  = us_label( tr( "Update Interval Seconds:" ), -1 );
328                ct_rinterv  = us_counter( 2, 10, 3600, 1 );
329   ct_rinterv->setFont( sfont );
330   ct_rinterv->setMinimumWidth( lwid );
331   ct_rinterv->resize( rhgt, swid );
332   ct_rinterv->setMinimum   (   10 );
333   ct_rinterv->setMaximum   ( 3600 );
334   ct_rinterv->setValue     (   60 );
335   ct_rinterv->setSingleStep(    1 );
336
337   // Scan controls     
338   QLabel*      lb_scanctl  = us_banner( tr( "Scan Control" ) );
339   QLabel*      lb_from     = us_label( tr( "From:" ) );
340   QLabel*      lb_to       = us_label( tr( "To:" ) );
341                ct_from     = us_counter( 3, 0, 500, 1 );
342                ct_to       = us_counter( 3, 0, 500, 1 );
343                pb_exclude  = us_pushbutton( tr( "Exclude Scan Range" ) );
344                pb_include  = us_pushbutton( tr( "Include All Scans"  ) );
345   ct_from  ->setFont( sfont );
346   ct_from  ->setMinimumWidth( lwid );
347   ct_from  ->resize( rhgt, swid );
348   ct_to    ->setFont( sfont );
349   ct_to    ->setMinimumWidth( lwid );
350   ct_to    ->resize( rhgt, swid );
351   ct_from  ->setValue( 0 );
352   ct_to    ->setValue( 0 );
353   ct_from  ->setSingleStep( 1 );
354   ct_to    ->setSingleStep( 1 );
355
356
357   // Status and standard pushbuttons
358   QLabel*      lb_status   = us_banner( tr( "Status" ) );
359   lb_status->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
360                le_status   = us_lineedit( tr( "(no data loaded)" ), -1, true );
361   QPalette stpal;
362   stpal.setColor( QPalette::Text, Qt::white );
363   stpal.setColor( QPalette::Base, Qt::blue  );
364   le_status->setPalette( stpal );
365
366   QPushButton* pb_help     = us_pushbutton( tr( "Help" ) );
367   QPushButton* pb_close    = us_pushbutton( tr( "Close" ) );
368
369   pb_stop =  us_pushbutton( tr( "STOP" ) );
370   pb_stop->setStyleSheet("font: bold;color: red;");
371
372   pb_close  ->setEnabled(false);
373
374      // Hide scan Control
375   if ( auto_mode.toStdString() == "AUTO")
376     {
377       pb_close->hide();
378       
379       // Hide Load controls
380       lb_run     ->hide();
381       pb_loadXpn ->hide();
382       pb_loadAUC ->hide();
383       pb_reset   ->hide();
384       pb_details ->hide();
385       pb_plot2d  ->hide();
386       pb_saveauc ->hide();
387       pb_showtmst->hide();
388       pb_reload  ->hide();
389       pb_colmap  ->hide();
390
391       lb_dir     ->hide();
392       le_dir     ->hide();
393       lb_dbhost  ->hide();
394       le_dbhost  ->hide();
395       lb_runID   ->hide();
396       le_runID   ->hide();
397       
398       le_colmap  ->hide();
399
400       // Hide some plot controls
401       lb_rstart  ->hide();
402       cb_rstart  ->hide();
403       lb_rend    ->hide();
404       cb_rend    ->hide();
405       ck_autoscy ->hide();
406       ck_autorld ->hide();
407       
408       // Hide interval controls
409       lb_rinterv->hide();
410       ct_rinterv->hide();
411       
412       // Hide Scan controls
413       lb_scanctl->hide();
414       lb_from   ->hide();
415       lb_to     ->hide();
416       ct_from   ->hide();
417       ct_to     ->hide();
418       pb_exclude->hide();
419       pb_include->hide();
420     
421     }
422   
423   // Default scan curve color list and count
424   QString cmfpath          = US_Settings::etcDir() + "/cm-rainbow.xml";
425 DbgLv(1) << "cmfpath" << cmfpath;
426   US_ColorGradIO::read_color_gradient( cmfpath, mcolors );
427   mcknt                    = mcolors.count();
428DbgLv(1) << "mcolors count" << mcknt;
429if(mcknt>0)
430 DbgLv(1) << "mcolors c0,cn" << mcolors[0] << mcolors[mcknt-1];
431
432   // Signals and Slots
433   connect( pb_loadXpn,   SIGNAL( clicked()      ),
434            this,         SLOT  ( load_xpn_raw() ) );
435   connect( pb_loadAUC,   SIGNAL( clicked()      ),
436            this,         SLOT  ( load_auc_xpn() ) );
437   connect( pb_reset,     SIGNAL( clicked()      ),
438            this,         SLOT  ( resetAll()     ) );
439   connect( pb_details,   SIGNAL( clicked()      ),
440            this,         SLOT  ( runDetails()   ) );
441   connect( pb_saveauc,   SIGNAL( clicked()      ),
442            this,         SLOT  ( export_auc()   ) );
443   connect( pb_reload,    SIGNAL( clicked()      ),
444            this,         SLOT  ( reloadData()   ) );
445   connect( ck_autorld,   SIGNAL( clicked()      ),
446            this,         SLOT  ( changeReload()             ) );
447   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
448            this,         SLOT  ( changeCellCh( )            ) );
449   connect( cb_rstart,    SIGNAL( currentIndexChanged( int ) ),
450            this,         SLOT  ( changeRadius( )            ) );
451   connect( cb_rend,      SIGNAL( currentIndexChanged( int ) ),
452            this,         SLOT  ( changeRadius( )            ) );
453   connect( cb_pltrec,    SIGNAL( currentIndexChanged( int ) ),
454            this,         SLOT  ( changeRecord( )            ) );
455   connect( pb_prev,      SIGNAL( clicked()  ),
456            this,         SLOT  ( prevPlot() ) );
457   connect( pb_next,      SIGNAL( clicked()  ),
458            this,         SLOT  ( nextPlot() ) );
459   connect( ct_from,      SIGNAL( valueChanged( double ) ),
460            this,         SLOT  ( exclude_from( double ) ) );
461   connect( ct_to,        SIGNAL( valueChanged( double ) ),
462            this,         SLOT  ( exclude_to  ( double ) ) );
463   connect( pb_exclude,   SIGNAL( clicked()       ),
464            this,         SLOT  ( exclude_scans() ) );
465   connect( pb_include,   SIGNAL( clicked()       ),
466            this,         SLOT  ( include_scans() ) );
467   connect( pb_plot2d,    SIGNAL( clicked()       ),
468            this,         SLOT  ( changeCellCh()  ) );
469   connect( pb_showtmst,  SIGNAL( clicked()       ),
470            this,         SLOT  ( showTimeState() ) );
471   connect( pb_colmap,    SIGNAL( clicked()        ),
472            this,         SLOT  ( selectColorMap() ) );
473   connect( ct_rinterv,   SIGNAL( valueChanged( double ) ),
474            this,         SLOT  ( changeInterval()       ) );
475   connect( pb_help,      SIGNAL( clicked()  ),
476            this,         SLOT  ( help()     ) );
477   connect( pb_close,     SIGNAL( clicked()  ),
478            this,         SLOT  ( close()    ) );
479
480   // Do the left-side layout
481   int row = 0;
482   settings->addWidget( lb_run,        row++, 0, 1, 8 );
483   settings->addWidget( lb_dir,        row++, 0, 1, 8 );
484   settings->addWidget( le_dir,        row++, 0, 1, 8 );
485   settings->addWidget( lb_dbhost,     row,   0, 1, 2 );
486   settings->addWidget( le_dbhost,     row++, 2, 1, 6 );
487   settings->addWidget( lb_runID,      row,   0, 1, 2 );
488   settings->addWidget( le_runID,      row++, 2, 1, 6 );
489   settings->addWidget( pb_loadXpn,    row,   0, 1, 4 );
490   settings->addWidget( pb_loadAUC,    row++, 4, 1, 4 );
491   settings->addWidget( pb_reset,      row,   0, 1, 4 );
492   settings->addWidget( pb_details,    row++, 4, 1, 4 );
493   settings->addWidget( pb_plot2d,     row,   0, 1, 4 );
494   settings->addWidget( pb_saveauc,    row++, 4, 1, 4 );
495   settings->addWidget( pb_reload,     row,   0, 1, 4 );
496   settings->addWidget( ck_autorld,    row++, 4, 1, 4 );
497   settings->addWidget( lb_rinterv,    row,   0, 1, 4 );
498   settings->addWidget( ct_rinterv,    row++, 4, 1, 4 );
499   settings->addWidget( lb_prcntls,    row++, 0, 1, 8 );
500   settings->addWidget( lb_rstart,     row,   0, 1, 2 );
501   settings->addWidget( cb_rstart,     row,   2, 1, 2 );
502   settings->addWidget( lb_rend,       row,   4, 1, 2 );
503   settings->addWidget( cb_rend,       row++, 6, 1, 2 );
504   settings->addWidget( lb_optsys,     row,   0, 1, 4 );
505   settings->addWidget( cb_optsys,     row++, 4, 1, 4 );
506   settings->addWidget( lb_cellchn,    row,   0, 1, 4 );
507   settings->addWidget( cb_cellchn,    row++, 4, 1, 4 );
508   settings->addWidget( lb_lrange,     row,   0, 1, 4 );
509   settings->addWidget( le_lrange,     row++, 4, 1, 4 );
510   settings->addWidget( lb_pltrec,     row,   0, 1, 2 );
511   settings->addWidget( cb_pltrec,     row,   2, 1, 2 );
512   settings->addWidget( pb_prev,       row,   4, 1, 2 );
513   settings->addWidget( pb_next,       row++, 6, 1, 2 );
514
515   settings->addWidget( lb_status,     row,   0, 1, 4 );
516   settings->addWidget( pb_stop,       row,   4, 1, 2 );
517   settings->addWidget( pb_help,       row++, 6, 1, 2 );
518   
519   settings->addWidget( ck_autoscy,    row,   0, 1, 4 );
520   settings->addWidget( pb_showtmst,   row++, 4, 1, 4 );
521   settings->addWidget( pb_colmap,     row,   0, 1, 2 );
522   settings->addWidget( le_colmap,     row++, 2, 1, 6 );
523   settings->addWidget( lb_scanctl,    row++, 0, 1, 8 );
524   settings->addWidget( lb_from,       row,   0, 1, 1 );
525   settings->addWidget( ct_from,       row,   1, 1, 3 );
526   settings->addWidget( lb_to,         row,   4, 1, 1 );
527   settings->addWidget( ct_to,         row++, 5, 1, 3 );
528   settings->addWidget( pb_exclude,    row,   0, 1, 4 );
529   settings->addWidget( pb_include,    row++, 4, 1, 4 );
530
531   //settings->addWidget( lb_status,     row++, 0, 1, 8 );
532
533   settings->addWidget( le_status,     row++, 0, 1, 8 );
534   //settings->addWidget( pb_help,       row,   0, 1, 8 );
535   //settings->addWidget( pb_close,      row++, 4, 1, 4 );
536
537   // Plot layout for the right side of window
538//   QBoxLayout* plot = new US_Plot( data_plot,
539   plot             = new US_Plot( data_plot,
540                                   tr( "Intensity Data" ),
541                                   tr( "Radius (in cm)" ), 
542                                   tr( "Intensity" ) );
543
544   data_plot->setMinimumSize( 400, 400 );
545
546   data_plot->enableAxis( QwtPlot::xBottom, true );
547   data_plot->enableAxis( QwtPlot::yLeft  , true );
548
549   data_plot->setAxisScale( QwtPlot::xBottom, 5.8,  7.2 );
550   data_plot->setAxisScale( QwtPlot::yLeft  , 0.0, 5e+4 );
551
552   picker = new US_PlotPicker( data_plot );
553   picker->setRubberBand     ( QwtPicker::VLineRubberBand );
554   picker->setMousePattern   ( QwtEventPattern::MouseSelect1,
555                               Qt::LeftButton, Qt::ControlModifier );
556
557   connect( plot, SIGNAL( zoomedCorners( QRectF ) ),
558            this, SLOT  ( currentRectf ( QRectF ) ) );
559
560   //Live params (rpm speed, temp.)
561   int row_params = 0;
562   rpm_box = new DialBox( this );
563   live_params->addWidget( rpm_box, row_params, 0, 1, 6 );
564
565   temperature_box = new WheelBox( Qt::Vertical  );  // Blue/Red box
566   live_params->addWidget( temperature_box, row_params++, 6, 1, 2 );
567
568   QLabel*      lb_elapsed     = us_label( tr( "Elapsed Time:" ), -1 );
569                le_elapsed     = us_lineedit( "00:00:00", -1, true );
570   QLabel*      lb_running     = us_label( tr( "Running Time:" ), -1 );
571                le_running     = us_lineedit( "00:00:00", -1, true );   
572   QLabel*      lb_remaining   = us_label( tr( "Remaining Time:" ), -1 );
573                le_remaining   = us_lineedit( "00:00:00", -1, true );
574
575   
576   time_params-> addWidget( lb_elapsed,   row_params,   0, 1, 2 );
577   time_params-> addWidget( le_elapsed,   row_params,   2, 1, 2 );
578   time_params-> addWidget( lb_running,   row_params,   4, 1, 2 );
579   time_params-> addWidget( le_running,   row_params,   6, 1, 2 );
580   time_params-> addWidget( lb_remaining, row_params,   8, 1, 2 );
581   time_params-> addWidget( le_remaining, row_params++, 10, 1, 2 );
582   
583   // Now let's assemble the page
584   
585   QVBoxLayout* left     = new QVBoxLayout;
586
587   left->addLayout( settings );
588   left->addLayout( live_params );
589   //left->addLayout( time_params );
590   
591   QVBoxLayout* right    = new QVBoxLayout;
592   
593   right->addLayout( plot );
594   right->addLayout( time_params );
595
596   QHBoxLayout* main = new QHBoxLayout;
597   // main->setSpacing         ( 2 );
598   // main->setContentsMargins ( 2, 2, 2, 2 );
599
600   main->addLayout( left );
601   main->addLayout( right );
602
603   main->setStretch( 0, 3 );
604   main->setStretch( 1, 7 );
605     
606   // //Plots for Temp.
607   // plot_temp             = new US_Plot( data_plot_temp, "", "", QString("Degrees, ")+QChar(0x2103));
608 
609   // //data_plot_temp->setMinimumSize( 50, 400 );
610
611   // data_plot_temp->enableAxis( QwtPlot::xBottom, false );
612   // data_plot_temp->enableAxis( QwtPlot::yLeft  , true );
613
614   // data_plot_temp->setAxisScale( QwtPlot::xBottom, 5.8,  7.2 );
615   // data_plot_temp->setAxisScale( QwtPlot::yLeft  , 0.0, 5e+4 );
616
617   // picker_temp = new US_PlotPicker( data_plot_temp );
618   // picker_temp->setRubberBand     ( QwtPicker::VLineRubberBand );
619   // picker_temp->setMousePattern   ( QwtEventPattern::MouseSelect1,
620   //             Qt::LeftButton, Qt::ControlModifier );
621
622   // connect( plot_temp, SIGNAL( zoomedCorners( QRectF ) ),
623   //          this, SLOT  ( currentRectf ( QRectF ) ) );
624
625   
626   //plot RPM
627   plot_rpm             = new US_Plot( data_plot_rpm, "", tr( "Elapsed Time (minutes)" ),
628                                                          tr( "RPM" ) );
629   QFont tfont( US_GuiSettings::fontFamily(),
630                US_GuiSettings::fontSize(),
631                QFont::Bold );
632
633   QwtText qwtTitleR( tr( "Temp." ) + DEGC );
634   qwtTitleR.setFont( tfont );
635   data_plot_rpm->setAxisTitle( QwtPlot::yRight , qwtTitleR );
636
637   QwtLegend *legend = new QwtLegend;
638   legend->setFrameStyle( QFrame::Box | QFrame::Sunken );
639   legend->setFont( QFont( US_GuiSettings::fontFamily(),
640                           US_GuiSettings::fontSize() - 1 ) );
641   data_plot_rpm->insertLegend( legend, QwtPlot::BottomLegend  );
642
643 
644   //data_plot_rpm->setMinimumSize( 50, 400 );
645
646   data_plot_rpm->enableAxis( QwtPlot::xBottom, true );
647   data_plot_rpm->enableAxis( QwtPlot::yLeft  , true );
648   data_plot_rpm->enableAxis( QwtPlot::yRight , true );
649
650   data_plot_rpm->setAxisScale( QwtPlot::xBottom, 1.0, 14400.0 );
651   data_plot_rpm->setAxisScale( QwtPlot::yLeft  , 0.0, 6e+4 );
652   data_plot_rpm->setAxisScale( QwtPlot::yRight , 0.0, 40 );
653
654   picker_rpm = new US_PlotPicker( data_plot_rpm );
655   picker_rpm->setRubberBand     ( QwtPicker::VLineRubberBand );
656   picker_rpm->setMousePattern   ( QwtEventPattern::MouseSelect1,
657           Qt::LeftButton, Qt::ControlModifier );
658
659   grid_rpm          = us_grid( data_plot_rpm );
660
661   //ALEXEY: curves for sysdata must be re-defined in the reset_auto() !!!
662   curv_rpm  = us_curve( data_plot_rpm, "RPM" );
663   curv_temp = us_curve( data_plot_rpm, "Temperature" );
664   curv_temp->setYAxis     ( QwtPlot::yRight );
665
666   QPen    pen_red ( Qt::red );
667   QPen    pen_green ( Qt::green );
668
669   curv_temp->setPen( pen_red);
670   curv_rpm ->setPen( pen_green);
671   /*************************************************************************/
672
673   
674   connect( plot_rpm, SIGNAL( zoomedCorners( QRectF ) ),
675            this, SLOT  ( currentRectf ( QRectF ) ) );
676
677   
678
679   // QHBoxLayout* running_temp  = new QHBoxLayout;
680   // running_temp->addLayout( plot_temp );
681   QHBoxLayout* running_rpm  = new QHBoxLayout;
682   running_rpm->addLayout( plot_rpm );
683
684   // MAIN panel
685   QVBoxLayout* supermain = new QVBoxLayout( this );
686   supermain->setSpacing         ( 2 );
687   supermain->setContentsMargins ( 2, 2, 2, 2 );     
688   supermain->addLayout( main );
689   //supermain->addLayout( running_temp );
690   supermain->addLayout( running_rpm );
691
692   // supermain->setStretch( 0, 7 );
693   // supermain->setStretch( 1, 3 );
694
695   reset();
696   setMinimumSize( 950, 450 );
697   adjustSize();
698
699   
700   // //1. Temporary test - C. Horne's experiment: ExpID = 408 (ExperimentDefinition, Postgres, Optima 1); ProtocolID = 43 (Us-lims, Mysql);
701   // // description = CHorne-NanR_Trunc_2r-DNA-MWL_60K_111918;
702   // // 2 cells; 41 wvls; 82 triples;
703   // QMap < QString, QString > protocol_details;
704   // protocol_details["experimentId"] = QString("408");   
705   // protocol_details["protocolName"] = QString("some_prot");
706   // protocol_details[ "experimentName" ] = QString("some_name");
707   // protocol_details[ "CellChNumber" ] = QString("2");
708   // protocol_details[ "TripleNumber" ] = QString("82");
709   // protocol_details[ "OptimaName" ] = QString("Optima 1");
710   // protocol_details[ "duration" ]   = QString("32400");
711
712   //2. Temporary test - S. Ling's experiment: ExpID = 465 (ExperimentDefinition, Postgres, Optima 1); ProtocolID = 150 (Us-lims, Mysql);
713   // description = CCLing-PZ5077-27k-021519;
714   // 2 cells; 1 wvls; 2 triples - for absorbance ONLY!!
715   // QMap < QString, QString > protocol_details;
716   // protocol_details["experimentId"] = QString("465");   
717   // protocol_details["protocolName"] = QString("some_prot");
718   // protocol_details[ "experimentName" ] = QString("some_name");
719   // protocol_details[ "CellChNumber" ] = QString("2");
720   // protocol_details[ "TripleNumber" ] = QString("2");
721   // protocol_details[ "OptimaName" ] = QString("Optima 1");
722   // protocol_details[ "duration" ]   = QString("27000");
723   
724   //3. Temporary test - Harmen's experiment:  ExpID = 286 (ExperimentDefinition, Postgres, Optima 2); ProtocolID = 286 (Us-lims, Mysql);
725   // description = HarmenS_20180417_Purity_Run_6;
726   // 8 cells (16 channels); 29 wvls; 29 triples - for absorbance ONLY!!
727   // QMap < QString, QString > protocol_details;
728   // protocol_details["experimentId"] = QString("286");   
729   // protocol_details["protocolName"] = QString("HarmenS_20180417_Purity_Run_6");
730   // protocol_details[ "experimentName" ] = QString("some_name");
731   // protocol_details[ "CellChNumber" ] = QString("16");
732   // protocol_details[ "TripleNumber" ] = QString("29");
733   // protocol_details[ "OptimaName" ] = QString("Optima 2");
734   // protocol_details[ "duration" ]   = QString("43200");
735     
736
737   // check_for_data( protocol_details );
738   // End of test
739   
740}
741
742
743// Regular constructor
744US_XpnDataViewer::US_XpnDataViewer() : US_Widgets()
745{
746   const QChar chlamb( 955 );
747
748   setWindowTitle( tr( "Beckman Optima Data Viewer" ) );
749   setPalette( US_GuiSettings::frameColor() );
750
751   QGridLayout* settings = new QGridLayout;
752   
753   auto_mode_bool = false;
754   experimentAborted  = false;
755   
756   navgrec      = 10;
757   dbg_level    = US_Settings::us_debug();
758   QFont sfont( US_GuiSettings::fontFamily(), US_GuiSettings::fontSize() - 1 );
759   QFontMetrics fmet( sfont );
760   int fwid     = fmet.maxWidth();
761   int lwid     = fwid * 4;
762   int swid     = lwid + fwid;
763   isMWL        = false;
764   isRaw        = true;
765   haveData     = false;
766   haveTmst     = false;
767   xpn_data     = NULL;
768   runID        = "";
769   runType      = "RI";
770   rlt_id       = 0;
771   currentDir   = "";
772   in_reload    = false;
773
774   //ALEXEY: old way, from .conf file
775   // QStringList xpnentr = US_Settings::defaultXpnHost();
776   // DbgLv(1) << "xpnentr count" << xpnentr.count();
777   
778   // if ( xpnentr.count() == 0 )
779   //   {
780   //     xpnentr << "test-host" << "bcf.uthscsa.edu" << "5432";
781   
782   //     QMessageBox::warning( this,
783   //            tr( "No Optima Host Entry" ),
784   //            tr( "A default Optima Host entry is being used.\n"
785   //          "You should add entries via Preferences:Optima Host Preferences\n"
786   //          "as soon as possible" ) );
787   //   }
788   // else
789   //   DbgLv(1) << "xpnentr ..." << xpnentr;
790   // QString encpw;
791   // QString decpw;
792   // QString encpw0;
793   // QString encpw1;
794   // QString masterpw;
795   // US_Passwd pw;
796   // xpndesc      = xpnentr.at( 0 );
797   // xpnhost      = xpnentr.at( 1 );
798   // xpnport      = xpnentr.at( 2 );
799   // xpnname      = xpnentr.at( 3 );
800   // xpnuser      = xpnentr.at( 4 );
801   // encpw        = xpnentr.at( 5 );
802   // encpw0       = encpw.section( "^", 0, 0 );
803   // encpw1       = encpw.section( "^", 1, 1 );
804   // masterpw     = pw.getPasswd();
805   // xpnpasw      = US_Crypto::decrypt( encpw0, masterpw, encpw1 );
806
807
808   // Load controls     
809   QLabel*      lb_run      = us_banner( tr( "Load the Run" ) );
810
811                pb_loadXpn  = us_pushbutton( tr( "Load Raw Optima Data" ) );
812                pb_loadAUC  = us_pushbutton( tr( "Load US3 AUC Data" ) );
813                pb_reset    = us_pushbutton( tr( "Reset Data" ) );
814                pb_details  = us_pushbutton( tr( "Data Details" ), true  );
815                pb_plot2d   = us_pushbutton( tr( "Refresh Plot" ) );
816                pb_saveauc  = us_pushbutton( tr( "Export openAUC" )  );
817                pb_showtmst = us_pushbutton( tr( "Show Time State" )  );
818                pb_reload   = us_pushbutton( tr( "Update Data" )      );
819                pb_colmap   = us_pushbutton( tr( "Color Map" )        );
820
821   QLabel*      lb_dir      = us_label( tr( "Directory" ), -1 );
822                le_dir      = us_lineedit( "", -1, true );
823
824   QLabel*      lb_dbhost   = us_label( tr( "DB Host" ), -1 );
825                //le_dbhost   = us_lineedit( "", -1, true );
826   cb_optima           = new QComboBox( this );                                // New
827   QLabel*      lb_optima_connected = us_label( tr( "Connection Status: " ) ); //New
828   le_optima_connected = us_lineedit( "", 0, true );                           //New
829   
830   //ALEXEY: new way <--------------------------------------------- //New
831   US_Passwd pw;
832   US_DB2*   dbP = new US_DB2( pw.getPasswd() );
833   if ( dbP != NULL )
834     read_optima_machines( dbP );
835
836   for ( int ii = 0; ii < instruments.count(); ii++ )
837     sl_optimas << instruments[ ii ][ "ID" ] 
838       + ": " + instruments[ ii ][ "name" ];
839   
840   cb_optima->clear();
841   cb_optima->addItems( sl_optimas );
842   
843   connect( cb_optima,    SIGNAL( activated      ( int ) ),
844            this,         SLOT  ( changeOptima   ( int ) ) );
845   
846   changeOptima(0); 
847   /* End of Optima machines read                                      //New    */ 
848
849   
850   QLabel*      lb_runID    = us_label( tr( "Run ID:" ), -1 );
851                le_runID    = us_lineedit( "", -1, false );
852
853   QLabel*      lb_cellchn  = us_label( tr( "Cell/Channel:" ), -1 );
854                cb_cellchn  = us_comboBox();
855
856                le_colmap   = us_lineedit( "cm-rainbow", -1, true );
857
858   int rhgt     = le_runID->height();
859   ptype_mw     = tr( "Plot %1:"    ).arg( chlamb );
860   ptype_tr     = tr( "Plot Triple:" );
861   prectype     = ptype_tr;
862
863   // Plot controls     
864   QLabel*      lb_prcntls  = us_banner( tr( "Plot Controls" ) );
865   QLabel*      lb_rstart   = us_label( tr( "Radius Start:"   ), -1 );
866                cb_rstart   = us_comboBox();
867   QLabel*      lb_rend     = us_label( tr( "Radius End:"     ), -1 );
868                cb_rend     = us_comboBox();
869   QLabel*      lb_lrange   = us_label( tr( "%1 Range:"   ).arg( chlamb ), -1 );
870                le_lrange   = us_lineedit( "280 only", -1, true );
871                lb_pltrec   = us_label( prectype, -1 );
872                cb_pltrec   = us_comboBox();
873   QLabel*      lb_optsys   = us_label( tr( "Optical System:" ), -1 );
874                cb_optsys   = us_comboBox();
875
876                pb_prev     = us_pushbutton( tr( "Previous" ) );
877                pb_next     = us_pushbutton( tr( "Next" ) );
878   us_checkbox( tr( "Always Auto-scale Y Axis" ), ck_autoscy, true );
879   us_checkbox( tr( "Auto Update" ),              ck_autorld, false );
880   pb_prev->setIcon( US_Images::getIcon( US_Images::ARROW_LEFT  ) );
881   pb_next->setIcon( US_Images::getIcon( US_Images::ARROW_RIGHT ) );
882   QLabel*      lb_rinterv  = us_label( tr( "Update Interval Seconds:" ), -1 );
883                ct_rinterv  = us_counter( 2, 10, 3600, 1 );
884   ct_rinterv->setFont( sfont );
885   ct_rinterv->setMinimumWidth( lwid );
886   ct_rinterv->resize( rhgt, swid );
887   ct_rinterv->setMinimum   (   10 );
888   ct_rinterv->setMaximum   ( 3600 );
889   ct_rinterv->setValue     (   60 );
890   ct_rinterv->setSingleStep(    1 );
891
892   // Scan controls     
893   QLabel*      lb_scanctl  = us_banner( tr( "Scan Control" ) );
894   QLabel*      lb_from     = us_label( tr( "From:" ) );
895   QLabel*      lb_to       = us_label( tr( "To:" ) );
896                ct_from     = us_counter( 3, 0, 500, 1 );
897                ct_to       = us_counter( 3, 0, 500, 1 );
898                pb_exclude  = us_pushbutton( tr( "Exclude Scan Range" ) );
899                pb_include  = us_pushbutton( tr( "Include All Scans"  ) );
900   ct_from  ->setFont( sfont );
901   ct_from  ->setMinimumWidth( lwid );
902   ct_from  ->resize( rhgt, swid );
903   ct_to    ->setFont( sfont );
904   ct_to    ->setMinimumWidth( lwid );
905   ct_to    ->resize( rhgt, swid );
906   ct_from  ->setValue( 0 );
907   ct_to    ->setValue( 0 );
908   ct_from  ->setSingleStep( 1 );
909   ct_to    ->setSingleStep( 1 );
910
911   // Status and standard pushbuttons
912   QLabel*      lb_status   = us_banner( tr( "Status" ) );
913                le_status   = us_lineedit( tr( "(no data loaded)" ), -1, true );
914   QPalette stpal;
915   stpal.setColor( QPalette::Text, Qt::white );
916   stpal.setColor( QPalette::Base, Qt::blue  );
917   le_status->setPalette( stpal );
918
919   QPushButton* pb_help     = us_pushbutton( tr( "Help" ) );
920   QPushButton* pb_close    = us_pushbutton( tr( "Close" ) );
921
922   // Default scan curve color list and count
923   QString cmfpath          = US_Settings::etcDir() + "/cm-rainbow.xml";
924 DbgLv(1) << "cmfpath" << cmfpath;
925   US_ColorGradIO::read_color_gradient( cmfpath, mcolors );
926   mcknt                    = mcolors.count();
927DbgLv(1) << "mcolors count" << mcknt;
928if(mcknt>0)
929 DbgLv(1) << "mcolors c0,cn" << mcolors[0] << mcolors[mcknt-1];
930
931   // Signals and Slots
932   connect( pb_loadXpn,   SIGNAL( clicked()      ),
933            this,         SLOT  ( load_xpn_raw() ) );
934   connect( pb_loadAUC,   SIGNAL( clicked()      ),
935            this,         SLOT  ( load_auc_xpn() ) );
936   connect( pb_reset,     SIGNAL( clicked()      ),
937            this,         SLOT  ( resetAll()     ) );
938   connect( pb_details,   SIGNAL( clicked()      ),
939            this,         SLOT  ( runDetails()   ) );
940   connect( pb_saveauc,   SIGNAL( clicked()      ),
941            this,         SLOT  ( export_auc()   ) );
942   connect( pb_reload,    SIGNAL( clicked()      ),
943            this,         SLOT  ( reloadData()   ) );
944   connect( ck_autorld,   SIGNAL( clicked()      ),
945            this,         SLOT  ( changeReload()             ) );
946   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
947            this,         SLOT  ( changeCellCh( )            ) );
948   connect( cb_rstart,    SIGNAL( currentIndexChanged( int ) ),
949            this,         SLOT  ( changeRadius( )            ) );
950   connect( cb_rend,      SIGNAL( currentIndexChanged( int ) ),
951            this,         SLOT  ( changeRadius( )            ) );
952   connect( cb_pltrec,    SIGNAL( currentIndexChanged( int ) ),
953            this,         SLOT  ( changeRecord( )            ) );
954   connect( pb_prev,      SIGNAL( clicked()  ),
955            this,         SLOT  ( prevPlot() ) );
956   connect( pb_next,      SIGNAL( clicked()  ),
957            this,         SLOT  ( nextPlot() ) );
958   connect( ct_from,      SIGNAL( valueChanged( double ) ),
959            this,         SLOT  ( exclude_from( double ) ) );
960   connect( ct_to,        SIGNAL( valueChanged( double ) ),
961            this,         SLOT  ( exclude_to  ( double ) ) );
962   connect( pb_exclude,   SIGNAL( clicked()       ),
963            this,         SLOT  ( exclude_scans() ) );
964   connect( pb_include,   SIGNAL( clicked()       ),
965            this,         SLOT  ( include_scans() ) );
966   connect( pb_plot2d,    SIGNAL( clicked()       ),
967            this,         SLOT  ( changeCellCh()  ) );
968   connect( pb_showtmst,  SIGNAL( clicked()       ),
969            this,         SLOT  ( showTimeState() ) );
970   connect( pb_colmap,    SIGNAL( clicked()        ),
971            this,         SLOT  ( selectColorMap() ) );
972   connect( ct_rinterv,   SIGNAL( valueChanged( double ) ),
973            this,         SLOT  ( changeInterval()       ) );
974   connect( pb_help,      SIGNAL( clicked()  ),
975            this,         SLOT  ( help()     ) );
976   connect( pb_close,     SIGNAL( clicked()  ),
977            this,         SLOT  ( close()    ) );
978
979   // Do the left-side layout
980   int row = 0;
981   settings->addWidget( lb_run,        row++, 0, 1, 8 );
982   settings->addWidget( lb_dir,        row++, 0, 1, 8 );
983   settings->addWidget( le_dir,        row++, 0, 1, 8 );
984
985   settings->addWidget( lb_dbhost,     row,   0, 1, 2 );
986   //settings->addWidget( le_dbhost,     row++, 2, 1, 6 );
987   settings->addWidget( cb_optima,     row++, 2, 1, 6 );      //New
988
989   settings->addWidget( lb_optima_connected,     row,   0, 1, 2 );      //New
990   settings->addWidget( le_optima_connected,     row++, 2, 1, 6 );      //New
991   
992   settings->addWidget( lb_runID,      row,   0, 1, 2 );
993   settings->addWidget( le_runID,      row++, 2, 1, 6 );
994   settings->addWidget( pb_loadXpn,    row,   0, 1, 4 );
995   settings->addWidget( pb_loadAUC,    row++, 4, 1, 4 );
996   settings->addWidget( pb_reset,      row,   0, 1, 4 );
997   settings->addWidget( pb_details,    row++, 4, 1, 4 );
998   settings->addWidget( pb_plot2d,     row,   0, 1, 4 );
999   settings->addWidget( pb_saveauc,    row++, 4, 1, 4 );
1000   settings->addWidget( pb_reload,     row,   0, 1, 4 );
1001   settings->addWidget( ck_autorld,    row++, 4, 1, 4 );
1002   settings->addWidget( lb_rinterv,    row,   0, 1, 4 );
1003   settings->addWidget( ct_rinterv,    row++, 4, 1, 4 );
1004   settings->addWidget( lb_prcntls,    row++, 0, 1, 8 );
1005   settings->addWidget( lb_rstart,     row,   0, 1, 2 );
1006   settings->addWidget( cb_rstart,     row,   2, 1, 2 );
1007   settings->addWidget( lb_rend,       row,   4, 1, 2 );
1008   settings->addWidget( cb_rend,       row++, 6, 1, 2 );
1009   settings->addWidget( lb_optsys,     row,   0, 1, 4 );
1010   settings->addWidget( cb_optsys,     row++, 4, 1, 4 );
1011   settings->addWidget( lb_cellchn,    row,   0, 1, 2 );
1012   settings->addWidget( cb_cellchn,    row,   2, 1, 2 );
1013   settings->addWidget( lb_lrange,     row,   4, 1, 2 );
1014   settings->addWidget( le_lrange,     row++, 6, 1, 2 );
1015   settings->addWidget( lb_pltrec,     row,   0, 1, 2 );
1016   settings->addWidget( cb_pltrec,     row,   2, 1, 2 );
1017   settings->addWidget( pb_prev,       row,   4, 1, 2 );
1018   settings->addWidget( pb_next,       row++, 6, 1, 2 );
1019   settings->addWidget( ck_autoscy,    row,   0, 1, 4 );
1020   settings->addWidget( pb_showtmst,   row++, 4, 1, 4 );
1021   settings->addWidget( pb_colmap,     row,   0, 1, 2 );
1022   settings->addWidget( le_colmap,     row++, 2, 1, 6 );
1023   settings->addWidget( lb_scanctl,    row++, 0, 1, 8 );
1024   settings->addWidget( lb_from,       row,   0, 1, 1 );
1025   settings->addWidget( ct_from,       row,   1, 1, 3 );
1026   settings->addWidget( lb_to,         row,   4, 1, 1 );
1027   settings->addWidget( ct_to,         row++, 5, 1, 3 );
1028   settings->addWidget( pb_exclude,    row,   0, 1, 4 );
1029   settings->addWidget( pb_include,    row++, 4, 1, 4 );
1030   settings->addWidget( lb_status,     row++, 0, 1, 8 );
1031   settings->addWidget( le_status,     row++, 0, 1, 8 );
1032   settings->addWidget( pb_help,       row,   0, 1, 4 );
1033   settings->addWidget( pb_close,      row++, 4, 1, 4 );
1034
1035   // Plot layout for the right side of window
1036//   QBoxLayout* plot = new US_Plot( data_plot,
1037   plot             = new US_Plot( data_plot,
1038                                   tr( "Intensity Data" ),
1039                                   tr( "Radius (in cm)" ), 
1040                                   tr( "Intensity" ) );
1041
1042   data_plot->setMinimumSize( 600, 400 );
1043
1044   data_plot->enableAxis( QwtPlot::xBottom, true );
1045   data_plot->enableAxis( QwtPlot::yLeft  , true );
1046
1047   data_plot->setAxisScale( QwtPlot::xBottom, 5.8,  7.2 );
1048   data_plot->setAxisScale( QwtPlot::yLeft  , 0.0, 5e+4 );
1049
1050   picker = new US_PlotPicker( data_plot );
1051   picker->setRubberBand     ( QwtPicker::VLineRubberBand );
1052   picker->setMousePattern   ( QwtEventPattern::MouseSelect1,
1053                               Qt::LeftButton, Qt::ControlModifier );
1054
1055   connect( plot, SIGNAL( zoomedCorners( QRectF ) ),
1056            this, SLOT  ( currentRectf ( QRectF ) ) );
1057
1058   // Now let's assemble the page
1059   
1060   QVBoxLayout* left     = new QVBoxLayout;
1061
1062   left->addLayout( settings );
1063   
1064   QVBoxLayout* right    = new QVBoxLayout;
1065   
1066   right->addLayout( plot );
1067
1068   QHBoxLayout* main = new QHBoxLayout( this );
1069   main->setSpacing         ( 2 );
1070   main->setContentsMargins ( 2, 2, 2, 2 );
1071
1072   main->addLayout( left );
1073   main->addLayout( right );
1074
1075   main->setStretch( 0, 2 );
1076   main->setStretch( 1, 4 );
1077
1078   reset();
1079   adjustSize();
1080
1081}
1082
1083
1084
1085void US_XpnDataViewer::reset( void )
1086{
1087   runID         = "";
1088   currentDir    = US_Settings::importDir() + "/" + runID;
1089   cb_cellchn ->disconnect();
1090   cb_cellchn ->clear();
1091   le_dir     ->setText( currentDir );
1092   le_runID   ->setText( runID );
1093   //le_dbhost  ->setText( xpnhost + ":" + xpnport + "   (" + xpndesc + ")" );       //New
1094
1095   pb_loadXpn ->setEnabled( true );
1096   pb_loadAUC ->setEnabled( true );
1097   pb_details ->setEnabled( false );
1098   pb_reload  ->setEnabled( false );
1099   ck_autorld ->setEnabled( true  );
1100   cb_cellchn ->setEnabled( false );
1101   cb_rstart  ->setEnabled( false );
1102   cb_rend    ->setEnabled( false );
1103   cb_pltrec  ->setEnabled( false );
1104   pb_prev    ->setEnabled( false );
1105   pb_next    ->setEnabled( false );
1106   ct_from    ->setEnabled( false );
1107   ct_to      ->setEnabled( false );
1108   pb_exclude ->setEnabled( false );
1109   pb_include ->setEnabled( false );
1110   pb_reset   ->setEnabled( false );
1111   ct_from    ->setEnabled( false );
1112   ct_to      ->setEnabled( false );
1113   pb_exclude ->setEnabled( false );
1114   pb_include ->setEnabled( false );
1115   pb_plot2d  ->setEnabled( false );
1116   pb_saveauc ->setEnabled( false );
1117   pb_showtmst->setEnabled( false );
1118//   pb_movie2d->setEnabled( false );
1119
1120   // Clear any data structures
1121   allData   .clear();
1122   lambdas   .clear();
1123   r_radii   .clear();
1124   excludes  .clear();
1125   runInfo   .clear();
1126   cellchans .clear();
1127   triples   .clear();
1128   haveData      = false;
1129
1130   dPlotClearAll( data_plot );
1131   picker   ->disconnect();
1132   data_plot->setAxisScale( QwtPlot::xBottom, 5.8,  7.2 );
1133   data_plot->setAxisScale( QwtPlot::yLeft  , 0.0, 5e+4 );
1134   grid          = us_grid( data_plot );
1135   data_plot->replot();
1136
1137 
1138   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
1139            this,         SLOT  ( changeCellCh(            ) ) );
1140//   connect( plot, SIGNAL( zoomedCorners( QRectF ) ),
1141//            this, SLOT  ( currentRectf ( QRectF ) ) );
1142
1143   last_xmin     = -1.0;
1144   last_xmax     = -1.0;
1145   last_ymin     = -1.0;
1146   last_ymax     = -1.0;
1147   xpn_data      = ( xpn_data == NULL ) ? new US_XpnData() : xpn_data;
1148
1149   connect( xpn_data, SIGNAL( status_text  ( QString ) ),
1150            this,     SLOT  ( status_report( QString ) ) );
1151
1152   xpn_data->clear();
1153   le_status->setText( tr( "(no data loaded)" ) );
1154
1155}
1156
1157void US_XpnDataViewer::reset_auto( void )
1158{
1159   runID         = "";
1160   currentDir    = US_Settings::importDir() + "/" + runID;
1161   cb_cellchn ->disconnect();
1162   cb_cellchn ->clear();
1163   le_dir     ->setText( currentDir );
1164   le_runID   ->setText( runID );
1165   //le_dbhost  ->setText( xpnhost + ":" + xpnport + "   (" + xpndesc + ")" );       //New
1166
1167   //Also clear Wavelengths && Lambda ranges:
1168   cb_pltrec ->disconnect();
1169   cb_pltrec ->clear();
1170   le_lrange ->setText("");
1171   
1172   
1173   pb_loadXpn ->setEnabled( true );
1174   pb_loadAUC ->setEnabled( true );
1175   pb_details ->setEnabled( false );
1176   pb_reload  ->setEnabled( false );
1177   ck_autorld ->setEnabled( true  );
1178   cb_cellchn ->setEnabled( false );
1179   cb_rstart  ->setEnabled( false );
1180   cb_rend    ->setEnabled( false );
1181   cb_pltrec  ->setEnabled( false );
1182   pb_prev    ->setEnabled( false );
1183   pb_next    ->setEnabled( false );
1184   ct_from    ->setEnabled( false );
1185   ct_to      ->setEnabled( false );
1186   pb_exclude ->setEnabled( false );
1187   pb_include ->setEnabled( false );
1188   pb_reset   ->setEnabled( false );
1189   ct_from    ->setEnabled( false );
1190   ct_to      ->setEnabled( false );
1191   pb_exclude ->setEnabled( false );
1192   pb_include ->setEnabled( false );
1193   pb_plot2d  ->setEnabled( false );
1194   pb_saveauc ->setEnabled( false );
1195   pb_showtmst->setEnabled( false );
1196//   pb_movie2d->setEnabled( false );
1197
1198   // Clear any data structures
1199   allData   .clear();
1200   lambdas   .clear();
1201   r_radii   .clear();
1202   excludes  .clear();
1203   runInfo   .clear();
1204   cellchans .clear();
1205   triples   .clear();
1206   haveData      = false;
1207
1208   dPlotClearAll( data_plot );
1209   picker   ->disconnect();
1210   data_plot->setAxisScale( QwtPlot::xBottom, 5.8,  7.2 );
1211   data_plot->setAxisScale( QwtPlot::yLeft  , 0.0, 5e+4 );
1212   grid          = us_grid( data_plot );
1213   data_plot->replot();
1214
1215   //ALEXEY: also reset sys data plot/temperature bar/RPM speedometer
1216   dPlotClearAll( data_plot_rpm );
1217   picker_rpm   ->disconnect();
1218   data_plot_rpm->setAxisScale( QwtPlot::xBottom, 1.0, 14400.0 );
1219   data_plot_rpm->setAxisScale( QwtPlot::yLeft  , 0.0, 6e+4 );
1220   data_plot_rpm->setAxisScale( QwtPlot::yRight , 0.0, 40 );
1221   grid_rpm      = us_grid( data_plot_rpm );
1222   data_plot_rpm->replot();
1223   //Curves for RPM/Temp.
1224   curv_rpm  = us_curve( data_plot_rpm, "RPM" );
1225   curv_temp = us_curve( data_plot_rpm, "Temperature" );
1226   curv_temp->setYAxis     ( QwtPlot::yRight );
1227   QPen    pen_red ( Qt::red );
1228   QPen    pen_green ( Qt::green );
1229   curv_temp->setPen( pen_red);
1230   curv_rpm ->setPen( pen_green);
1231   
1232   //RPM/Temp.
1233   rpm_box->setSpeed(0);
1234   temperature_box->setTemp(0);
1235   //times
1236   le_elapsed  ->setText("00:00:00");
1237   le_remaining->setText("00:00:00");
1238   le_running  ->setText("00:00:00");
1239
1240   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
1241          this,         SLOT  ( changeCellCh(            ) ) );
1242
1243   connect( cb_pltrec,    SIGNAL( currentIndexChanged( int ) ),
1244            this,         SLOT  ( changeRecord( )            ) );
1245
1246
1247//   connect( plot, SIGNAL( zoomedCorners( QRectF ) ),
1248//            this, SLOT  ( currentRectf ( QRectF ) ) );
1249
1250   last_xmin     = -1.0;
1251   last_xmax     = -1.0;
1252   last_ymin     = -1.0;
1253   last_ymax     = -1.0;
1254   xpn_data      = ( xpn_data == NULL ) ? new US_XpnData() : xpn_data;
1255
1256   connect( xpn_data, SIGNAL( status_text  ( QString ) ),
1257            this,     SLOT  ( status_report( QString ) ) );
1258
1259   xpn_data->clear();
1260   le_status->setText( tr( "(no data loaded)" ) );
1261
1262   runID           = "";
1263   data_plot->setTitle( tr( "Intensity Data" ) );
1264}
1265
1266// Slot to read all Optima machines <------------------------------- // New
1267void US_XpnDataViewer::read_optima_machines( US_DB2* db )
1268{
1269  QStringList q( "" );
1270  q.clear();
1271  q  << QString( "get_instrument_names" )
1272     << QString::number( 1 );
1273  db->query( q );
1274 
1275  if ( db->lastErrno() == US_DB2::OK )      // If not, no instruments defined
1276    {
1277      QList< int > instrumentIDs;
1278     
1279      // Grab all the IDs so we can reuse the db connection
1280      while ( db->next() )
1281  {
1282    int ID = db->value( 0 ).toString().toInt();
1283    instrumentIDs << ID;
1284   
1285    qDebug() << "InstID: " << ID;
1286  }
1287     
1288      // Instrument information
1289      foreach ( int ID, instrumentIDs )
1290  {
1291    QMap<QString,QString> instrument;
1292   
1293    q.clear();
1294    q  << QString( "get_instrument_info_new" )
1295       << QString::number( ID );
1296    db->query( q );
1297    db->next();
1298
1299    instrument[ "ID" ]              =   QString::number( ID );
1300    instrument[ "name" ]            =   db->value( 0 ).toString();
1301    instrument[ "serial" ]          =   db->value( 1 ).toString();
1302    instrument[ "optimaHost" ]      =   db->value( 5 ).toString();     
1303    instrument[ "optimaPort" ]      =   db->value( 6 ).toString(); 
1304    instrument[ "optimaDBname" ]    =   db->value( 7 ).toString();     
1305    instrument[ "optimaDBusername" ] =  db->value( 8 ).toString();     
1306    instrument[ "optimaDBpassw" ]    =  db->value( 9 ).toString();     
1307    instrument[ "selected" ]        =   db->value( 10 ).toString();
1308     
1309    instrument[ "opsys1" ]  = db->value( 11 ).toString();
1310    instrument[ "opsys2" ]  = db->value( 12 ).toString();
1311    instrument[ "opsys3" ]  = db->value( 13 ).toString();
1312
1313    instrument[ "radcalwvl" ]  =  db->value( 14 ).toString();
1314    instrument[ "chromoab" ]   =  db->value( 15 ).toString();
1315
1316   
1317    if ( instrument[ "name" ].contains("Optima") || instrument[ "optimaHost" ].contains("AUC_DATA_DB") )
1318      this->instruments << instrument;
1319  }
1320    }
1321  qDebug() << "Reading Instrument: FINISH";
1322}
1323
1324// Slot to select in Optima in use        <----------------------- // New   
1325void US_XpnDataViewer::changeOptima( int ndx )
1326{
1327   cb_optima->setCurrentIndex( ndx );
1328   QString coptima     = cb_optima->currentText();
1329   QString descr       = coptima.section( ":", 1, 1 ).simplified();
1330
1331   for ( int ii = 0; ii < instruments.size(); ii++ )
1332     {
1333       QString name = instruments[ii][ "name" ].trimmed();
1334       if ( name == descr )
1335   currentInstrument = instruments[ii];
1336     }
1337
1338   xpndesc     = currentInstrument[ "name" ];
1339   xpnhost     = currentInstrument[ "optimaHost" ];
1340   xpnport     = currentInstrument[ "optimaPort" ];
1341   xpnname     = currentInstrument[ "optimaDBname" ];
1342   xpnuser     = currentInstrument[ "optimaDBusername" ];
1343   xpnpasw     = currentInstrument[ "optimaDBpassw" ];
1344
1345   test_optima_connection();
1346}
1347
1348//Slot to test Optima connection when Optima selection changed <------------- //New
1349void US_XpnDataViewer::test_optima_connection()
1350{
1351
1352   qDebug() << "Optima in use: name, host, port, dbname, dbuser, dbpasw: " << xpndesc << " " << xpnhost << " "
1353        << xpnport << " "  << xpnname << " " << xpnuser << " " << xpnpasw ;
1354
1355
1356   QPalette orig_pal = le_optima_connected->palette();
1357   
1358   if ( xpnhost.isEmpty() || xpnport.isEmpty()
1359  || xpnname.isEmpty() || xpnuser.isEmpty() || xpnpasw.isEmpty()  )
1360     {
1361       le_optima_connected->setText( "disconnected" );
1362       QPalette *new_palette = new QPalette();
1363       new_palette->setColor(QPalette::Text,Qt::red);
1364       new_palette->setColor(QPalette::Base, orig_pal.color(QPalette::Base));
1365       le_optima_connected->setPalette(*new_palette);
1366
1367       return;
1368     }
1369   
1370   US_XpnData* xpn_data1 = new US_XpnData();
1371   bool o_connected           = xpn_data1->connect_data( xpnhost, xpnport.toInt(), xpnname, xpnuser,  xpnpasw );
1372   xpn_data1->close();
1373   delete xpn_data1;
1374     
1375   if ( o_connected )
1376     {
1377       le_optima_connected->setText( "connected" );
1378       QPalette *new_palette = new QPalette();
1379       new_palette->setColor(QPalette::Text, Qt::darkGreen);
1380       new_palette->setColor(QPalette::Base, orig_pal.color(QPalette::Base));
1381       le_optima_connected->setPalette(*new_palette);
1382     }
1383   else
1384     {
1385       le_optima_connected->setText( "disconnected" );
1386       QPalette *new_palette = new QPalette();
1387       new_palette->setColor(QPalette::Text,Qt::red);
1388       new_palette->setColor(QPalette::Base, orig_pal.color(QPalette::Base));
1389       le_optima_connected->setPalette(*new_palette);
1390     }
1391}
1392
1393
1394// Slot to select Optima in use by name for autoflow    <----------------------- // New   
1395void US_XpnDataViewer::selectOptimaByName_auto( QString OptimaName )
1396{
1397  for ( int ii = 0; ii < instruments.size(); ii++ )
1398    {
1399      QString name = instruments[ii][ "name" ].trimmed();
1400      if ( name == OptimaName )
1401  currentInstrument = instruments[ii];
1402    }
1403 
1404  xpndesc     = currentInstrument[ "name" ];
1405  xpnhost     = currentInstrument[ "optimaHost" ];
1406  xpnport     = currentInstrument[ "optimaPort" ];
1407  xpnname     = currentInstrument[ "optimaDBname" ];
1408  xpnuser     = currentInstrument[ "optimaDBusername" ];
1409  xpnpasw     = currentInstrument[ "optimaDBpassw" ];
1410}
1411
1412
1413void US_XpnDataViewer::resetAll( void )
1414{
1415   if ( allData.size() > 0 )
1416   {
1417      int status = QMessageBox::information( this,
1418               tr( "New Data Warning" ),
1419               tr( "This will erase all data currently on the screen, and " 
1420                   "reset the program to its starting condition. No hard-drive "
1421                   "data or database information will be affected. Proceed? " ),
1422               tr( "&OK" ), tr( "&Cancel" ),
1423               0, 0, 1 );
1424      if ( status != 0 ) return;
1425   }
1426
1427   reset();
1428
1429   runID           = "";
1430   data_plot->setTitle( tr( "Intensity Data" ) );
1431}
1432
1433
1434// Enable the common dialog controls based on the presence of data
1435void US_XpnDataViewer::enableControls( void )
1436{
1437   const QChar chlamb( 955 );
1438
1439   if ( allData.size() == 0 )
1440   {  // If no data yet, just reset
1441      reset();
1442      return;
1443   }
1444
1445   // Enable and disable controls now
1446   pb_loadXpn ->setEnabled( false );
1447   pb_loadAUC ->setEnabled( false );
1448   pb_reset   ->setEnabled( true );
1449   pb_details ->setEnabled( true );
1450   pb_reload  ->setEnabled( true );
1451   cb_cellchn ->setEnabled( true );
1452   cb_rstart  ->setEnabled( true );
1453   cb_rend    ->setEnabled( true );
1454   cb_pltrec  ->setEnabled( true );
1455   pb_prev    ->setEnabled( true );
1456   pb_next    ->setEnabled( true );
1457   pb_plot2d  ->setEnabled( true );
1458   pb_saveauc ->setEnabled( true );
1459   pb_showtmst->setEnabled( haveTmst );
1460//   pb_movie2d->setEnabled( true );
1461   ct_from    ->setEnabled( true );
1462   ct_to      ->setEnabled( true );
1463   pb_exclude ->setEnabled( true );
1464
1465   ncellch     = cellchans.count();
1466   nlambda     = lambdas  .count();
1467   ntriple     = triples  .count();
1468   nscan       = allData[ 0 ].scanCount();
1469   npoint      = allData[ 0 ].pointCount();
1470   ntpoint     = nscan * npoint;
1471   int ktrip   = ncellch * nlambda;
1472   isMWL       = ( nlambda > 2  &&  ntriple == ktrip  &&  ntriple > 48 );
1473   cb_cellchn ->setEnabled( isMWL );
1474
1475DbgLv(1) << "ec: ncc nwl nsc npt ntpt" << ncellch << nlambda << nscan
1476 << npoint << ntpoint << "Mwl" << isMWL;
1477DbgLv(1) << "ec: npoint" << npoint << "radsize" << r_radii.count();
1478DbgLv(1) << "ec: nlambda" << nlambda << "lmbsize" << lambdas.count();
1479DbgLv(1) << "ec: ntriple" << ntriple << "trpsize" << triples.count() << "ktrip" << ktrip;
1480   QStringList slrads;
1481   QStringList sllmbs;
1482   QStringList plrecs;
1483
1484   for ( int jj = 0; jj < npoint; jj++ )
1485      slrads << QString().sprintf( "%.3f", r_radii[ jj ] );
1486
1487   for ( int jj = 0; jj < nlambda; jj++ )
1488      sllmbs << QString::number( lambdas[ jj ] );
1489
1490   if ( isMWL )
1491   {
1492      prectype    = ptype_mw;
1493      plrecs      = sllmbs;
1494   }
1495   else
1496   {
1497      prectype    = ptype_tr;
1498      for ( int jj = 0; jj < ntriple; jj++ )
1499         plrecs << QString( triples[ jj ] ).replace( " ", "" );
1500   }
1501
1502   lb_pltrec->setText( prectype );
1503   connect_ranges( false );
1504   cb_cellchn->clear();
1505   cb_rstart ->clear();
1506   cb_rend   ->clear();
1507   cb_pltrec ->clear();
1508
1509   cb_cellchn->addItems( cellchans );
1510   cb_rstart ->addItems( slrads );
1511   cb_rend   ->addItems( slrads );
1512   cb_pltrec ->addItems( plrecs );
1513
1514   if ( nlambda == 1 )
1515      le_lrange ->setText( sllmbs[ 0 ] + tr( " only" ) );
1516   else if ( nlambda > 1 )
1517      le_lrange ->setText( sllmbs[ 0 ] + tr( " to " ) 
1518                         + sllmbs[ nlambda - 1 ] );
1519
1520   cb_cellchn->setCurrentIndex( 0 );
1521   cb_rstart ->setCurrentIndex( 0 );
1522   cb_rend   ->setCurrentIndex( npoint - 1 );
1523   connect_ranges( true );
1524
1525   have_rngs  = false;
1526   compute_ranges( );
1527
1528   ct_from   ->setMaximum( nscan );
1529   ct_to     ->setMaximum( nscan );
1530   cb_pltrec ->setCurrentIndex( nlambda / 2 );
1531   qApp->processEvents();
1532
1533DbgLv(1) << "ec: call changeCellCh";
1534   changeCellCh();                          // Force a plot initialize
1535}
1536
1537// Load Optima raw (.postgres) data
1538bool US_XpnDataViewer::load_xpn_raw_auto( )
1539{
1540  bool status_ok = false;
1541
1542  if ( in_reload_data_init )             // If already doing a reload,
1543    return status_ok;                   //  skip starting a new one
1544 
1545  in_reload_data_init   = true;
1546
1547  // Ask for data directory
1548  QString dbhost    = xpnhost;
1549  int     dbport    = xpnport.toInt();
1550  if ( xpn_data->connect_data( dbhost, dbport, xpnname, xpnuser, xpnpasw ) )
1551    {
1552      // if ( dbg_level > 0 )
1553      //  xpn_data->dump_tables();
1554
1555      // Implement: query ExperiementRun and based on ExpID build array of RunIDs, find the bigger (the latest) and call it RunID_to_retrieve
1556      RunID_to_retrieve = QString::number(xpn_data->get_runid( ExpID_to_use ));
1557
1558      qDebug() << "RunID_to_retrieve 1: " << RunID_to_retrieve;
1559
1560      // runInfo.clear();
1561     
1562      //xpn_data->scan_runs( runInfo );                          // ALEXEY initial query (for us_comproject needs to be based on ExpId )
1563      // xpn_data->filter_runs( runInfo );                        // ALEXEY Optima data filtering by type [Absorbance, Interference etc.]
1564
1565      // for ( int ii = 0; ii < runInfo.count(); ii++ )
1566      //  {
1567      //    QString delim_t       = QString( runInfo[ 0 ] ).left( 1 );
1568      //    QString rDesc_t       = runInfo[ ii ];
1569      //    QString lRunID_t      = QString( rDesc_t ).mid( 1 ).section( delim_t, 0, 0 );
1570
1571      //    qDebug() << "FIRST: runInfo: delim, rDesc, lRunID: " << delim_t << ", " << rDesc_t << ", " << lRunID_t;
1572      //  }
1573    }
1574  else
1575    {
1576      runInfo.clear();
1577    }
1578 
1579  // Check if there are non-zero data
1580  //if ( runInfo.size() < 1 )
1581  if ( RunID_to_retrieve.toInt() == 0) 
1582    {
1583      // QMessageBox::information( this,
1584      //        tr( "Status" ),
1585      //        tr( "Run was submitted to the Optima, but not launched yet. \n"
1586      //            "Awaiting for data to emerge... \n" ) );
1587      // OR Message on connection to Optima: BUT it should be connected here as experiment has just been submitted...
1588      status_ok = false;
1589    }
1590  else 
1591    {
1592      status_ok = true;
1593      timer_data_init->stop();
1594      disconnect(timer_data_init, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
1595      msg_data_avail->accept();
1596      //msg_data_avail->close();
1597      //ok_msg_data->click();
1598
1599      //ALEXEY: make sure ExpID is coupled to the RunID which is already in the autoflow DB
1600      if ( !runID_passed.isEmpty() || runID_passed != "NULL" )
1601  {
1602    if ( runID_passed.toInt() != RunID_to_retrieve.toInt() )
1603      {
1604        RunID_to_retrieve = runID_passed;
1605        qDebug() << "Correcting RunID to : " << RunID_to_retrieve;
1606      }
1607  }
1608 
1609     
1610      //ALEXEY: need to update 'autoflow' table with the unique RunID_to_retrieve && Start Run Time fields !!!
1611      //Conditional:  Do it ONLY once !!!
1612      update_autoflow_runId_timeStarted();
1613
1614      //ALEXEY: retrieve startTime from autoflow table:
1615      ElapsedTimeOffset = read_timeElapsed_offset();
1616
1617      qDebug() << "Elapsed Time Offset as read form autoflow table DB:" << ElapsedTimeOffset;
1618       
1619      //ALEXEY: elapsed timer start
1620      elapsed_timer = new QElapsedTimer;
1621      elapsed_timer->start();
1622     
1623      qDebug() << "RunID_to_retrieve 2: " << RunID_to_retrieve;
1624
1625      runInfo.clear();
1626      xpn_data->scan_runs_auto( runInfo, RunID_to_retrieve );                          // ALEXEY initial query (for us_comproject needs to be based on ExpId )
1627     
1628      for ( int ii = 0; ii < runInfo.count(); ii++ )
1629  {
1630    QString delim_t       = QString( runInfo[ 0 ] ).left( 1 );
1631    QString rDesc_t       = runInfo[ ii ];
1632    QString lRunID_t      = QString( rDesc_t ).mid( 1 ).section( delim_t, 0, 0 );
1633   
1634    qDebug() << "SECOND: runInfo: delim, rDesc, lRunID: " << delim_t << ", " << rDesc_t << ", " << lRunID_t;
1635  }
1636
1637     
1638      //ALEXEY: Start another timer - SysData (RPM, Temp.) - should be run in a separate thread!!!
1639      //Plus to check_for_sys_Data: elapsed time counter!!!
1640      temp_data.clear();
1641      rpm_data.clear();
1642      time_data.clear();
1643     
1644    // Check if all triple info is available
1645      //timer_all_data_avail = new QTimer;
1646      connect(timer_all_data_avail, SIGNAL(timeout()), this, SLOT( retrieve_xpn_raw_auto ( ) ));
1647      timer_all_data_avail->start(5000);     // 5 sec
1648
1649
1650
1651      // timer_check_sysdata = new QTimer(this);
1652      // connect(timer_check_sysdata, SIGNAL(timeout()), this, SLOT(  check_for_sysdata( )  ));
1653      // timer_check_sysdata->start(2000);     //
1654
1655      // OR
1656      //Alternativly: put it in separate thread:
1657      //QThread* sys_thread = new QThread(this);
1658      sys_thread = new QThread(this);
1659      timer_check_sysdata = new QTimer(0); // parent to 0 !
1660      timer_check_sysdata->setInterval(2000);
1661      timer_check_sysdata->moveToThread(sys_thread);
1662      //connect( timer_check_sysdata, SIGNAL(timeout()), this, SLOT( check_for_sysdata( )  ), Qt::QueuedConnection ) ; //Qt::DirectConnection );
1663      connect( timer_check_sysdata, SIGNAL(timeout()), this, SLOT( check_for_sysdata( )  ) );//, Qt::QueuedConnection );
1664      //QThread's started() SIGNAL: before the run()/exec() function is called!!! Is this a potential issue, timer is started from a thread???
1665      connect( sys_thread, SIGNAL( started() ), timer_check_sysdata, SLOT( start() ));
1666      connect( sys_thread, SIGNAL( finished() ), timer_check_sysdata, SLOT( stop() ));
1667      sys_thread->start();
1668      // How to stop sys_thread?
1669     
1670           
1671      // // Check if all triple info is available
1672      // timer_all_data_avail = new QTimer;
1673      // connect(timer_all_data_avail, SIGNAL(timeout()), this, SLOT( retrieve_xpn_raw_auto ( ) ));
1674      // timer_all_data_avail->start(5000);     // 5 sec
1675
1676    }
1677 
1678  in_reload_data_init   = false;
1679  return status_ok;
1680}
1681
1682
1683// When Optima run started & runID aqcuried, update 'autoflow' table
1684void US_XpnDataViewer::update_autoflow_runId_timeStarted( void )
1685{
1686   // Check DB connection
1687   US_Passwd pw;
1688   QString masterpw = pw.getPasswd();
1689   US_DB2* db = new US_DB2( masterpw );
1690
1691   if ( db->lastErrno() != US_DB2::OK )
1692     {
1693       QMessageBox::warning( this, tr( "Connection Problem" ),
1694           tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
1695       return;
1696     }
1697
1698   QStringList qry;
1699   qry << "update_autoflow_runid_starttime"
1700       << ExpID_to_use
1701       << RunID_to_retrieve;
1702
1703   db->query( qry );
1704   //ALEXEY: Updates with runID && timeStarted only once, when runID && runStarttime IS NULL
1705}
1706
1707// Read diffference btw started tiem and NOW() as an offset for Elapsed time
1708int US_XpnDataViewer::read_timeElapsed_offset( void )
1709{
1710   // Check DB connection
1711   US_Passwd pw;
1712   QString masterpw = pw.getPasswd();
1713   US_DB2* db = new US_DB2( masterpw );
1714
1715   int time_offset = 0;
1716   
1717   if ( db->lastErrno() != US_DB2::OK )
1718     {
1719       QMessageBox::warning( this, tr( "Connection Problem" ),
1720           tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
1721       return time_offset;
1722     }
1723   
1724   QStringList qry;
1725   qry << "read_autoflow_times_mod"
1726       << RunID_to_retrieve;
1727
1728   // //Test only
1729   // qry << "read_autoflow_times_mod_test";
1730     
1731   time_offset = db->functionQuery( qry );
1732
1733   return time_offset;
1734}
1735
1736//Delete autoflow record upon Run abortion
1737void US_XpnDataViewer::delete_autoflow_record( void )
1738{
1739   // Check DB connection
1740   US_Passwd pw;
1741   QString masterpw = pw.getPasswd();
1742   US_DB2* db = new US_DB2( masterpw );
1743
1744   if ( db->lastErrno() != US_DB2::OK )
1745     {
1746       QMessageBox::warning( this, tr( "Connection Problem" ),
1747           tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
1748       return;
1749     }
1750
1751   QStringList qry;
1752   qry << "delete_autoflow_record"
1753       << RunID_to_retrieve;
1754
1755   //db->query( qry );
1756
1757   // OR
1758   
1759   int status = db->statusQuery( qry );
1760   
1761   if ( status == US_DB2::NO_AUTOFLOW_RECORD )
1762     {
1763       QMessageBox::warning( this,
1764           tr( "Autoflow Record Not Deleted" ),
1765           tr( "No autoflow record\n"
1766         "associated with this experiment." ) );
1767       return;
1768     }
1769}
1770   
1771
1772//Delete autoflow record upon Run abortion
1773void US_XpnDataViewer::updateautoflow_record_atLiveUpdate( void )
1774{
1775
1776   details_at_live_update[ "runID" ] = RunID_to_retrieve;
1777 
1778   // Check DB connection
1779   US_Passwd pw;
1780   QString masterpw = pw.getPasswd();
1781   US_DB2* db = new US_DB2( masterpw );
1782
1783   if ( db->lastErrno() != US_DB2::OK )
1784     {
1785       QMessageBox::warning( this, tr( "Connection Problem" ),
1786           tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
1787       return;
1788     }
1789
1790   QStringList qry;
1791   qry << "update_autoflow_at_live_update"
1792       << RunID_to_retrieve
1793       << currentDir;
1794
1795   db->query( qry );
1796
1797   details_at_live_update[ "dataPath" ] = currentDir;
1798
1799   //ALEXEY: if there is NO chromatic Abber. data, set corrRadii in autoflow record to 'NO'
1800   if ( correctRadii == "NO" )
1801     {
1802       qry.clear();
1803       qry << "update_autoflow_at_live_update_radiicorr"
1804     << RunID_to_retrieve;
1805
1806       db->query( qry );
1807
1808       details_at_live_update[ "correctRadii" ] = QString("NO"); //currentDir;
1809     }
1810
1811   //ALEXEY: if run was aborted manually from the Optima panel, set expAborted to 'YES'
1812   if ( experimentAborted )
1813     {
1814       qry.clear();
1815       qry << "update_autoflow_at_live_update_expaborted"
1816     << RunID_to_retrieve;
1817
1818       db->query( qry );
1819
1820       details_at_live_update[ "expAborted" ] = QString("YES");
1821     }
1822   
1823   // // OR
1824
1825   // qDebug() << "Trying to Update Autoflow table AT LIVE_UPDATE!!";
1826   // int status = db->statusQuery( qry );
1827   
1828   // if ( status == US_DB2::NO_AUTOFLOW_RECORD )
1829   //   {
1830   //     QMessageBox::warning( this,
1831   //            tr( "Autoflow Record Not Updated" ),
1832   //            tr( "No autoflow record\n"
1833   //          "associated with RunID %1 exists!" ).arg( RunID_to_retrieve ) );
1834   //     return;
1835   //   }
1836}
1837   
1838
1839// Check periodically for SysData
1840void US_XpnDataViewer::check_for_sysdata( void )
1841{
1842  qDebug() << "sys_timer IS RUNNING here: ";
1843  qDebug() << "sys_timer IS RUNNING here: in_reload_check_sysdata " << in_reload_check_sysdata;
1844 
1845  if ( in_reload_check_sysdata )            // If already doing a reload,
1846    return;                                //  skip starting a new one
1847 
1848  in_reload_check_sysdata   = true;          // Flag in the midst of a reload
1849
1850  int idrun = RunID_to_retrieve.toInt();
1851   
1852  //xpn_data->update_isysrec( idrun );
1853
1854  int exp_time = 0;
1855  double temperature=0;
1856  int rpm;
1857  //int etimoff;
1858  //int stage_number;
1859  while ( temperature == 0 ) // what if the temperature is actually set to zero degrees?
1860  {
1861    xpn_data->update_isysrec( idrun );
1862    exp_time       = xpn_data->countOf_sysdata( "exp_time"  ).toInt();     //time form the start
1863  //stage_number   = xpn_data->countOf_sysdata( "stage_number" ).toInt();  //stage number
1864    temperature    = xpn_data->countOf_sysdata( "tempera" ).toDouble();    //temperature
1865    rpm            = xpn_data->countOf_sysdata( "last_rpm"  ).toInt();     //revolutions per minute !
1866    //etimoff        = xpn_data->countOf_sysdata( "etim_off"  ).toInt();     //experimental time offset
1867  }
1868
1869  // Update rmp, temperature GUI icons...
1870  //RPM speed
1871  double rpm_for_meter = double(rpm/1000.0);
1872  rpm_box->setSpeed(rpm_for_meter);
1873  qApp->processEvents();
1874 
1875  //Temperature
1876  temperature_box->setTemp(temperature);
1877  qApp->processEvents();
1878 
1879  //Running Time
1880  QList< int > dhms_r;
1881  int running_time = exp_time;// + etimoff; //ALEXEY: OR elapsed_time + etimoff? OR just exp_time ???? //ALEXEY: etimoff < 0 ?
1882  if ( running_time < 0 )
1883    running_time = 0;
1884  timeToList( running_time, dhms_r );
1885  QString running_time_text;
1886  //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
1887  //ALEXEY: if times >~1 day, update #hours
1888  if ( dhms_r[0] > 0 )
1889    dhms_r[1] += 24;
1890 
1891  running_time_text = QString::number(dhms_r[1]) + ":" + QString::number(dhms_r[2]) + ":" + QString::number(dhms_r[3]);
1892  le_running->setText( running_time_text );
1893  qApp->processEvents();
1894
1895  //Elapsed Time
1896  qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Elapsed Time Offset as read form autoflow table DB:" << ElapsedTimeOffset;
1897
1898  QList< int > dhms_e;
1899  int elapsed_time = int( elapsed_timer->elapsed() / 1000 ) + ElapsedTimeOffset;
1900  int elapsed_time_1 = elapsed_time;
1901  timeToList( elapsed_time, dhms_e );
1902  QString elapsed_time_text;
1903  //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
1904  //ALEXEY: if times >~1 day, update #hours
1905  if ( dhms_e[0] > 0 )
1906    dhms_e[1] += 24;
1907 
1908  elapsed_time_text = QString::number(dhms_e[1]) + ":" + QString::number(dhms_e[2]) + ":" + QString::number(dhms_e[3]);
1909  le_elapsed->setText( elapsed_time_text );
1910  qApp->processEvents();
1911 
1912  //Remaining Time
1913  QList< int > dhms_remain;
1914  int remaining_time = TotalDuration.toInt() - ( exp_time ); //+ etimoff );
1915  timeToList( remaining_time, dhms_remain );
1916  QString remaining_time_text;
1917  //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
1918  //ALEXEY: if times >~1 day, update #hours
1919  if ( dhms_remain[0] > 0 )
1920    dhms_remain[1] += 24;
1921   
1922  remaining_time_text = QString::number(dhms_remain[1]) + ":" + QString::number(dhms_remain[2]) + ":" + QString::number(dhms_remain[3]);
1923  le_remaining->setText( remaining_time_text );
1924  qApp->processEvents();
1925
1926  //RPM/Temp. Plots:
1927
1928  //counter_mins += 500; //temporary for testing only
1929
1930  rpm_data.push_back(rpm);
1931  time_data.push_back( double(elapsed_time_1/60.0) );  // Running time in minutes
1932  temp_data.push_back(temperature);
1933 
1934  //time_data.push_back( double(elapsed_time_1/60.0) );  // Running time in minutes
1935
1936  // //Debugs for RPM, Temp., Time
1937  //qDebug() << "Sizes of arrays: RMP.size(), temperature.size() " <<  rpm_data.size() << ", " << temp_data.size();
1938     
1939  double* d_rpm          = rpm_data.data();
1940  double* d_temp         = temp_data.data();
1941  double* d_time         = time_data.data();
1942 
1943  //axis ranges, temporary
1944  double rpm_min = 0;
1945  double rpm_max = rpm + 5000;
1946  double temp_min = temperature - 1;
1947  if(temp_min < 0)
1948    temp_min = 0;
1949  double temp_max = temperature + 1;
1950
1951  //if (temp_data.size() != 0 )
1952  curv_temp->setSamples( d_time, d_temp, time_data.size() );
1953  curv_rpm->setSamples(  d_time, d_rpm,  time_data.size() );   
1954 
1955  //data_plot_rpm->setAxisScale( QwtPlot::xBottom, 0.0, double(elapsed_time_1/60.0) );  // <-- HERE
1956  data_plot_rpm->setAxisScale( QwtPlot::xBottom, double(ElapsedTimeOffset/60.0), double(elapsed_time_1/60.0) );  //
1957  //data_plot_rpm->setAxisScale( QwtPlot::xBottom, 0.0, double(exp_time/60.0 + counter_mins ) ); // for testing only
1958  data_plot_rpm->setAxisScale( QwtPlot::yLeft, rpm_min, rpm_max );     //Y-RPM
1959  data_plot_rpm->setAxisScale( QwtPlot::yRight, temp_min, temp_max );  //Y-Temp.
1960 
1961  //ALEXEY: no plot rescaling to bounds...
1962
1963  qDebug() << "SYS_STAT: BEFORE replot(), BEFORE CheExpStat!! ";
1964   
1965  data_plot_rpm->replot();
1966  qApp->processEvents();
1967
1968  qDebug() << "SYS_STAT: After replot(), BEFORE CheExpStat!! ";
1969
1970  int exp_status = CheckExpComplete_auto( RunID_to_retrieve  );
1971   
1972  if ( exp_status == 55 || exp_status == 10 )
1973    {
1974      if ( exp_status == 0)
1975  experimentAborted  = true;
1976     
1977      //timer_check_sysdata->stop();
1978      //ALEXEY: This timer cannot be stopped from another thread, but can be dealt with signal/slot upon Qthread termination..
1979      //        disconnection maybe enough...
1980      disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
1981      //Maybe add this?
1982      sys_thread->quit();     // ALEXEY: I think this emits Qthread's finished() signal... (connected to stopping timer_sysdata)
1983      qApp->processEvents();  // <-- IMPORTANT to process event loop while stopping thread!!!
1984     
1985      if ( sys_thread->isFinished() )
1986  qDebug() << "QThread STOPPED !!! ";
1987     
1988      if ( !timer_check_sysdata->isActive() )
1989  qDebug() << "QTimer timer_check_sysdata STOPPED by quitting the QThread !!! ";
1990
1991      qDebug() << "ExpStat: 5/0  - sys_timer STOPPED here: ";
1992     
1993      rpm_box->setSpeed( 0 );
1994      le_remaining->setText( "00:00:00" );
1995      qApp->processEvents();
1996     
1997      if ( !timer_all_data_avail->isActive() ) // Check if reload_data Timer is stopped
1998  {
1999    if ( !timer_data_reload->isActive() )
2000      {
2001        qDebug() << "TRY PROCEED INTO == 5/0 from check_for_sys_data()....";
2002
2003        export_auc_auto();
2004       
2005        // QString mtitle_complete  = tr( "Complete!" );
2006        // QString message_done     = tr( "Experiment was completed. Optima data saved..." );
2007        // QMessageBox::information( this, mtitle_complete, message_done );
2008       
2009        updateautoflow_record_atLiveUpdate();
2010        //emit experiment_complete_auto( currentDir, ProtocolName, invID_passed, correctRadii  );  // Updtade later: what should be passed with signal ??
2011
2012        reset_auto();
2013
2014        in_reload_check_sysdata   = false;
2015       
2016        emit experiment_complete_auto( details_at_live_update );
2017       
2018        return;
2019      }
2020  }
2021    }
2022 
2023 
2024  // if ( exp_status == 0 ) //ALEXEY should be == 3 as per documentation
2025  //   {
2026  //     experimentAborted  = true;
2027  //     //timer_check_sysdata->stop();
2028  //     disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
2029  //     sys_thread->quit(); // ALEXEY: does this emit Qthread's finished() signal??
2030  //     qDebug() << "ExpStat: 3  - sys_timer STOPPED here: ";
2031     
2032  //     rpm_box->setSpeed( 0 );
2033  //     le_remaining->setText( "00:00:00" );
2034     
2035  //     if ( !timer_all_data_avail->isActive() ) // Check if reload_data Timer is stopped
2036  //  {
2037  //    if ( !timer_data_reload->isActive() )
2038  //      {
2039  //        // Ask if data retrived so far should be saved:
2040       
2041  //        QMessageBox msgBox;
2042  //        msgBox.setText(tr("Experiment was aborted!"));
2043  //        msgBox.setInformativeText("The data retrieved so far can be saved or disregarded. If saved, the program will proceed to the next stage (Editing). Otherwise, it will return to the initial stage (Experiment), all data will be lost.");
2044  //        msgBox.setWindowTitle(tr("Experiment Abortion"));
2045  //        QPushButton *Save      = msgBox.addButton(tr("Save Data"), QMessageBox::YesRole);
2046  //        QPushButton *Ignore    = msgBox.addButton(tr("Ignore Data"), QMessageBox::RejectRole);
2047       
2048  //        msgBox.setIcon(QMessageBox::Question);
2049  //        msgBox.exec();
2050       
2051  //        if (msgBox.clickedButton() == Save)
2052  //    {
2053  //      export_auc_auto();
2054     
2055  //      QString mtitle_complete  = tr( "Complete!" );
2056  //      QString message_done     = tr( "Experiment was completed. Optima data saved..." );
2057  //      QMessageBox::information( this, mtitle_complete, message_done );
2058     
2059  //      updateautoflow_record_atLiveUpdate();
2060  //      emit experiment_complete_auto( currentDir, ProtocolName, invID_passed, correctRadii  );  // Updtade later: what should be passed with signal ??
2061  //      return;
2062  //    }
2063       
2064  //        else if (msgBox.clickedButton() == Ignore)
2065  //    {
2066  //      reset();
2067  //      delete_autoflow_record();
2068  //      emit return_to_experiment( ProtocolName  );
2069  //      return;
2070  //    }
2071  //      } 
2072  //  }
2073  //   }
2074 
2075
2076   qDebug() << "sys_timer RAN here: ";
2077   in_reload_check_sysdata   = false;
2078 
2079  //qDebug() << "sys_timer RAN here: ";
2080}
2081
2082
2083// Function to convert from a time in sec. to days, hours, minutes, seconds
2084void US_XpnDataViewer::timeToList( int& sectime, QList< int >& dhms )
2085{
2086   int t_day = (int)( sectime / (24*3600) );
2087   sectime -= t_day * 24 * 3600;
2088
2089   int t_hour = (int)( sectime / 3600 );
2090   sectime -= t_hour * 3600;
2091
2092   int t_minute = (int)( sectime / 60 );
2093   sectime -= t_minute * 60;
2094
2095   int t_second = sectime;
2096
2097   qDebug() << "TimeToList(): DD: " << t_day;
2098   qDebug() << "TimeToList(): HH: " << t_hour;
2099   qDebug() << "TimeToList(): MM: " << t_minute;
2100   qDebug() << "TimeToList(): SS: " << t_second;
2101   
2102   dhms.clear();
2103   dhms << t_day << t_hour << t_minute << t_second;
2104}
2105
2106//Query for Optima DB periodically, see if data available
2107void US_XpnDataViewer::check_for_data( QMap < QString, QString > & protocol_details)
2108{
2109  //Also reset the panel before reattachement
2110  //reset_auto();
2111 
2112  xpn_data->setEtimOffZero(); //ALEXEY: intialize etimoff to zero for the first time
2113
2114  experimentAborted  = false;
2115  counter_mins = 0;
2116  ElapsedTimeOffset = 0;
2117 
2118  ExpID_to_use = protocol_details["experimentId"];   
2119  ProtocolName = protocol_details["protocolName"];
2120  RunName      = protocol_details[ "experimentName" ];
2121  CellChNumber = protocol_details[ "CellChNumber" ];
2122  TripleNumber = protocol_details[ "TripleNumber" ];
2123  OptimaName   = protocol_details[ "OptimaName" ];               //New
2124  TotalDuration = protocol_details[ "duration" ];
2125  invID_passed = protocol_details[ "invID_passed" ];
2126  correctRadii = protocol_details[ "correctRadii" ];
2127  expAborted   = protocol_details[ "expAborted" ];
2128  runID_passed = protocol_details[ "runID" ];
2129 
2130  qDebug() << "RUNID_PASSED !!! " << runID_passed;
2131
2132  details_at_live_update = protocol_details;
2133
2134  selectOptimaByName_auto( OptimaName );                         //New 
2135
2136  //ALEXEY: just define all QTimers here for later safe stopping
2137  timer_all_data_avail = new QTimer;
2138  timer_data_reload = new QTimer;
2139  timer_end_processes = new QTimer;
2140
2141
2142  timer_data_init = new QTimer;
2143  connect(timer_data_init, SIGNAL(timeout()), this, SLOT( load_xpn_raw_auto( ) ));
2144  timer_data_init->start(5000);     // 5 sec
2145
2146  msg_data_avail = new QMessageBox;
2147  msg_data_avail->setIcon(QMessageBox::Information);
2148 
2149  //msg_data_avail->setStandardButtons(0);
2150  msg_data_avail->setWindowFlags ( Qt::CustomizeWindowHint | Qt::WindowTitleHint);
2151  // QPushButton *okButton = msg_data_avail->addButton(tr("Ok"), QMessageBox::AcceptRole);
2152  // okButton->hide();
2153
2154  QPushButton *Close    = msg_data_avail->addButton(tr("Return to Managing Optima Runs?"), QMessageBox::RejectRole);
2155  msg_data_avail->setText(tr( "Run named <b>%1</b> was submitted to: <br>"
2156                    "<br><b>%2</b> <br>"
2157              "<br>Please start this method scan from the instrument panel. <br>"
2158              "<br>You may return to managing Optima runs now and reattach later by reopening and "
2159              "selecting <b>%1</b> among the list of Optima runs to follow. "
2160              "Alternatively, you can wait untill the method is started from "
2161              "the Optima panel and monitor the progress.")
2162          .arg(RunName).arg(OptimaName) );
2163
2164  msg_data_avail->setWindowTitle(tr("Live Update"));
2165 
2166  if ( runID_passed.isEmpty() || runID_passed == "NULL" )
2167    {
2168      msg_data_avail->exec();
2169     
2170      if (msg_data_avail->clickedButton() == Close)
2171  {
2172    timer_data_init->stop();
2173    disconnect(timer_data_init, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
2174   
2175    reset_auto();
2176
2177    emit close_program(); 
2178  }
2179    }
2180}
2181
2182
2183// Reset LIVE UPDATE panel && stop timers && quit threads
2184void US_XpnDataViewer::reset_liveupdate_panel_public ( void )
2185{
2186  finishing_live_update = true;
2187  reset_liveupdate_panel();
2188}
2189
2190
2191// Reset LIVE UPDATE panel && stop timers && quit threads
2192void US_XpnDataViewer::reset_liveupdate_panel ( void )
2193{
2194  //Quit sys_thread, emit finished() to stop timer_check_sysdata from withing thread
2195  if ( !sys_thread->isFinished() )
2196    {
2197      sys_thread->quit();   
2198      qApp->processEvents();
2199    }
2200
2201  //Disconnect timer_check_sysdata
2202  if ( timer_check_sysdata->isActive() )
2203    {
2204      timer_check_sysdata->stop();
2205      disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);
2206
2207      qDebug() << "Stopping timer_check_sysdata";
2208    }
2209 
2210  //Stop other timers if active
2211  if ( timer_all_data_avail->isActive() ) 
2212    {
2213      timer_all_data_avail->stop();
2214      disconnect(timer_all_data_avail, SIGNAL(timeout()), 0, 0);
2215
2216       qDebug() << "Stopping timer_all_data_avail";
2217    }
2218 
2219  if ( timer_data_reload->isActive() )
2220    {
2221      timer_data_reload->stop();
2222      disconnect(timer_data_reload, SIGNAL(timeout()), 0, 0);
2223
2224      qDebug() << "Stopping timer_data_reload";
2225    }
2226
2227  if ( timer_data_init->isActive() )
2228    {
2229      timer_data_init->stop();
2230      disconnect(timer_data_init, SIGNAL(timeout()), 0, 0);
2231
2232      qDebug() << "Stopping timer_data_init";
2233    }
2234
2235  qApp->processEvents();
2236 
2237  /***** DEBUG ***********************/
2238  if ( sys_thread->isFinished() )
2239    qDebug() << "QThread STOPPED upon clickig Manage Optima runs !!! ";
2240 
2241  if ( !timer_check_sysdata->isActive() )
2242    qDebug() << "QTimer timer_check_sysdata STOPPED by clickig Manage Optima runs !!! ";
2243
2244  if ( !timer_data_init->isActive() )
2245    qDebug() << "QTimer timer_data_init STOPPED by clickig Manage Optima runs !!! ";
2246 
2247  if ( !timer_all_data_avail->isActive() )
2248    qDebug() << "QTimer timer_all_data_avail STOPPED by clickig Manage Optima runs !!! ";
2249
2250  if ( !timer_data_reload->isActive() )
2251    qDebug() << "QTimer timer_data_reload STOPPED by clickig Manage Optima runs !!! ";
2252  /*************************************/
2253
2254  qDebug() << "BEFORE: " << in_reload_auto << ", " << in_reload_all_data << ", " << in_reload_data_init << ", " << in_reload_check_sysdata;
2255 
2256  //ALEXEY: should wait for execution of all below variables to be false (end of all timer functions) BEFORE reset_all();
2257  // Introduce QTimer which checks for all abpve vartibales to be false (check all related functions to always reset them to false on completion)
2258  // Put reset_auto() into the timer && and stop/disconnect timer from within connected SLOT.
2259  //timer_end_processes = new QTimer;
2260  connect(timer_end_processes, SIGNAL(timeout()), this, SLOT( end_processes ( ) ));
2261  timer_end_processes->start(1000);     // 5 sec
2262 
2263  qApp->processEvents();
2264}
2265
2266//to end all existing update processes
2267void US_XpnDataViewer::end_processes( void )
2268{
2269  qDebug() << "In the END process: in_reload_end_processes = " << in_reload_end_processes;
2270 
2271  if ( in_reload_end_processes )            // If already doing a reload,
2272    return;                              //  skip starting a new one
2273 
2274  in_reload_end_processes   = true;          // Flag in the midst of a reload
2275 
2276  qDebug() << "Checking if processes STOPPED.";
2277  qDebug() << "MIDDLE: " << in_reload_auto << ", " << in_reload_all_data << ", " << in_reload_data_init << ", " << in_reload_check_sysdata;
2278     
2279  if (  !in_reload_auto && !in_reload_all_data &&  !in_reload_data_init && !in_reload_check_sysdata ) 
2280    {
2281     
2282      timer_end_processes->stop();
2283      disconnect(timer_end_processes, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
2284
2285      //ALEXEY: may not be needed
2286      qDebug() << "LIVE UPDATE panel has been reset!";
2287      qDebug() << "AFTER: " << in_reload_auto << ", " << in_reload_all_data << ", " << in_reload_data_init << ", " << in_reload_check_sysdata;
2288     
2289      reset_auto(); 
2290      qApp->processEvents();
2291     
2292      in_reload_end_processes = false; 
2293
2294      emit liveupdate_processes_stopped();
2295       
2296      //in_reload_end_processes   = false;
2297    }
2298  else
2299    {
2300      in_reload_end_processes   = false; 
2301      qApp->processEvents();
2302    }
2303}
2304
2305
2306//void US_XpnDataViewer::retrieve_xpn_raw_auto( QString & RunID )
2307void US_XpnDataViewer::retrieve_xpn_raw_auto( void )
2308{
2309   if ( in_reload_all_data )            // If already doing a reload,
2310     return;                            //  skip starting a new one
2311 
2312   in_reload_all_data   = true;          // Flag in the midst of a reload
2313 
2314   QString drDesc    = "";
2315   QString delim       = ( runInfo.count() > 0 ) ?
2316                         QString( runInfo[ 0 ] ).left( 1 ) :
2317                         "";
2318   /************* For Automated *****/
2319   // Search description list and choose the item with matching runID
2320   for ( int ii = 0; ii < runInfo.count(); ii++ )                   // In principle there should be just 1 record in runInfo
2321   {
2322      QString rDesc       = runInfo[ ii ];
2323      QString lRunID      = QString( rDesc ).mid( 1 ).section( delim, 0, 0 );
2324
2325      qDebug() << "IN retrieve_xpn_raw_auto: rDesc " << rDesc << ", lRunID: "  << lRunID << ", RunID: " <<  RunID_to_retrieve;
2326     
2327      if ( lRunID == RunID_to_retrieve )                                       // ExpII is passed from US_Experiment
2328  {
2329    qDebug() << "RunID found !!!";
2330    drDesc = rDesc;
2331    break;
2332  }
2333   }
2334   
2335//   US_XpnRunRaw* lddiag = new US_XpnRunRaw( drDesc, runInfo );
2336//    if ( lddiag->exec() == QDialog::Rejected )                    //ALEXEY need drDesc but do NOT need dialog
2337//    {
2338// DbgLv(1) << "RDr:  rtn fr XpnRunRaw dialog: CANCEL";
2339//       return;
2340//    }
2341
2342//    // Restore area beneath dialog
2343//    qApp->processEvents();
2344// DbgLv(1) << "RDr:  rtn fr XpnRunRaw dialog";
2345// DbgLv(1) << "RDr:   drDesc" << drDesc;
2346
2347   // See if we need to fix the runID
2348
2349
2350   QString fRunId    = QString( drDesc ).section( delim, 1, 1 ); 
2351
2352   qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!DRDESC: " << drDesc << ", fRunId:  " << fRunId; 
2353
2354   
2355   QString fExpNm    = QString( drDesc ).section( delim, 5, 5 );
2356   QString new_runID = fExpNm + "-run" + fRunId;
2357   runType           = "RI";
2358   QRegExp rx( "[^A-Za-z0-9_-]" );
2359
2360   int pos            = 0;
2361   bool runID_changed = false;
2362
2363   if ( new_runID.length() > 60 )
2364   {
2365      int kchar         = 60 - 4 - fRunId.length();
2366      new_runID         = fExpNm.left( kchar ) + "-run" + fRunId;
2367      runID_changed     = true;
2368   }
2369
2370   while ( ( pos = rx.indexIn( new_runID ) ) != -1 )
2371   {
2372      new_runID.replace( pos, 1, "_" );         // Replace 1 char at pos
2373      runID_changed     = true;
2374   }
2375
2376   // Let the user know if the runID name has changed
2377   if ( runID_changed )
2378   {
2379      QMessageBox::warning( this,
2380            tr( "RunId Name Changed" ),
2381            tr( "The runId name has been changed.\nIt may consist only "
2382                "of alphanumeric characters,\nthe underscore, and the "
2383                "hyphen;\nand may be at most 60 characters in length."
2384                "\nNew runId:\n  " ) + new_runID );
2385   }
2386
2387   // Set the runID and directory
2388   runID       = new_runID;
2389   le_runID->setText( runID );
2390   currentDir  = US_Settings::importDir() + "/" + runID;
2391   le_dir  ->setText( currentDir );
2392   qApp->processEvents();
2393
2394   // Read the data
2395   //QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
2396   le_status->setText( tr( "Reading Raw Optima data ..." ) );
2397   qApp->processEvents();
2398QDateTime sttime=QDateTime::currentDateTime();
2399
2400   int iRunId         = fRunId.toInt();
2401   QString sMasks     = QString( drDesc ).section( delim, 7, 10 );
2402   int scanmask       = QString( sMasks ).mid( 0, 1 ) == "1" ? 1 : 0;
2403   scanmask          += QString( sMasks ).mid( 2, 1 ) == "1" ? 2 : 0;
2404   scanmask          += QString( sMasks ).mid( 4, 1 ) == "1" ? 4 : 0;
2405   scanmask          += QString( sMasks ).mid( 6, 1 ) == "1" ? 8 : 0;
2406DbgLv(1) << "RDr:     iRId" << iRunId << "sMsks scnmask" << sMasks << scanmask;
2407
2408 qDebug() << "RDr:     iRId" << iRunId << "sMsks scnmask" << sMasks << scanmask;
2409
2410 //ALEXEY: maybe put in_reload_check_sysdata = true; and then false (after xpn_data->import_data( iRunId, scanmask ); )
2411 //in_reload_check_sysdata = true; //ALEXEY
2412 xpn_data->import_data( iRunId, scanmask );                               // ALEXEY <-- actual data retreiving
2413   int ntsrows        = xpn_data->countOf( "scan_rows" );
2414DbgLv(1) << "RDr:     ntsrows" << ntsrows;
2415DbgLv(1) << "RDr:      knt(triple)   " << xpn_data->countOf( "triple"    );
2416 qApp->processEvents();
2417
2418   if ( ntsrows < 1 )
2419   {
2420      le_status->setText( tr( "Run %1 has no associated data..." )
2421                          .arg( fRunId ) );
2422
2423      in_reload_all_data   = false; 
2424      return;
2425   }
2426
2427   le_status->setText( tr( "Initial Raw Optima data import complete." ) );
2428   qApp->processEvents();
2429   //in_reload_check_sysdata = false; //ALEXEY
2430   
2431double tm1=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
2432   QStringList opsys;
2433
2434   // Infer and report on type of data to eventually export
2435   runType            = "RI";
2436   int optndx         = 0;
2437
2438   if ( scanmask == 1  ||  scanmask == 2  ||
2439        scanmask == 4  ||  scanmask == 8 )
2440   {
2441      runType            = ( scanmask == 2 ) ? "FI" : runType;
2442      runType            = ( scanmask == 4 ) ? "IP" : runType;
2443      runType            = ( scanmask == 8 ) ? "WI" : runType;
2444      if ( scanmask == 1 )
2445         opsys << "Absorbance";
2446      else if ( scanmask == 2 )
2447         opsys << "Fluorescence";
2448      else if ( scanmask == 4 )
2449         opsys << "Interference";
2450      else if ( scanmask == 8 )
2451         opsys << "Wavelength";
2452   }
2453
2454   else if ( ( scanmask & 1 ) != 0 )
2455   {
2456      QApplication::restoreOverrideCursor();
2457      QApplication::restoreOverrideCursor();
2458      QString runType2( "IP" );
2459      runType2           = ( ( scanmask & 2 ) != 0 ) ? "FI" : runType2;
2460      runType2           = ( ( scanmask & 8 ) != 0 ) ? "WI" : runType2;
2461      QString drtype1    = "Absorbance";
2462      QString drtype2    = "Interference";
2463      drtype1            = ( runType  == "FI" ) ? "Fluorescence" : drtype1;
2464      drtype1            = ( runType  == "IP" ) ? "Interference" : drtype1;
2465      drtype1            = ( runType  == "WI" ) ? "Wavelength"   : drtype1;
2466      drtype2            = ( runType2 == "RI" ) ? "Absorbance"   : drtype2;
2467      drtype2            = ( runType2 == "FI" ) ? "Fluorescence" : drtype2;
2468      drtype2            = ( runType2 == "WI" ) ? "Wavelength"   : drtype2;
2469      opsys << drtype1 << drtype2;
2470
2471      QString msg        = tr( "Multiple scan data types are present:\n" )
2472                           +   "'" + drtype1 + "'\n or \n"
2473                           +   "'" + drtype2 + "' .\n\n"
2474                           + tr( "Choose one for initial display." );
2475      QMessageBox mbox;
2476      mbox.setWindowTitle( tr( "Scan Data Type to Process" ) );
2477      mbox.setText( msg );
2478      QPushButton* pb_opt1 = mbox.addButton( drtype1, QMessageBox::AcceptRole );
2479      QPushButton* pb_opt2 = mbox.addButton( drtype2, QMessageBox::RejectRole );
2480      mbox.setEscapeButton ( pb_opt2 );
2481      mbox.setDefaultButton( pb_opt1 );
2482
2483      mbox.exec();
2484      if ( mbox.clickedButton() == pb_opt2 )
2485      {
2486         runType            = runType2;
2487         optndx             = 1;
2488      }
2489   }
2490
2491   qApp->processEvents();  //ALEXEY: maybe this will help
2492   
2493   qDebug() << "1. Crashes HERE!!!!";
2494     
2495   cb_optsys->disconnect();
2496   cb_optsys->clear();
2497
2498   qDebug() << "1a. Crashes HERE!!!!";
2499   
2500   cb_optsys->addItems( opsys );                                  // ALEXEY fill out Optics listbox
2501
2502   qDebug() << "1ab. Crashes HERE!!!! - BEFORE Setting index to cb_optsys";
2503   cb_optsys->setCurrentIndex( optndx );
2504   qDebug() << "1ac. Crashes HERE!!!! - AFTER Setting index to cb_optsys";
2505   
2506   connect( cb_optsys,    SIGNAL( currentIndexChanged( int ) ),
2507            this,         SLOT  ( changeOptics( )            ) );
2508
2509   qDebug() << "1b. Crashes HERE!!!!";
2510   
2511   runID         = new_runID;
2512DbgLv(1) << "RDr:  runID" << runID << "runType" << runType;
2513   xpn_data->set_run_values( runID, runType );                    // ALEXEY
2514
2515   qDebug() << "2. Crashes HERE!!!! (after xpn_data->set_run_values( runID, runType ) )";
2516
2517   // Build the AUC equivalent
2518   //QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
2519   le_status->setText( tr( "Building AUC data ..." ) );
2520   qApp->processEvents();
2521
2522   xpn_data->build_rawData( allData );                            // ALEXEY Builds Raw Data
2523
2524   qDebug() << "3. Crashes HERE!!!! (after  xpn_data->build_rawData( allData ))";
2525   
2526double tm2=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
2527DbgLv(1) << "RDr:      build-raw done: tm1 tm2" << tm1 << tm2;
2528
2529   QApplication::restoreOverrideCursor();
2530   QApplication::restoreOverrideCursor();
2531   isRaw         = true;
2532   haveData      = true;
2533   ncellch       = xpn_data->cellchannels( cellchans );
2534   r_radii.clear();
2535   r_radii << allData[ 0 ].xvalues;
2536   nscan         = allData[ 0 ].scanCount();
2537   npoint        = allData[ 0 ].pointCount();
2538
2539DbgLv(1) << "RDr: mwr ntriple" << ntriple;
2540DbgLv(1) << "RDr: ncellch" << ncellch << cellchans.count();
2541DbgLv(1) << "RDr: nscan" << nscan << "npoint" << npoint;
2542DbgLv(1) << "RDr:   rvS rvE" << r_radii[0] << r_radii[npoint-1];
2543   cb_cellchn->disconnect();                                     
2544   cb_cellchn->clear();
2545   cb_cellchn->addItems( cellchans );                             // ALEXEY fill out Cells/Channels listbox
2546   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
2547            this,         SLOT  ( changeCellCh(            ) ) );
2548
2549   nlambda      = xpn_data->lambdas_raw( lambdas );               // ALEXEY  lambdas
2550   int wvlo     = lambdas[ 0 ];
2551   int wvhi     = lambdas[ nlambda - 1 ];
2552#if 0
2553   ntriple      = nlambda * ncellch;  // Number triples
2554   ntpoint      = npoint  * nscan;    // Number radius points per triple
2555DbgLv(1) << "RDr: nwl wvlo wvhi" << nlambda << wvlo << wvhi
2556   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple;
2557   triples.clear();
2558
2559   for ( int jj = 0; jj < ncellch; jj++ )
2560   {
2561      QString celchn  = cellchans[ jj ];
2562
2563      for ( int kk = 0; kk < nlambda; kk++ )
2564         triples << celchn + " / " + QString::number( lambdas[ kk] );
2565   }
2566#endif
2567#if 1
2568   ntriple      = xpn_data->data_triples( triples );              // ALEXEY triples
2569DbgLv(1) << "RDr: nwl wvlo wvhi" << nlambda << wvlo << wvhi
2570   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple
2571   << triples.count();
2572
2573 qDebug() << "RDr: nwl wvlo wvhi" << nlambda << wvlo << wvhi
2574   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple
2575   << triples.count();
2576#endif
2577
2578DbgLv(1) << "RDr: allData size" << allData.size();
2579
2580 qDebug() << "RDr: allData size" << allData.size();
2581
2582 //QApplication::restoreOverrideCursor();
2583   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
2584   haveTmst       = QFile( tspath ).exists();
2585   in_reload_auto      = false;
2586
2587   // Ok to enable some buttons now
2588   enableControls();                                    //ALEXEY ...and actual plotting data
2589
2590   qDebug() << "CellChNumber, cellchans.count() " << CellChNumber.toInt() << ", " << cellchans.count();
2591   qDebug() << "TripleNumber, ntriple " << TripleNumber.toInt() << ", " << ntriple;
2592
2593   //ALEXEY: Add Exp. Abortion Exception HERE...
2594   if ( CheckExpComplete_auto( RunID_to_retrieve ) == 10 ) //ALEXEY should be == 3 as per documentation
2595     {
2596       qDebug() << "ABORTION IN EARLY STAGE...";
2597       
2598       experimentAborted  = true;
2599       
2600       timer_all_data_avail->stop();
2601       disconnect(timer_all_data_avail, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
2602       
2603       if ( !timer_check_sysdata->isActive()  ) // Check if sys_data Timer is stopped
2604   {
2605     export_auc_auto();
2606     updateautoflow_record_atLiveUpdate();
2607
2608     reset_auto();
2609     
2610     in_reload_all_data   = false; 
2611     
2612     emit experiment_complete_auto( details_at_live_update  ); 
2613     return;
2614   }
2615     }
2616 
2617   
2618   
2619   if ( cellchans.count() == CellChNumber.toInt() && ntriple == TripleNumber.toInt() )                // <--- Change to the values from the protocol
2620     {
2621       //stop timer
2622       timer_all_data_avail->stop();
2623       disconnect(timer_all_data_avail, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
2624
2625       in_reload_all_data   = false; 
2626       
2627       // Auto-update hereafter
2628       //timer_data_reload = new QTimer;
2629
2630       if ( !finishing_live_update )
2631   {
2632     connect(timer_data_reload, SIGNAL(timeout()), this, SLOT( reloadData_auto( ) ));
2633     timer_data_reload->start(10000);     // 5 sec
2634   }
2635     }
2636
2637   in_reload_all_data   = false; 
2638}
2639
2640
2641// Load Optima raw (.postgres) data
2642void US_XpnDataViewer::load_xpn_raw( )
2643{
2644
2645   // Ask for data directory
2646   QString dbhost    = xpnhost;
2647   int     dbport    = xpnport.toInt();
2648DbgLv(1) << "RDr: call connect_data  dbname h p u w"
2649 << xpnname << dbhost << dbport << xpnuser << xpnpasw;
2650   if ( xpn_data->connect_data( dbhost, dbport, xpnname, xpnuser, xpnpasw ) )
2651   {
2652if ( dbg_level > 0 ) xpn_data->dump_tables();
2653       xpn_data->scan_runs( runInfo );                         
2654#if 0
2655DbgLv(1) << "RDr:  pre-filter runs" << runInfo.count();
2656 xpn_data->filter_runs( runInfo );                             
2657DbgLv(1) << "RDr:  post-filter runs" << runInfo.count();
2658#endif
2659DbgLv(1) << "RDr:  rtn fr scan_runs,filter_runs";
2660   }
2661   else
2662   {
2663DbgLv(1) << "RDr:  connection failed";
2664      runInfo.clear();
2665   }
2666   
2667   QString drDesc    = "";
2668   US_XpnRunRaw* lddiag = new US_XpnRunRaw( drDesc, runInfo );
2669   if ( lddiag->exec() == QDialog::Rejected )                 
2670   {
2671DbgLv(1) << "RDr:  rtn fr XpnRunRaw dialog: CANCEL";
2672      return;
2673   }
2674
2675   // Restore area beneath dialog
2676   qApp->processEvents();
2677DbgLv(1) << "RDr:  rtn fr XpnRunRaw dialog";
2678DbgLv(1) << "RDr:   drDesc" << drDesc;
2679
2680   // See if we need to fix the runID
2681   QString delim     = QString( drDesc ).left( 1 );
2682   QString fRunId    = QString( drDesc ).section( delim, 1, 1 );
2683   QString fExpNm    = QString( drDesc ).section( delim, 5, 5 );
2684   QString new_runID = fExpNm + "-run" + fRunId;
2685   runType           = "RI";
2686   QRegExp rx( "[^A-Za-z0-9_-]" );
2687
2688   int pos            = 0;
2689   bool runID_changed = false;
2690
2691   if ( new_runID.length() > 60 )
2692   {
2693      int kchar         = 60 - 4 - fRunId.length();
2694      new_runID         = fExpNm.left( kchar ) + "-run" + fRunId;
2695      runID_changed     = true;
2696   }
2697
2698   while ( ( pos = rx.indexIn( new_runID ) ) != -1 )
2699   {
2700      new_runID.replace( pos, 1, "_" );         // Replace 1 char at pos
2701      runID_changed     = true;
2702   }
2703
2704   // Let the user know if the runID name has changed
2705   if ( runID_changed )
2706   {
2707      QMessageBox::warning( this,
2708            tr( "RunId Name Changed" ),
2709            tr( "The runId name has been changed.\nIt may consist only "
2710                "of alphanumeric characters,\nthe underscore, and the "
2711                "hyphen;\nand may be at most 60 characters in length."
2712                "\nNew runId:\n  " ) + new_runID );
2713   }
2714
2715   // Set the runID and directory
2716   runID       = new_runID;
2717   le_runID->setText( runID );
2718   currentDir  = US_Settings::importDir() + "/" + runID;
2719   le_dir  ->setText( currentDir );
2720   qApp->processEvents();
2721
2722   // Read the data
2723   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
2724   le_status->setText( tr( "Reading Raw Optima data ..." ) );
2725   qApp->processEvents();
2726QDateTime sttime=QDateTime::currentDateTime();
2727
2728   int iRunId         = fRunId.toInt();
2729   QString sMasks     = QString( drDesc ).section( delim, 7, 10 );
2730   int scanmask       = QString( sMasks ).mid( 0, 1 ) == "1" ? 1 : 0;
2731   scanmask          += QString( sMasks ).mid( 2, 1 ) == "1" ? 2 : 0;
2732   scanmask          += QString( sMasks ).mid( 4, 1 ) == "1" ? 4 : 0;
2733   scanmask          += QString( sMasks ).mid( 6, 1 ) == "1" ? 8 : 0;
2734DbgLv(1) << "RDr:     iRId" << iRunId << "sMsks scnmask" << sMasks << scanmask;
2735
2736 xpn_data->import_data( iRunId, scanmask );                             
2737   int ntsrows        = xpn_data->countOf( "scan_rows" );
2738DbgLv(1) << "RDr:     ntsrows" << ntsrows;
2739DbgLv(1) << "RDr:      knt(triple)   " << xpn_data->countOf( "triple"    );
2740
2741
2742   if ( ntsrows < 1 )
2743   {
2744      le_status->setText( tr( "Run %1 has no associated data..." )
2745                          .arg( fRunId ) );
2746      return;
2747   }
2748
2749   le_status->setText( tr( "Initial Raw Optima data import complete." ) );
2750   qApp->processEvents();
2751double tm1=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
2752   QStringList opsys;
2753
2754   // Infer and report on type of data to eventually export
2755   runType            = "RI";
2756   int optndx         = 0;
2757
2758   if ( scanmask == 1  ||  scanmask == 2  ||
2759        scanmask == 4  ||  scanmask == 8 )
2760   {
2761      runType            = ( scanmask == 2 ) ? "FI" : runType;
2762      runType            = ( scanmask == 4 ) ? "IP" : runType;
2763      runType            = ( scanmask == 8 ) ? "WI" : runType;
2764      if ( scanmask == 1 )
2765         opsys << "Absorbance";
2766      else if ( scanmask == 2 )
2767         opsys << "Fluorescence";
2768      else if ( scanmask == 4 )
2769         opsys << "Interference";
2770      else if ( scanmask == 8 )
2771         opsys << "Wavelength";
2772   }
2773
2774   else if ( ( scanmask & 1 ) != 0 )
2775   {
2776      QApplication::restoreOverrideCursor();
2777      QApplication::restoreOverrideCursor();
2778      QString runType2( "IP" );
2779      runType2           = ( ( scanmask & 2 ) != 0 ) ? "FI" : runType2;
2780      runType2           = ( ( scanmask & 8 ) != 0 ) ? "WI" : runType2;
2781      QString drtype1    = "Absorbance";
2782      QString drtype2    = "Interference";
2783      drtype1            = ( runType  == "FI" ) ? "Fluorescence" : drtype1;
2784      drtype1            = ( runType  == "IP" ) ? "Interference" : drtype1;
2785      drtype1            = ( runType  == "WI" ) ? "Wavelength"   : drtype1;
2786      drtype2            = ( runType2 == "RI" ) ? "Absorbance"   : drtype2;
2787      drtype2            = ( runType2 == "FI" ) ? "Fluorescence" : drtype2;
2788      drtype2            = ( runType2 == "WI" ) ? "Wavelength"   : drtype2;
2789      opsys << drtype1 << drtype2;
2790
2791      QString msg        = tr( "Multiple scan data types are present:\n" )
2792                           +   "'" + drtype1 + "'\n or \n"
2793                           +   "'" + drtype2 + "' .\n\n"
2794                           + tr( "Choose one for initial display." );
2795      QMessageBox mbox;
2796      mbox.setWindowTitle( tr( "Scan Data Type to Process" ) );
2797      mbox.setText( msg );
2798      QPushButton* pb_opt1 = mbox.addButton( drtype1, QMessageBox::AcceptRole );
2799      QPushButton* pb_opt2 = mbox.addButton( drtype2, QMessageBox::RejectRole );
2800      mbox.setEscapeButton ( pb_opt2 );
2801      mbox.setDefaultButton( pb_opt1 );
2802
2803      mbox.exec();
2804      if ( mbox.clickedButton() == pb_opt2 )
2805      {
2806         runType            = runType2;
2807         optndx             = 1;
2808      }
2809   }
2810
2811   cb_optsys->disconnect();
2812   cb_optsys->clear();
2813   cb_optsys->addItems( opsys );                               
2814   cb_optsys->setCurrentIndex( optndx );
2815   connect( cb_optsys,    SIGNAL( currentIndexChanged( int ) ),
2816            this,         SLOT  ( changeOptics( )            ) );
2817
2818   runID         = new_runID;
2819DbgLv(1) << "RDr:  runID" << runID << "runType" << runType;
2820   xpn_data->set_run_values( runID, runType );                 
2821
2822   // Build the AUC equivalent
2823   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
2824   le_status->setText( tr( "Building AUC data ..." ) );
2825   qApp->processEvents();
2826
2827   xpn_data->build_rawData( allData );                           
2828double tm2=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
2829DbgLv(1) << "RDr:      build-raw done: tm1 tm2" << tm1 << tm2;
2830
2831   QApplication::restoreOverrideCursor();
2832   QApplication::restoreOverrideCursor();
2833   isRaw         = true;
2834   haveData      = true;
2835   ncellch       = xpn_data->cellchannels( cellchans );
2836   r_radii.clear();
2837   r_radii << allData[ 0 ].xvalues;
2838   nscan         = allData[ 0 ].scanCount();
2839   npoint        = allData[ 0 ].pointCount();
2840
2841DbgLv(1) << "RDr: mwr ntriple" << ntriple;
2842DbgLv(1) << "RDr: ncellch" << ncellch << cellchans.count();
2843DbgLv(1) << "RDr: nscan" << nscan << "npoint" << npoint;
2844DbgLv(1) << "RDr:   rvS rvE" << r_radii[0] << r_radii[npoint-1];
2845   cb_cellchn->disconnect();                                     
2846   cb_cellchn->clear();
2847   cb_cellchn->addItems( cellchans );                           
2848   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
2849            this,         SLOT  ( changeCellCh(            ) ) );
2850
2851   nlambda      = xpn_data->lambdas_raw( lambdas );             
2852   int wvlo     = lambdas[ 0 ];
2853   int wvhi     = lambdas[ nlambda - 1 ];
2854#if 0
2855   ntriple      = nlambda * ncellch;  // Number triples
2856   ntpoint      = npoint  * nscan;    // Number radius points per triple
2857DbgLv(1) << "RDr: nwl wvlo wvhi" << nlambda << wvlo << wvhi
2858   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple;
2859   triples.clear();
2860
2861   for ( int jj = 0; jj < ncellch; jj++ )
2862   {
2863      QString celchn  = cellchans[ jj ];
2864
2865      for ( int kk = 0; kk < nlambda; kk++ )
2866         triples << celchn + " / " + QString::number( lambdas[ kk] );
2867   }
2868#endif
2869#if 1
2870   ntriple      = xpn_data->data_triples( triples );           
2871DbgLv(1) << "RDr: nwl wvlo wvhi" << nlambda << wvlo << wvhi
2872   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple
2873   << triples.count();
2874#endif
2875
2876DbgLv(1) << "RDr: allData size" << allData.size();
2877   QApplication::restoreOverrideCursor();
2878   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
2879   haveTmst       = QFile( tspath ).exists();
2880   in_reload      = false;
2881
2882   // Ok to enable some buttons now
2883   enableControls();                                 
2884}
2885
2886
2887// Load US3 AUC Optima-derived data
2888void US_XpnDataViewer::load_auc_xpn( )
2889{
2890   int status        = 0;
2891   QStringList ifpaths;
2892
2893   resetAll();
2894
2895   QString dir       = "";
2896   US_XpnRunAuc lddiag( dir );
2897   if ( lddiag.exec() == QDialog::Rejected )
2898      return;
2899   
2900   // Restore area beneath dialog
2901   qApp->processEvents();
2902
2903   if ( dir.isEmpty() ) return; 
2904   
2905   dir.replace( "\\", "/" );                 // WIN32 issue
2906   if ( dir.right( 1 ) != "/" ) dir += "/";  // Ensure trailing '/'
2907   
2908   // Check the runID
2909   QString new_runID = dir.section( "/", -2, -2 ).simplified();
2910DbgLv(1) << "RDa: runID" << new_runID;
2911DbgLv(1) << "RDa: dir" << dir;
2912     
2913   QRegExp rx( "^[A-Za-z0-9_-]{1,80}$" );
2914   if ( rx.indexIn( new_runID ) < 0 )
2915   {
2916      QMessageBox::warning( this,
2917            tr( "Bad runID Name" ),
2918            tr( "The runID name may consist only of alphanumeric\n" 
2919                "characters, the underscore, and the hyphen." ) );
2920      return;
2921   }
2922
2923   // Set the runID and directory
2924   runID             = new_runID;
2925   currentDir        = dir;
2926   le_runID ->setText( runID );
2927   le_dir   ->setText( currentDir );
2928DbgLv(1) << "RDa: runID" << runID;
2929DbgLv(1) << "RDa: dir" << currentDir;
2930
2931   // Error reporting
2932   if ( status == US_DB2::NO_PROJECT ) 
2933   { 
2934      QMessageBox::information( this, 
2935            tr( "Attention" ), 
2936            tr( "The project was not found.\n" 
2937                "Please select an existing project and try again.\n" ) ); 
2938   } 
2939   
2940   else if ( status != US_DB2::OK ) 
2941   { 
2942      QMessageBox::information( this, 
2943            tr( "Disk Read Problem" ), 
2944            tr( "Could not read data from the disk.\n" 
2945                "Disk status: " ) + QString::number( status ) ); 
2946   }
2947
2948   // Load the AUC data
2949   le_status->setText( tr( "Reading AUC Xpn data ..." ) );
2950   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
2951   QDir dirdir( dir, "*", QDir::Name, QDir::Files | QDir::Readable );
2952   dirdir.makeAbsolute();
2953   if ( dir.right( 1 ) != "/" ) dir += "/"; // Ensure trailing /
2954   xpn_fnames       = dirdir.entryList( QStringList( "*.auc" ),
2955                                        QDir::Files, QDir::Name );
2956   xpn_fnames.sort();
2957   ntriple           = xpn_fnames.size();
2958   cellchans.clear();
2959   lambdas  .clear();
2960   triples  .clear();
2961   int missm         = 0;
2962DbgLv(1) << "RDa: mwr ntriple" << ntriple;
2963
2964   for ( int ii = 0; ii < ntriple; ii++ )
2965   {
2966      QString mwrfname  = xpn_fnames.at( ii );
2967      QString mwrfpath  = currentDir + mwrfname;
2968      ifpaths << mwrfpath;
2969      US_DataIO::RawData  rdata;
2970
2971      US_DataIO::readRawData( mwrfpath, rdata );
2972
2973      allData << rdata;
2974
2975      QString celchn    = QString::number( rdata.cell ) + " / " +
2976                          QString( rdata.channel );
2977      QString ccnode    = mwrfname.section( ".", -4, -3 );
2978      QString celchnf   = ccnode.replace( ".", " / " );
2979
2980      if ( celchn != celchnf )
2981      {
2982DbgLv(1) << "RDa:   **F/D MISMATCH** " << celchn << celchnf << ii;
2983         celchn            = celchnf;
2984         missm++;
2985      }
2986
2987      int lambda        = qRound( rdata.scanData[ 0 ].wavelength );
2988      QString triple    = celchn + " / " + QString::number( lambda );
2989
2990      if ( ! cellchans.contains( celchn ) )
2991         cellchans << celchn;
2992
2993      if ( ! lambdas.contains( lambda ) )
2994         lambdas   << lambda;
2995
2996      if ( ! triples.contains( triple ) )
2997         triples   << triple;
2998
2999      le_status->setText( tr( "Data in for triple %1 of %2" )
3000                          .arg( ii + 1 ).arg( ntriple ) );
3001      qApp->processEvents();
3002   }
3003
3004   if ( missm > 0 )
3005   {
3006      QMessageBox::warning( this,
3007            tr( "Data/File Cell/Channel Mismatches" ),
3008            tr( "%1 mismatch(es) occurred in the Cell/Channel setting\n"
3009               " of AUC data versus File name nodes.\n\n"
3010               "The Cell/Channel settings  have been corrected,\n"
3011               " but input data should be reviewed!!" )
3012               .arg( missm ) );
3013   }
3014
3015   r_radii.clear();
3016   r_radii << allData[ 0 ].xvalues;
3017
3018   isRaw        = false;
3019   haveData     = true;
3020   ncellch      = cellchans .size();
3021   nlambda      = lambdas   .size();
3022   nscan        = allData[ 0 ].scanCount();
3023   npoint       = allData[ 0 ].pointCount();
3024   ntpoint      = nscan * npoint;
3025DbgLv(1) << "RDa: mwr ncellch nlambda nscan npoint"
3026 << ncellch << nlambda << nscan << npoint;
3027DbgLv(1) << "RDa:   rvS rvE" << r_radii[0] << r_radii[npoint-1];
3028   le_status->setText( tr( "All %1 raw AUCs have been loaded." )
3029                       .arg( ntriple ) );
3030   QApplication::restoreOverrideCursor();
3031   QApplication::restoreOverrideCursor();
3032   qApp->processEvents();
3033
3034   ct_from->setMaximum( nscan );
3035   ct_to  ->setMaximum( nscan );
3036
3037   xpn_data->load_auc( allData, ifpaths );
3038
3039   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
3040   haveTmst       = QFile( tspath ).exists();
3041DbgLv(1) << "RDa: load_auc complete";
3042   // Ok to enable some buttons now
3043   enableControls();
3044DbgLv(1) << "RDa: enableControls complete";
3045}
3046
3047// Display detailed information about the data
3048void US_XpnDataViewer::runDetails( void )
3049{
3050   // Use the data object to compose details text
3051   QString msg = xpn_data->runDetails();
3052
3053   // Open the dialog and display the report text
3054   US_Editor* editd = new US_Editor( US_Editor::DEFAULT, true );
3055
3056   editd->setWindowTitle( tr( "Optima Raw Data Statistics" ) );
3057   editd->move( pos() + QPoint( 200, 200 ) );
3058   editd->resize( 600, 500 );
3059   editd->e->setFont( QFont( US_Widgets::fixedFont().family(),
3060                             US_GuiSettings::fontSize() ) );
3061   editd->e->setText( msg );
3062   editd->show();
3063}
3064
3065// Plot the current data record
3066void US_XpnDataViewer::plot_current( void )
3067{
3068   if ( allData.size() == 0 )
3069      return;
3070
3071   plot_titles();     // Set the titles
3072
3073   plot_all();        // Plot the data
3074}
3075
3076// Compose plot titles for the current record
3077void US_XpnDataViewer::plot_titles( void )
3078{
3079DbgLv(1) << "pTit: prectype" << prectype;
3080   QString prec     = cb_pltrec->currentText();
3081   QString cell     = prec.section( "/", 0, 0 ).simplified();
3082   QString chan     = prec.section( "/", 1, 1 ).simplified();
3083   QString wvln     = prec.section( "/", 2, 2 ).simplified();
3084
3085   if ( isMWL )
3086   {
3087      QString cellch   = cb_cellchn ->currentText();
3088      cell             = cellch.section( "/", 0, 0 ).simplified();
3089      chan             = cellch.section( "/", 1, 1 ).simplified();
3090      wvln             = prec;
3091   }
3092DbgLv(1) << "pTit: prec" << prec << "isMWL" << isMWL << "wvln" << wvln;
3093
3094   // Plot Title and legends
3095   QString title    = "Radial Intensity Data\nRun ID: " + runID +
3096                      "\n    Cell: " + cell + "  Channel: " + chan +
3097                      "  Wavelength: " + wvln;
3098   QString xLegend  = QString( "Radius (in cm)" );
3099   QString yLegend  = "Radial Intensity at " + wvln + " nm";
3100
3101   if ( runType == "IP" )
3102   {
3103      title            = "Interference Data\nRun ID: " + runID +
3104                         "\n    Cell: " + cell + "  Channel: " + chan +
3105                         "  Wavelength: " + wvln;
3106      yLegend          = "Interference at " + wvln + " nm";
3107   }
3108   else if ( runType == "FI" )
3109   {
3110      title            = "Fluorescence Intensity Data\nRun ID: " + runID +
3111                         "\n    Cell: " + cell + "  Channel: " + chan +
3112                         "  Wavelength: " + wvln;
3113      yLegend          = "Fluorescence at " + wvln + " nm";
3114   }
3115   else if ( runType == "WI" )
3116   {
3117      title            = "Wavelength Intensity Data\nRun ID: " + runID +
3118                         "\n    Cell: " + cell + "  Channel: " + chan +
3119                         "  Radius: " + wvln;
3120      xLegend          = QString( "Wavelength (in nm)" );
3121      yLegend          = "Radial Intensity at " + wvln;
3122   }
3123
3124   data_plot->setTitle( title );
3125   data_plot->setAxisTitle( QwtPlot::yLeft,   yLegend );
3126   data_plot->setAxisTitle( QwtPlot::xBottom, xLegend );
3127}
3128
3129// Draw scan curves for the current plot record
3130void US_XpnDataViewer::plot_all( void )
3131{
3132   dPlotClearAll( data_plot );
3133   grid           = us_grid( data_plot );
3134
3135   // Make sure ranges are set up, then build an averaged data vector
3136   compute_ranges();
3137
3138   //   DbgLv(1) << "PltA: kpoint" << kpoint << "datsize" << curr_adata.size();
3139   DbgLv(1) << "PltA: kpoint" << kpoint << "trpxs" << trpxs;
3140// << "nscan" << nscan << allData[trpxs].scanCount();
3141   // Build the X,Y vectors
3142   QVector< double > rvec( kpoint );
3143   QVector< double > vvec( kpoint );
3144   double* rr     = rvec.data();
3145   double* vv     = vvec.data();
3146
3147   int     scan_from = (int)ct_from->value();
3148   int     scan_to   = (int)ct_to  ->value();
3149   int     scan_nbr  = 0;
3150   QPen    pen_red ( Qt::red );
3151   QPen    pen_plot( US_GuiSettings::plotCurve() );
3152   int     rdx       = radxs;
3153   int     colx      = -1;
3154   US_DataIO::RawData* rdata = &allData[ trpxs ];
3155   int     scan_knt  = rdata->scanCount();
3156
3157   for ( int ptx = 0; ptx < kpoint; ptx++, rdx++ )
3158   {  // One-time build of X vector
3159      rr[ ptx ]       = rdata->xvalues[ rdx ];
3160   }
3161DbgLv(1) << "PltA:   rr[n]" << rr[kpoint-1];
3162
3163//   for ( int scnx = 0; scnx < nscan; scnx++ )
3164   for ( int scnx = 0; scnx < scan_knt; scnx++ )
3165   {  // Build Y vector for each scan
3166      if ( excludes.contains( scnx ) )  continue;
3167
3168      for ( int ptx = 0, rdx = radxs; ptx < kpoint; ptx++, rdx++ )
3169      {
3170         vv[ ptx ]       = rdata->value( scnx, rdx );
3171      }
3172
3173      if ( mcknt > 0 )
3174      {
3175         colx                = scan_nbr % mcknt;
3176         pen_plot            = QPen( mcolors[ colx ] );
3177      }
3178
3179      scan_nbr++;
3180if(scnx<3 || (scnx+4)>nscan)
3181DbgLv(1) << "PltA:   vv[n]" << vv[kpoint-1] << "scnx" << scnx
3182 << "scan_nbr" << scan_nbr << "colx" << colx;
3183      QString       title = tr( "Raw Data at scan " )
3184                            + QString::number( scan_nbr );
3185      QwtPlotCurve* curv  = us_curve( data_plot, title );
3186
3187      if ( scan_nbr > scan_to  ||  scan_nbr < scan_from )
3188         curv->setPen( pen_plot );            // Normal pen
3189      else
3190         curv->setPen( pen_red  );            // Scan-focus pen
3191
3192      curv->setSamples( rr, vv, kpoint );     // Build a scan curve
3193//DbgLv(1) << "PltA:   scx" << scx << "rr0 vv0 rrn vvn"
3194// << rr[0] << rr[kpoint-1] << vv[0] << vv[kpoint-1];
3195   }
3196
3197DbgLv(1) << "PltA: last_xmin" << last_xmin;
3198   if ( last_xmin < 0.0 )
3199   {  // If first time, use auto scale to set plot ranges
3200      data_plot->setAxisAutoScale( QwtPlot::yLeft   );
3201      data_plot->setAxisAutoScale( QwtPlot::xBottom );
3202   }
3203
3204   else
3205   {  // After first time, use the same plot ranges as set before
3206      data_plot->setAxisScale( QwtPlot::xBottom, last_xmin, last_xmax );
3207      if ( ck_autoscy->isChecked() )
3208         data_plot->setAxisAutoScale( QwtPlot::yLeft   );
3209      else
3210         data_plot->setAxisScale( QwtPlot::yLeft  , last_ymin, last_ymax );
3211   }
3212
3213   // Draw the plot
3214//   connect( plot, SIGNAL( zoomedCorners( QRectF ) ),
3215//            this, SLOT  ( currentRectf ( QRectF ) ) );
3216   data_plot->replot();
3217
3218   // Pick up the actual bounds plotted (including any Config changes)
3219   QwtScaleDiv* sdx = AXISSCALEDIV( QwtPlot::xBottom );
3220   QwtScaleDiv* sdy = AXISSCALEDIV( QwtPlot::yLeft   );
3221   last_xmin      = sdx->lowerBound();
3222   last_xmax      = sdx->upperBound();
3223   last_ymin      = sdy->lowerBound();
3224   last_ymax      = sdy->upperBound();
3225DbgLv(1) << "PltA: xlo xhi" << last_xmin << last_xmax
3226 << "ylo yhi" << last_ymin << last_ymax;
3227}
3228
3229// Slot to handle a change in start or end radius
3230void US_XpnDataViewer::changeRadius()
3231{
3232DbgLv(1) << "chgRadius";
3233   have_rngs  = false;
3234   compute_ranges();                        // Recompute ranges
3235   last_xmin      = -1;
3236   last_xmax      = -1;
3237
3238   plot_current();                      // Re-plot with adjusted range
3239}
3240
3241void US_XpnDataViewer::changeCellCh( void )
3242{
3243   // Match the description to find the correct triple in memory
3244   QString cellch = cb_cellchn->currentText();
3245DbgLv(1) << "chgCC:  cellch" << cellch << "last_xmin" << last_xmin;
3246   if ( allData.size() < 1 )
3247      return;
3248
3249   if ( last_xmin < 0.0 )
3250   {  // If first time plotting any data, detect actual data bounds
3251      have_rngs     = false;
3252      compute_ranges();
3253
3254      int trxs      = trpxs + lmbxs;
3255      int trxe      = trpxs + lmbxe;
3256
3257      last_xmin     = allData[ trxs ].xvalues[ radxs ];
3258      last_xmax     = last_xmin;
3259      US_DataIO::RawData* edata = &allData[ trxs ];
3260
3261      for ( int rdx = radxs; rdx < radxe; rdx++ )
3262      {
3263         last_xmin  = qMin( last_xmin, edata->xvalues[ rdx ] );
3264         last_xmax  = qMax( last_xmax, edata->xvalues[ rdx ] );
3265      }
3266
3267      last_ymin     = allData[ trxs ].reading( 0, 0 );
3268      last_ymax     = last_ymin;
3269
3270      for ( int trx = trxs; trx < trxe; trx++ )
3271      {  // Accumulate Y bounds, the amplitude bounds
3272         US_DataIO::RawData* edata = &allData[ trx ];
3273
3274         for ( int scx = 0; scx < nscan; scx++ )
3275         {
3276            for ( int rdx = radxs; rdx < radxe; rdx++ )
3277            {
3278               last_ymin  = qMin( last_ymin, edata->reading( scx, rdx ) );
3279               last_ymax  = qMax( last_ymax, edata->reading( scx, rdx ) );
3280            }
3281         }
3282      }
3283DbgLv(1) << "chgCC: trxs trxe" << trxs << trxe;
3284   }
3285
3286   else
3287   {  // After first time, detect what has been already set
3288      QwtScaleDiv* sdx = AXISSCALEDIV( QwtPlot::xBottom );
3289      QwtScaleDiv* sdy = AXISSCALEDIV( QwtPlot::yLeft   );
3290      last_xmin      = sdx->lowerBound();
3291      last_xmax      = sdx->upperBound();
3292      last_ymin      = sdy->lowerBound();
3293      last_ymax      = sdy->upperBound();
3294   }
3295DbgLv(1) << "chgCC:  xmin xmax ymin ymax"
3296 << last_xmin << last_xmax << last_ymin << last_ymax;
3297
3298   have_rngs      = false;
3299   int lplrec     = ntriple - 1;
3300
3301   // Make sure cell/channel and plot record are in sync
3302   if ( ! isMWL )
3303   {  // If plot record ranges are triples, point to first of cell/channel
3304      QString ccval  = cb_cellchn->currentText().replace( " / ", "/" );
3305      QString ccplr  = cb_pltrec->currentText().section( "/", 0, 1 );
3306DbgLv(1) << "chgCC: ccval" << ccval << "ccplr" << ccplr;
3307
3308      if ( ccval != ccplr )
3309      {
3310         for ( int jj = 0; jj < ntriple; jj++ )
3311         {
3312            ccplr          = triples[ jj ].section( "/", 0, 1 ).simplified()
3313                                          .replace( " / ", "/" );
3314DbgLv(1) << "chgCC:   jj" << jj << "ccplr" << ccplr;
3315            if ( ccplr == ccval )
3316            {  // Set plot record to first triple from cell/channel
3317               connect_ranges( false );
3318DbgLv(1) << "chgCC:     set pltrec index" << jj;
3319               cb_pltrec->setCurrentIndex( jj );
3320               connect_ranges( true );
3321               break;
3322            }
3323         }
3324      }
3325   }
3326   else
3327   {  // If plot record ranges are wavelengths, point to first wavelength
3328DbgLv(1) << "chgCC: isMWL" << isMWL;
3329      lplrec         = nlambda - 1;
3330//      connect_ranges( false );
3331//      cb_pltrec->setCurrentIndex( 0 );
3332//      connect_ranges( true );
3333   }
3334
3335   compute_ranges();
3336   pb_prev  ->setEnabled( ( recx > 0 )      );
3337   pb_next  ->setEnabled( ( recx < lplrec ) );
3338
3339//   changeRecord();
3340   plot_current();
3341}
3342
3343// Slot to handle a change in the plot record
3344void US_XpnDataViewer::changeRecord( void )
3345{
3346   recx           = cb_pltrec->currentIndex();
3347   int lplrec     = ntriple - 1;
3348
3349   if ( isMWL )
3350   {  // For MWL, limit record range to lambda range
3351      lplrec         = nlambda - 1;
3352   }
3353
3354   else
3355   {  // For non-MWL, change cell/channel if appropriate
3356      QString new_cc = QString( cb_pltrec->currentText() )
3357                       .section( "/", 0, 1 ).replace( "/", " / " );
3358      QString celchn = cb_cellchn->currentText();
3359
3360      if ( new_cc != celchn )
3361      {
3362         int iccx       = cellchans.indexOf( new_cc );
3363         connect_ranges( false );
3364         cb_cellchn->setCurrentIndex( iccx );
3365         QString new_wl = QString( cb_pltrec->currentText() )
3366                          .section( "/", 2, 2 );
3367         le_lrange ->setText( new_wl + tr( " only" ) );
3368         connect_ranges( true );
3369      }
3370   }
3371
3372DbgLv(1) << "chgRec: recx" << recx;
3373
3374   // Plot what we have
3375   plot_current();
3376
3377   // Update status text (if not part of movie save) and set prev/next arrows
3378   le_status->setText( lb_pltrec->text() + "  " + cb_pltrec->currentText() );
3379   pb_prev  ->setEnabled( ( recx > 0 )      );
3380   pb_next  ->setEnabled( ( recx < lplrec ) );
3381}
3382
3383// Slot to handle a change in the optical system
3384void US_XpnDataViewer::changeOptics( void )
3385{
3386   // Determine the new run type
3387   int optrx      = cb_optsys->currentIndex();
3388   QString ostyp  = cb_optsys ->currentText();
3389   QString rtype( "RI" );
3390   if ( ostyp == "Interference" )
3391      rtype          = "IP";
3392   else if ( ostyp == "Fluorescence" )
3393      rtype          = "FI";
3394   else if ( ostyp == "Wavelength" )
3395      rtype          = "WI";
3396DbgLv(1) << "chgOpt: optrx" << optrx << "ostyp" << ostyp
3397 << "rtype" << rtype << "nopts" << cb_optsys->children().count();
3398
3399  // If simply re-choosing the same optics, bale out now
3400   if ( rtype == runType )
3401      return;
3402
3403QDateTime sttime=QDateTime::currentDateTime();
3404   runType       = rtype;    // Set the new run type (RI, IP, ...)
3405
3406   // Turn off auto-reload if on
3407   if ( rlt_id != 0 )
3408   {
3409      ck_autorld->setChecked( false );
3410      QMessageBox::warning( this,
3411            tr( "Auto-Reload Stopped" ),
3412            tr( "Auto-Reload has been stopped and its box unchecked,"
3413                "\n since the optical system has been changed." ) );
3414   }
3415
3416   // Set up for a new run type
3417   xpn_data->set_run_values( runID, runType );
3418
3419   // For new optics, rebuild internal arrays and all AUC
3420   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
3421   le_status->setText( tr( "Rebuilding AUC data ..." ) );
3422   qApp->processEvents();
3423
3424   xpn_data->build_rawData( allData );
3425double tm2=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
3426DbgLv(1) << "chgOpt:   build-raw done: tm2" << tm2;
3427
3428   QApplication::restoreOverrideCursor();
3429   QApplication::restoreOverrideCursor();
3430
3431   // Reset various flags, counts, and lists
3432   isRaw         = true;
3433   haveData      = true;
3434   ncellch       = xpn_data->cellchannels( cellchans );
3435   r_radii.clear();
3436   r_radii << allData[ 0 ].xvalues;
3437   nscan         = allData[ 0 ].scanCount();
3438   npoint        = allData[ 0 ].pointCount();
3439
3440DbgLv(1) << "chgOpt: mwr ntriple" << ntriple;
3441DbgLv(1) << "chgOpt: ncellch" << ncellch << cellchans.count();
3442DbgLv(1) << "chgOpt: nscan" << nscan << "npoint" << npoint;
3443DbgLv(1) << "chgOpt:   rvS rvE" << r_radii[0] << r_radii[npoint-1];
3444   cb_cellchn->disconnect();
3445   cb_cellchn->clear();
3446   cb_cellchn->addItems( cellchans );
3447   connect( cb_cellchn,   SIGNAL( currentIndexChanged( int ) ),
3448            this,         SLOT  ( changeCellCh(            ) ) );
3449
3450   nlambda      = xpn_data->lambdas_raw( lambdas );
3451   int wvlo     = lambdas[ 0 ];
3452   int wvhi     = lambdas[ nlambda - 1 ];
3453   ntriple      = xpn_data->data_triples( triples );
3454DbgLv(1) << "chgOpt: nwl wvlo wvhi" << nlambda << wvlo << wvhi
3455   << "ncellch" << ncellch << "nlambda" << nlambda << "ntriple" << ntriple
3456   << triples.count();
3457
3458DbgLv(1) << "chgOpt: allData size" << allData.size();
3459   QApplication::restoreOverrideCursor();
3460   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
3461   haveTmst       = QFile( tspath ).exists();
3462
3463   // Ok to reenable some buttons now
3464   enableControls();
3465}
3466
3467// Slot to handle a click to go to the previous record
3468void US_XpnDataViewer::prevPlot( void )
3469{
3470   int pltrx      = cb_pltrec->currentIndex() - 1;
3471
3472   if ( pltrx < 1 )
3473   {
3474      pltrx          = 0;
3475      pb_prev->setEnabled( false );
3476   }
3477
3478   QwtScaleDiv* sdx = AXISSCALEDIV( QwtPlot::xBottom );
3479   QwtScaleDiv* sdy = AXISSCALEDIV( QwtPlot::yLeft   );
3480   last_xmin      = sdx->lowerBound();
3481   last_xmax      = sdx->upperBound();
3482   last_ymin      = sdy->lowerBound();
3483   last_ymax      = sdy->upperBound();
3484
3485   cb_pltrec->setCurrentIndex( pltrx );
3486}
3487
3488// Slot to handle a click to go to the next record
3489void US_XpnDataViewer::nextPlot( void )
3490{
3491   int pltrx      = cb_pltrec->currentIndex() + 1;
3492   int nitems     = cb_pltrec->count();
3493
3494   if ( ( pltrx + 2 ) > nitems )
3495   {
3496      pltrx          = nitems - 1;
3497      pb_next->setEnabled( false );
3498   }
3499
3500   QwtScaleDiv* sdx = AXISSCALEDIV( QwtPlot::xBottom );
3501   QwtScaleDiv* sdy = AXISSCALEDIV( QwtPlot::yLeft   );
3502   last_xmin      = sdx->lowerBound();
3503   last_xmax      = sdx->upperBound();
3504   last_ymin      = sdy->lowerBound();
3505   last_ymax      = sdy->upperBound();
3506
3507   cb_pltrec->setCurrentIndex( pltrx );
3508}
3509
3510// Compute the plot range indexes implied by current settings
3511void US_XpnDataViewer::compute_ranges()
3512{
3513   if ( have_rngs )   // If we just did this computation, return now
3514      return;
3515
3516   ccx        = cb_cellchn->currentIndex();         // Cell/Channel index
3517   rad_start  = cb_rstart ->currentText().toDouble();  // Radius start
3518   rad_end    = cb_rend   ->currentText().toDouble();  // Radius end
3519   lmb_start  = lambdas[ 0 ];                       // Lambda start
3520   lmb_end    = lambdas[ nlambda - 1 ];             // Lambda end
3521   recx       = cb_pltrec ->currentIndex();         // Plot record index
3522   lmbxs      = lambdas.indexOf( lmb_start );       // Lambda start index
3523   lmbxe      = lambdas.indexOf( lmb_end   ) + 1;   // Lambda end index
3524   radxs      = dvec_index( r_radii, rad_start );     // Radius start index
3525   radxe      = dvec_index( r_radii, rad_end   ) + 1; // Radius end index
3526DbgLv(1) << "cmpR:  rS rE rxS rxE" << rad_start << rad_end << radxs << radxe;
3527DbgLv(1) << "cmpR:   rvS rvE" << r_radii[radxs] << r_radii[radxe-1];
3528   klambda    = lmbxe - lmbxs;                      // Count of plot lambdas
3529   kradii     = radxe - radxs;                      // Count of plot radii
3530   kscan      = nscan - excludes.size();            // Count included scans
3531   trpxs      = ccx * nlambda;                      // Start triple index
3532   kpoint     = kradii;                             // Count of plot points
3533   ktpoint    = kscan * kpoint;                     // Total plot data points
3534
3535   if ( isMWL )
3536   {
3537      trpxs     += recx;                            // Triple-to-plot index
3538   }
3539   else
3540   {
3541      trpxs      = recx;                            // Triple-to-plot index
3542   }
3543//   have_rngs  = true;                               // Mark ranges computed
3544DbgLv(1) << "cmpR:  isMWL" << isMWL << "kpoint" << kpoint << "trpxs" << trpxs;
3545}
3546
3547// Connect or Disconnect plot-range related controls
3548void US_XpnDataViewer::connect_ranges( bool conn )
3549{
3550   if ( conn )
3551   {  // Connect the range-related controls
3552      connect( cb_cellchn, SIGNAL( currentIndexChanged( int ) ),
3553               this,       SLOT  ( changeCellCh(            ) ) );
3554      connect( cb_rstart,  SIGNAL( currentIndexChanged( int ) ),
3555               this,       SLOT  ( changeRadius(            ) ) );
3556      connect( cb_rend,    SIGNAL( currentIndexChanged( int ) ),
3557               this,       SLOT  ( changeRadius(            ) ) );
3558      connect( cb_pltrec,  SIGNAL( currentIndexChanged( int ) ),
3559               this,       SLOT  ( changeRecord(            ) ) );
3560   }
3561
3562   else
3563   {  // Disconnect the range-related controls
3564      cb_cellchn->disconnect();
3565      cb_rstart ->disconnect();
3566      cb_rend   ->disconnect();
3567      cb_pltrec ->disconnect();
3568   }
3569}
3570
3571// export_auc data in us_com_project
3572void US_XpnDataViewer::export_auc_auto()
3573{
3574   correct_radii();      // Perform chromatic aberration radius corrections
3575
3576   int nfiles     = xpn_data->export_auc( allData );
3577//   int noptsy     = cb_optsys->children().count();
3578   int noptsy     = cb_optsys->count();
3579DbgLv(1) << "ExpAucA: noptsy koptsy" << noptsy << cb_optsys->children().count();
3580
3581   if ( noptsy > 1 )
3582   {  // Export data from Optical Systems other than currently selected one
3583      int currsx     = cb_optsys->currentIndex();
3584
3585      for ( int osx = 0; osx < noptsy; osx++ )
3586      {
3587         if ( osx == currsx )  continue;   // Skip already-handled opt sys
3588
3589         cb_optsys->setCurrentIndex( osx );
3590         correct_radii();                  // Chromatic aberration correction if needed
3591         int kfiles     = xpn_data->export_auc( allData ) - 2;  // Export data
3592         nfiles        += kfiles;          // Total files written
3593      }
3594
3595      // Restore Optical System selection to what it was before
3596      cb_optsys->setCurrentIndex( currsx );
3597   }
3598
3599   le_status  ->setText( tr( "%1 AUC/TMST files written ..." ).arg( nfiles ) );
3600   qApp->processEvents();
3601}
3602
3603// Slot to export to openAUC
3604void US_XpnDataViewer::export_auc()
3605{
3606   if ( !isRaw )
3607   {
3608      int status = QMessageBox::information( this, tr( "Data Overwrite Warning..." ),
3609               tr( "This operation will overwrite all data currently in"
3610                   "the same directory where these data were loaded from. Proceed? " ),
3611               tr( "&OK" ), tr( "&Cancel" ),
3612               0, 0, 1 );
3613      if ( status != 0 ) return;
3614   }
3615   QString runIDt = le_runID->text();              // User given run ID text
3616DbgLv(1) << "ExpAuc: runIDt" << runIDt;
3617DbgLv(1) << "ExpAuc: runID" << runID;
3618
3619   if ( runIDt != runID )
3620   {  // Set runID to new entry given by user
3621      QRegExp rx( "[^A-Za-z0-9_-]" );              // Possibly modify entry
3622      QString new_runID  = runIDt;
3623      int pos            = 0;
3624
3625      while ( ( pos = rx.indexIn( new_runID ) ) != -1 )
3626      {  // Loop thru any invalid characters given (not alphanum.,'_','-')
3627         new_runID.replace( pos, 1, "_" );         // Replace 1 char at pos
3628      }
3629
3630DbgLv(1) << "ExpAuc: new_runID len" << new_runID.length();
3631      if ( new_runID.length() > 60 )
3632      {
3633         new_runID          = QString( new_runID ).left( 52 )
3634                            + QString( new_runID ).right( 8 );
3635DbgLv(1) << "ExpAuc: corr new_runID len" << new_runID.length();
3636DbgLv(1) << "ExpAuc: new_runID" << new_runID;
3637      }
3638
3639      // Let the user know that the runID name has changed
3640      QMessageBox::warning( this,
3641         tr( "RunId Name Changed" ),
3642         tr( "The runId name has been changed."
3643             "\nNew runId:\n  " ) + new_runID );
3644
3645      runID          = new_runID;                  // Show new run ID, dir.
3646      le_runID->setText( runID );
3647      currentDir     = US_Settings::importDir() + "/" + runID;
3648      le_dir  ->setText( currentDir );
3649      qApp->processEvents();
3650
3651      xpn_data->set_run_values( runID, runType );  // Set run ID for export
3652   }
3653
3654   // Export the AUC data to a local directory and build TMST
3655DbgLv(1) << "ExpAuc: BEFORE correct_radii() !!!!";
3656   correct_radii();      // Perform chromatic aberration radius corrections
3657DbgLv(1) << "ExpAuc: AFTER correct_radii() !!!!";
3658   int nfiles     = xpn_data->export_auc( allData );  // Export AUC/TMST
3659
3660   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
3661   haveTmst       = QFile( tspath ).exists();
3662
3663   pb_showtmst->setEnabled( haveTmst );
3664   qApp->processEvents();
3665DbgLv(1) << "ExpAuc: haveTmst" << haveTmst << "tmst file" << tspath;
3666//   int noptsy     = cb_optsys->children().count();
3667   int noptsy     = cb_optsys->count();
3668DbgLv(1) << "ExpAucA: noptsy koptsy" << noptsy << cb_optsys->children().count();
3669
3670   qDebug() << "Optical Systems Count: (noptsy) = " << cb_optsys->children().count();
3671   
3672   if ( noptsy > 1 )
3673   {  // Export data from Optical Systems other than currently selected one
3674      int currsx     = cb_optsys->currentIndex();
3675
3676      for ( int osx = 0; osx < noptsy; osx++ )
3677      {
3678         if ( osx == currsx )  continue;   // Skip already-handled opt sys
3679
3680         cb_optsys->setCurrentIndex( osx );
3681         correct_radii();                  // Chromatic aberration correction if needed
3682         int kfiles     = xpn_data->export_auc( allData ) - 2;  // Export data
3683         nfiles        += kfiles;          // Total files written
3684      }
3685
3686      // Restore Optical System selection to what it was before
3687      cb_optsys->setCurrentIndex( currsx );
3688   }
3689
3690   le_status  ->setText( tr( "%1 AUC/TMST files written ..." ).arg( nfiles ) );
3691}
3692
3693// Slot to handle a change in scan exclude "from" value
3694void US_XpnDataViewer::exclude_from( double sfr )
3695{
3696   int scan_from  = (int)sfr;
3697   int scan_to    = (int)ct_to  ->value();
3698
3699   if ( scan_to < scan_from )
3700   {
3701      ct_to  ->disconnect();
3702      ct_to  ->setValue( scan_from );
3703
3704      connect( ct_to,        SIGNAL( valueChanged( double ) ),
3705               this,         SLOT  ( exclude_to  ( double ) ) );
3706   }
3707
3708   plot_current();
3709}
3710
3711// Slot to handle a change in scan exclude "to" value
3712void US_XpnDataViewer::exclude_to( double sto )
3713{
3714   int scan_to    = (int)sto;
3715   int scan_from  = (int)ct_from->value();
3716
3717   if ( scan_from > scan_to )
3718   {
3719      ct_from->disconnect();
3720      ct_from->setValue( scan_to );
3721
3722      connect( ct_from,      SIGNAL( valueChanged( double ) ),
3723               this,         SLOT  ( exclude_from( double ) ) );
3724   }
3725
3726   plot_current();
3727}
3728
3729// Slot to handle click of Exclude Scan Range
3730void US_XpnDataViewer::exclude_scans()
3731{
3732   int scan_from  = (int)ct_from->value();
3733   int scan_to    = (int)ct_to  ->value();
3734   int scan_knt   = 1;
3735
3736   for ( int scnx = 0; scnx < nscan; scnx++ )
3737   {
3738      if ( excludes.contains( scnx ) )  continue;
3739
3740      if ( scan_knt >= scan_from  &&  scan_knt <= scan_to )
3741         excludes << scnx;
3742
3743      scan_knt++;
3744   }
3745
3746   qSort( excludes );
3747   kscan      = nscan - excludes.count();
3748DbgLv(1) << "Excl: kscan" << kscan;
3749   ct_from   ->disconnect();
3750   ct_to     ->disconnect();
3751   ct_from   ->setMaximum( kscan );
3752   ct_to     ->setMaximum( kscan );
3753   connect( ct_from,      SIGNAL( valueChanged( double ) ),
3754            this,         SLOT  ( exclude_from( double ) ) );
3755   connect( ct_to,        SIGNAL( valueChanged( double ) ),
3756            this,         SLOT  ( exclude_to  ( double ) ) );
3757   ct_to     ->setValue( 0 );
3758   pb_include->setEnabled( true );
3759}
3760
3761// Slot to handle click of Include All (restore of all scans)
3762void US_XpnDataViewer::include_scans()
3763{
3764   excludes.clear();
3765
3766   kscan      = nscan;
3767   ktpoint    = kscan * kpoint;
3768DbgLv(1) << "Incl: nscan" << nscan << "kscn ecnt" << kscan << excludes.count();
3769   ct_to     ->setValue( 0 );
3770//   changeRecord();                     // Force replot
3771   plot_current();                     // Force replot
3772
3773   ct_from   ->disconnect();
3774   ct_to     ->disconnect();
3775   ct_from   ->setMaximum( kscan );
3776   ct_to     ->setMaximum( kscan );
3777   connect( ct_from,      SIGNAL( valueChanged( double ) ),
3778            this,         SLOT  ( exclude_from( double ) ) );
3779   connect( ct_to,        SIGNAL( valueChanged( double ) ),
3780            this,         SLOT  ( exclude_to  ( double ) ) );
3781   ct_to     ->setValue( 0 );
3782   pb_include->setEnabled( false );
3783}
3784
3785// Utility to find an index in a QVector<double> to a value epsilon match
3786int US_XpnDataViewer::dvec_index( QVector< double >& dvec, const double dval )
3787{
3788   const double eps = 1.e-4;
3789   double dmag     = qAbs( dval);
3790//DbgLv(1) << "dvix: dval dvknt" << dval << dvec.count();
3791
3792   int indx        = dvec.indexOf( dval );   // Try to find an exact match
3793//DbgLv(1) << "dvix: dvec0 dval indx" << dvec[0] << dval << indx;
3794
3795   if ( indx < 0 )
3796   {  // If no exact match was found, look for a match within epsilon
3797
3798      for ( int jj = 0; jj < dvec.size(); jj++ )
3799      {  // Search doubles vector
3800         double ddif     = qAbs( dvec[ jj ] - dval ) / dmag;
3801//if(jj<3||(jj+4)>dvec.size())
3802//DbgLv(1) << "dvix:   jj" << jj << "dvj" << dvec[jj] << "ddif" << ddif;
3803
3804         if ( ddif < eps )
3805         {  // If vector value matches within epsilon, break and return
3806            indx            = jj;
3807            break;
3808         }
3809      }
3810   }
3811
3812//DbgLv(1) << "dvix:   dval" << dval << "indx" << indx;
3813   return indx;
3814}
3815
3816// Slot to pop up dialog to plot TMST values
3817void US_XpnDataViewer::showTimeState()
3818{
3819   QString tspath = currentDir + "/" + runID + ".time_state.tmst";
3820   US_TmstPlot* tsdiag = new US_TmstPlot( this, tspath );
3821
3822DbgLv(1) << "sTS: tsdiag exec()";
3823   tsdiag->exec();
3824DbgLv(1) << "sTS: tsdiag DONE";
3825}
3826
3827// Slot to report updated status text
3828void US_XpnDataViewer::status_report( QString stat_text )
3829{
3830   qApp->processEvents();
3831
3832   le_status->setText( stat_text );
3833
3834   qApp->processEvents();
3835}
3836
3837// Slot to reload data
3838void US_XpnDataViewer::reloadData()
3839{
3840DbgLv(1) << "RLd:  in_reload" << in_reload;
3841   if ( in_reload )             // If already doing a reload,
3842      return;                   //  skip starting a new one
3843
3844   in_reload   = true;          // Flag in the midst of a reload
3845   int runix          = runID.lastIndexOf( "-run" ) + 4;
3846   QString fRunId     = runID.mid( runix );
3847   int iRunId         = fRunId.toInt();
3848DbgLv(1) << "RLd:  runID" << runID << "runix" << runix << "iRunId" << iRunId;
3849   int scanmask       = 1;
3850   scanmask           = ( runType == "FI" ) ? 2 : scanmask;
3851   scanmask           = ( runType == "IP" ) ? 4 : scanmask;
3852   scanmask           = ( runType == "WI" ) ? 8 : scanmask;
3853DbgLv(1) << "RLd:     iRunId" << iRunId << "runType scanmask" << runType << scanmask;
3854
3855QDateTime sttime=QDateTime::currentDateTime();
3856   QString smsg       = le_status->text();
3857   le_status->setText( tr( "Scanning Optima DB for any data updates..." ) );
3858   qApp->processEvents();
3859
3860   // Import any newly added Scan Data records
3861   bool upd_ok        =  xpn_data->reimport_data( iRunId, scanmask );
3862
3863   if ( ! upd_ok )
3864   {  // No change in data scans:  report inability to update
3865      nscan       = allData[ trpxs ].scanCount();
3866DbgLv(1) << "RLd:      upd_ok" << upd_ok << "rlt_id" << rlt_id << "nscan" << nscan;
3867      if ( rlt_id == 0 )    // Output message only if not auto-reload
3868      {
3869         QMessageBox::warning( this,
3870               tr( "Reload Data Not Possible" ),
3871               tr( "The \"Reload Data\" action had no effect.\n"
3872                   "No additional data has been recorded." ) );
3873      }
3874
3875      if ( ! smsg.endsWith( tr( " scans)" ) ) )
3876      {  // If need be, add scan count to the status message
3877         smsg        = smsg + tr( "  (%1 scans)" ).arg( nscan );
3878         le_status->setText( smsg );
3879        qApp->processEvents();
3880      }
3881DbgLv(1) << "RLd:       NO CHANGE";
3882      in_reload   = false;         // Flag no longer in the midst of reload
3883      return;     // Return with no change in AUC data
3884   }
3885double tm1=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
3886
3887   // Otherwise, report updated raw data import
3888   le_status->setText( tr( "Update of Raw Optima data import complete." ) );
3889   qApp->processEvents();
3890
3891   // Now, update the AUC data with new scans
3892DbgLv(1) << "RLd:      build-raw started: tm1" << tm1;
3893   xpn_data->rebuild_rawData( allData );
3894
3895double tm2=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
3896DbgLv(1) << "RLd:      build-raw done: tm1 tm2" << tm1 << tm2
3897 << "tm2i" << (tm2-tm1);
3898   // Reset scan counter maximum and report update complete
3899   nscan       = allData[ trpxs ].scanCount();
3900   npoint      = allData[ trpxs ].pointCount();
3901   ntpoint     = nscan * npoint;
3902   ct_from->setMaximum( nscan );
3903   ct_to  ->setMaximum( nscan );
3904   le_status->setText( tr( "Update of AUC data complete -- now %1 scans." )
3905                       .arg( nscan ) );
3906   qApp->processEvents();
3907
3908   // Do resets and re-plot the current triple
3909   changeCellCh();
3910   in_reload   = false;         // Flag no longer in the midst of reload
3911}
3912
3913
3914int US_XpnDataViewer::CheckExpComplete_auto( QString & runid )
3915{
3916  // Implement Optima's ExperimentRun query for RunStatus field [enum: 0 - NoRunInfo; 2- InProgress; 5- CompleteOK], look in db_defines.h of Dennis's util
3917  // in utils/us_xpn_data.cpp
3918  int exp_status =  xpn_data->checkExpStatus( runid );
3919
3920  return exp_status;
3921}
3922
3923// Slot to reload data
3924void US_XpnDataViewer::reloadData_auto()
3925{
3926   if ( in_reload_auto )            // If already doing a reload,
3927     return;                   //  skip starting a new one
3928
3929   in_reload_auto   = true;          // Flag in the midst of a reload
3930
3931   int runix          = runID.lastIndexOf( "-run" ) + 4;
3932   QString fRunId     = runID.mid( runix );
3933   int iRunId         = fRunId.toInt();
3934DbgLv(1) << "RLd:  runID" << runID << "runix" << runix << "iRunId" << iRunId;
3935   int scanmask       = 1;
3936   scanmask           = ( runType == "FI" ) ? 2 : scanmask;
3937   scanmask           = ( runType == "IP" ) ? 4 : scanmask;
3938   scanmask           = ( runType == "WI" ) ? 8 : scanmask;
3939DbgLv(1) << "RLd:     iRunId" << iRunId << "runType scanmask" << runType << scanmask;
3940
3941QDateTime sttime=QDateTime::currentDateTime();
3942   QString smsg       = le_status->text();
3943   le_status->setText( tr( "Scanning Optima DB for any data updates..." ) );
3944   qApp->processEvents();
3945
3946   // Import any newly added Scan Data records
3947   bool upd_ok        =  xpn_data->reimport_data( iRunId, scanmask );
3948
3949   if ( ! upd_ok )
3950   {  // No change in data scans:  report inability to update
3951      nscan       = allData[ trpxs ].scanCount();
3952
3953      if ( ! smsg.endsWith( tr( " scans)" ) ) )
3954      {  // If need be, add scan count to the status message
3955         smsg        = smsg + tr( "  (%1 scans)" ).arg( nscan );
3956         le_status->setText( smsg );
3957        qApp->processEvents();
3958      }
3959DbgLv(1) << "RLd:       NO CHANGE";
3960
3961      /*** Check Experiement Status: if completed, kill the timer, export the data into AUC format, return, signal to switch panels in US_comproject ***/
3962      int statusExp = CheckExpComplete_auto( RunID_to_retrieve  );
3963
3964      if ( statusExp == 55 || statusExp == 10 )
3965  {
3966    if ( statusExp == 0 )
3967      experimentAborted  = true;
3968   
3969    timer_data_reload->stop();
3970    disconnect(timer_data_reload, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
3971
3972    qDebug() << "STOPPING timer_data_reload...";
3973
3974    if ( !timer_check_sysdata->isActive()  ) // Check if sys_data Timer is stopped
3975      {
3976
3977        qDebug() << "Exporing/Writing to disk...";
3978        // ALEXEY Export AUC data: devise export_auc_auto() function which would return directory name with saved data - to pass to emit signal below...
3979        export_auc_auto();
3980   
3981        // QString mtitle_complete  = tr( "Complete!" );
3982        // QString message_done     = tr( "Experiment was completed. Optima data saved..." );
3983        // QMessageBox::information( this, mtitle_complete, message_done );
3984
3985        updateautoflow_record_atLiveUpdate();
3986
3987        reset_auto();
3988
3989        in_reload_auto   = false;
3990               
3991        //emit experiment_complete_auto( currentDir, ProtocolName, invID_passed, correctRadii  );  // Updtade later: what should be passed with signal ??
3992        emit experiment_complete_auto( details_at_live_update );
3993       
3994        return;
3995      }
3996  }
3997
3998     
3999   
4000       in_reload_auto   = false;         // Flag no longer in the midst of reload
4001       
4002       qDebug() << "Exit from reloaData with no change!";
4003       
4004       return;     // Return with no change in AUC data
4005   }
4006double tm1=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
4007
4008   // Otherwise, report updated raw data import
4009   le_status->setText( tr( "Update of Raw Optima data import complete." ) );
4010   qApp->processEvents();
4011
4012   // Now, update the AUC data with new scans
4013DbgLv(1) << "RLd:      build-raw started: tm1" << tm1;
4014   xpn_data->rebuild_rawData( allData );
4015
4016double tm2=(double)sttime.msecsTo(QDateTime::currentDateTime())/1000.0;
4017DbgLv(1) << "RLd:      build-raw done: tm1 tm2" << tm1 << tm2
4018 << "tm2i" << (tm2-tm1);
4019   // Reset scan counter maximum and report update complete
4020   nscan       = allData[ trpxs ].scanCount();
4021   npoint      = allData[ trpxs ].pointCount();
4022   ntpoint     = nscan * npoint;
4023   ct_from->setMaximum( nscan );
4024   ct_to  ->setMaximum( nscan );
4025   le_status->setText( tr( "Update of AUC data complete -- now %1 scans." )
4026                       .arg( nscan ) );
4027   qApp->processEvents();
4028
4029   // Do resets and re-plot the current triple
4030   changeCellCh();
4031
4032   in_reload_auto   = false;         // Flag no longer in the midst of reload
4033   
4034   qDebug() << "Exit from reloaData with SOME change!";
4035}
4036
4037
4038// Slot to respond to a timer event (auto-reload)
4039void US_XpnDataViewer::timerEvent( QTimerEvent *event )
4040{
4041   int tim_id  = event->timerId();
4042DbgLv(1) << "            timerEvent:   tim_id" << tim_id << "    "
4043 << QDateTime::currentDateTime().toString( "hh:mm:ss" )
4044 << "  rlt_id" << rlt_id;
4045
4046   if ( tim_id != rlt_id )
4047   {  // if other than auto-reload event, pass on to normal handler
4048      QWidget::timerEvent( event );
4049      return;
4050   }
4051
4052   // Do a reload of data (if none currently underway)
4053   reloadData();
4054}
4055
4056// Slot to handle change in auto-reload check
4057void US_XpnDataViewer::changeReload()
4058{
4059DbgLv(1) << "chgRld: checked" << ck_autorld->isChecked();
4060   if ( ck_autorld->isChecked() )
4061   {  // Changing to checked:  start the timer
4062      data_plot->replot();
4063
4064      rlt_dlay    = qRound( ct_rinterv->value() * 1000.0 );
4065      rlt_id      = startTimer( rlt_dlay );
4066DbgLv(1) << "chgRld:  rlt_dlay" << rlt_dlay << "rlt_id" << rlt_id;
4067   }
4068
4069   else
4070   {  // Just been unchecked:  stop the timer if need be
4071DbgLv(1) << "chgRld:  rlt_id" << rlt_id;
4072      if ( rlt_id != 0 )
4073      {
4074         killTimer( rlt_id );
4075DbgLv(1) << "chgRld:    STOPPED";
4076      }
4077      rlt_id      = 0;
4078      in_reload   = false;
4079   }
4080}
4081
4082// Slot to handle change in auto-reload interval
4083void US_XpnDataViewer::changeInterval()
4084{
4085DbgLv(1) << "chgInt: checked" << ck_autorld->isChecked();
4086   if ( ! ck_autorld->isChecked() )
4087   {  // If no auto reload checked, ignore this interval change for now
4088      rlt_id      = 0;
4089      return;
4090   }
4091
4092DbgLv(1) << "chgInt:  rlt_id" << rlt_id << "newInt" << ct_rinterv->value()
4093 << "    " << QDateTime::currentDateTime().toString( "hh:mm:ss" );
4094   // Otherwise, stop the timer and then restart it with a new delay
4095   if ( rlt_id != 0 )
4096   {
4097      killTimer( rlt_id );
4098   }
4099
4100   changeReload();
4101}
4102
4103// Slot to use a file dialog to select a new scan curve color map
4104void US_XpnDataViewer::selectColorMap()
4105{
4106   QString cmapname( "cm-rainbow" );
4107   QString filter  = tr( "Color Map files (*cm-*.xml);;"
4108                         "Any XML files (*.xml);;"
4109                         "Any files (*)" );
4110
4111   // get an xml file name for the color map
4112   QString cmfpath = QFileDialog::getOpenFileName( this,
4113       tr( "Load Color Map File" ),
4114       US_Settings::etcDir(), filter, 0, 0 );
4115
4116   if ( cmfpath.isEmpty() )
4117        return;
4118
4119DbgLv(1) << "sCM: cmfpath" << cmfpath;
4120   US_ColorGradIO::read_color_gradient( cmfpath, mcolors );
4121   mcknt           = mcolors.count();
4122DbgLv(1) << "sCM: mcolors count" << mcknt;
4123   cmapname        = QFileInfo( cmfpath ).baseName().replace( ".xml$", "" );
4124   le_colmap->setText( cmapname );
4125
4126   if ( allData.size() > 0 )
4127      plot_all();
4128}
4129
4130
4131// Apply a chromatic aberration correction to auc data radius values <--- New function: uses lambdas/corr. from DB
4132void US_XpnDataViewer::correct_radii()
4133{
4134   const double rad_inc = 1e-5;     // Radius precision
4135
4136   char wktyp[ 3 ];
4137   strncpy( wktyp, allData[ 0 ].type, 2 );
4138   wktyp[ 2 ] = '\0';
4139   QString dtype = QString( wktyp );
4140DbgLv(1) << "CR: dtype" << dtype << wktyp;
4141   if ( dtype == "IP" )
4142   {
4143DbgLv(0) << "NO Chromatic Aberration correction for Interference data";
4144      return;     // No correction for Interference data
4145   }
4146
4147   int ntripl = allData.count();
4148   int npoint = allData[ 0 ].pointCount();
4149   double radval;
4150   QString fline;
4151   QVector <double> lambda;
4152   QVector <double> correction;
4153   lambda.clear();
4154   correction.clear();
4155
4156   QString chromoArrayString;
4157   QStringList strl;
4158
4159   chromoArrayString = currentInstrument["chromoab"].trimmed();  //<--- From DB
4160
4161   if ( !chromoArrayString.isEmpty() )
4162     {
4163       strl = chromoArrayString.split(QRegExp("[\r\n\t ]+"));
4164       
4165       foreach (QString str, strl)
4166   {
4167     str.remove("(");
4168     str.remove(")");
4169     
4170     lambda.push_back( double( str.split(",")[0].trimmed().toFloat() ) );
4171     correction.push_back( double( str.split(",")[1].trimmed().toFloat() ) );
4172     
4173     qDebug() << str.split(",")[0].trimmed() << " " << str.split(",")[1].trimmed();
4174   }
4175     }
4176   // a correction was found
4177   if (correction.size() > 0)
4178   {
4179     if ( !auto_mode_bool  )
4180       {
4181      int response=QMessageBox::question( this,
4182             tr( "Chromatic Aberration Correction:" ),
4183             tr( "Wavelength correction data for currently used Optima machine\n"
4184           "are found in DB and will be used to correct your data for\n"
4185           "chromatic aberration between 190 nm and 800 nm.\n\n"
4186           "Exported data will be modified!\n") );
4187      if (response == QMessageBox::No) return;
4188       }
4189      DbgLv(1) << "go ahead and correct..."; 
4190      // For each triple, get the wavelength; then compute and apply a correction
4191      for ( int jd = 0; jd < ntripl; jd++ )
4192      {
4193         int i=0;
4194         while ((int) lambda.at(i) != (int) allData[ jd ].scanData[ 0 ].wavelength)
4195         {
4196            i++; // Wavelength index
4197            if (i > 610) break;
4198            if (correction.at(i)  != 0.0 )
4199            {
4200               for ( int jr = 0; jr < npoint; jr++ )
4201               {  // Correct each radial point
4202                  radval = r_radii[ jr ] - correction.at(i);     // Corrected radius
4203                  radval = qRound( radval / rad_inc ) * rad_inc; // Rounded
4204                  allData[ jd ].xvalues[ jr ] = radval;          // Replace radius
4205               }
4206            }
4207         }
4208   if (jd<3 || (jd+4)>ntripl )
4209     DbgLv(1) << "c_r:  ri0 ro0" << r_radii[0] << allData[jd].xvalues[0]
4210        << "rin ron" << r_radii[npoint-1] << allData[jd].xvalues[npoint-1];
4211      }
4212   }
4213   else // No chromatic abberation in instrument's table
4214     {
4215       if ( auto_mode_bool  )
4216   {
4217     correctRadii = QString("NO");
4218   }
4219     }
4220}
4221
4222
4223/*
4224// Apply a chromatic aberration correction to auc data radius values       <--- OLD function
4225void US_XpnDataViewer::correct_radii()
4226{
4227   const double rad_inc = 1e-5;     // Radius precision
4228   int ntripl = allData.count();
4229   int npoint = allData[ 0 ].pointCount();
4230   double radval;
4231   QString fline;
4232   QVector <double> lambda;
4233   QVector <double> correction;
4234   lambda.clear();
4235   correction.clear();
4236
4237   // If coefficient values are in an etc file, use them
4238   QString cofname = US_Settings::etcDir() + "/chromo-aberration-array.dat";
4239   QFile cofile( cofname );
4240
4241   if ( cofile.open( QIODevice::ReadOnly | QIODevice::Text ) )
4242   {
4243      int i=190;
4244      QTextStream cotxti( &cofile );
4245      while ( ! cotxti.atEnd() )
4246      {
4247         fline = cotxti.readLine().simplified();
4248         if ( ! fline.isEmpty()  &&  ! fline.startsWith( "#" ) )
4249         {  // Get values from first non-empty, non-comment line
4250            // make sure there is one entry for each wavelength
4251            if (i == fline.section( " ", 0, 0 ).simplified().toInt())
4252            {
4253               lambda.push_back((double) i);
4254               correction.push_back(fline.section( " ", 1, 1 ).simplified().toDouble());
4255            }
4256            i++;
4257         }
4258      }
4259      cofile.close();
4260      if (i != 801)
4261      {
4262         correction.clear(); // delete any entries, invalid interpolation.
4263         lambda.clear();
4264         QMessageBox::warning( this,
4265            tr( "Incorrect File Format..." ),
4266            tr( "The wavelength correction file:\n") +
4267                US_Settings::etcDir() + "/chromo-aberration-array.dat\n" +
4268            tr( "is incorrectly formatted or contains invalid data.\n"
4269                "Exported data will not be corrected for any chromatic\n"
4270                "aberration." ) );
4271      }
4272      else
4273      {
4274         QMessageBox::warning( this,
4275            tr( "Chromatic Aberration Correction:" ),
4276            tr( "The wavelength correction file:\n") +
4277                US_Settings::etcDir() + "/chromo-aberration-array.dat\n" +
4278            tr( "is found and will be used to correct your data for chromatic\n"
4279                "aberration between 190 nm and 800 nm. Exported data will be modified.\n") );
4280      }
4281   }
4282   else
4283   {
4284      // only use chromo-aberration-coeffs.dat if chromo-aberration-array.dat isn't available
4285      cofname = US_Settings::etcDir() + "/chromo-aberration-coeffs.dat";
4286      cofile.setFileName( cofname );
4287
4288      if ( cofile.open( QIODevice::ReadOnly | QIODevice::Text ) )
4289      {
4290         double a_coef  = 0.0;         // Default 5th order polynomial coefficents
4291         double b1_coef = 0.0;     
4292         double b2_coef = 0.0;
4293         double b3_coef = 0.0;
4294         double b4_coef = 0.0;
4295         double b5_coef = 0.0;
4296         QTextStream cotxti( &cofile );
4297         while ( ! cotxti.atEnd() )
4298         {
4299            fline = cotxti.readLine().simplified();
4300            if ( ! fline.isEmpty()  &&  ! fline.startsWith( "#" ) )
4301            {  // Get values from first non-empty, non-comment line
4302               a_coef  = QString( fline ).section( " ", 0, 0 )
4303                         .simplified().toDouble();
4304               b1_coef = QString( fline ).section( " ", 1, 1 )
4305                         .simplified().toDouble();
4306               b2_coef = QString( fline ).section( " ", 2, 2 )
4307                         .simplified().toDouble();
4308               b3_coef = QString( fline ).section( " ", 3, 3 )
4309                         .simplified().toDouble();
4310               b4_coef = QString( fline ).section( " ", 4, 4 )
4311                         .simplified().toDouble();
4312               b5_coef = QString( fline ).section( " ", 5, 5 )
4313                         .simplified().toDouble();
4314               break;
4315            }
4316         }
4317         cofile.close();
4318         double wl_p2, wl_p3, wl_p4, wl_p5, corr;
4319         for (int i=190; i<801; i++)
4320         {
4321            lambda.push_back((double) i);
4322            wl_p2  =      sq((double) i);      // Squared
4323            wl_p3  = wl_p2 * (double) i;       // Cubed
4324            wl_p4  = wl_p2 * wl_p2;            // To 4th power
4325            wl_p5  = wl_p3 * wl_p2;            // To 5th power
4326
4327            // Wavelength-dependent correction
4328            corr = a_coef + (double) i * b1_coef
4329                          + wl_p2      * b2_coef
4330                          + wl_p3      * b3_coef
4331                          + wl_p4      * b4_coef
4332                          + wl_p5      * b5_coef;
4333            correction.push_back(corr);
4334         }
4335            QMessageBox::warning( this,
4336            tr( "Chromatic Aberration Correction:" ),
4337            tr( "The wavelength correction file:\n") +
4338                US_Settings::etcDir() + "/chromo-aberration-coeffs.dat\n" +
4339            tr( "is found and will be used to correct your data for chromatic aberration\n"
4340                "between 190 nm and 800 nm. Exported data will be modified.\n") );
4341      }
4342   }
4343   // a correction was found
4344   if (correction.size() > 0)
4345   {
4346      // For each triple, get the wavelength; then compute and apply a correction
4347      for ( int jd = 0; jd < ntripl; jd++ )
4348      {
4349         int i=0;
4350         while ((int) lambda.at(i) != (int) allData[ jd ].scanData[ 0 ].wavelength)
4351         {
4352            i++; // Wavelength index
4353            if (i > 610) break;
4354            if (correction.at(i)  != 0.0 )
4355            {
4356               for ( int jr = 0; jr < npoint; jr++ )
4357               {  // Correct each radial point
4358                  radval = r_radii[ jr ] - correction.at(i);     // Corrected radius
4359                  radval = qRound( radval / rad_inc ) * rad_inc; // Rounded
4360                  allData[ jd ].xvalues[ jr ] = radval;          // Replace radius
4361               }
4362            }
4363         }
4364if (jd<3 || (jd+4)>ntripl )
4365DbgLv(1) << "c_r:  ri0 ro0" << r_radii[0] << allData[jd].xvalues[0]
4366 << "rin ron" << r_radii[npoint-1] << allData[jd].xvalues[npoint-1];
4367      }
4368   }
4369}
4370*/
4371
4372
4373
4374// Capture X range of latest Zoom
4375void US_XpnDataViewer::currentRectf( QRectF rectf )
4376{
4377   QVector< double >  ascdat;
4378   QVector< int > srpms;
4379   QVector< int > ssfscs;
4380   QVector< int > sslscs;
4381   double radv1     = qRound( rectf.left()  * 10000.0 ) * 0.0001;
4382   double radv2     = qRound( rectf.right() * 10000.0 ) * 0.0001;
4383   if ( radv2 > 7.0 )
4384      return;           // Skip further processing if not reasonable zoom
4385   int irx1         = 0;
4386   int irx2         = 0;
4387   double kpoint    = 0;
4388   QString cellch   = cb_cellchn ->currentText();
4389   QString cech     = QString( cellch ).replace( " / ", "" );
4390
4391   QString impath   = US_Settings::importDir() + "/" + runID;
4392   QDir dir;
4393   if ( ! dir.exists( impath ) )
4394      dir.mkpath( impath );
4395   QString dapath   = impath + "/" + cech + ".wavelen.radpos.dat";
4396   QFile dafile( dapath );
4397   if ( !dafile.open( QIODevice::WriteOnly | QIODevice::Text ) )
4398   {
4399      return;
4400   }
4401   QTextStream datxto( &dafile );
4402
4403   QString msg      = tr( "%1, %2-to-%3 Radial adjustment scan..." )
4404                      .arg( cellch ).arg( radv1 ).arg( radv2 );
4405   le_status->setText( msg );
4406   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
4407   qApp->processEvents();
4408DbgLv(1) << "cRect" << msg;
4409   datxto << "Wavelength,Meniscus\n";
4410
4411   // Determine meniscus position for each wavelength of this channel
4412   for ( int jd = 0; jd < allData.count(); jd++ )
4413   {
4414      US_DataIO::RawData *rdata = &allData[ jd ];
4415
4416      QString dchann    = QString::number( rdata->cell )
4417                          + QString( rdata->channel );
4418      if ( dchann != cech )
4419         continue;
4420
4421      if ( irx2 == 0 )
4422      {  // Get radial range indexes
4423         irx1             = US_DataIO::index( rdata, radv1 );
4424         irx2             = US_DataIO::index( rdata, radv2 );
4425         kpoint           = irx2 - irx1 + 1;
4426      }
4427
4428      double wavelen    = rdata->scanData[ 0 ].wavelength; // Wavelength
4429
4430      // Create an average scan value vector for the search range
4431      int nscan         = rdata->scanCount();
4432      double afact      = 1.0 / (double)nscan;
4433      ascdat.fill( 0.0, kpoint );
4434
4435      for ( int js = 0; js < nscan; js++ )
4436      {
4437         US_DataIO::Scan* dscan = &rdata->scanData[ js ];
4438
4439         // Save unique speeds and each one's scan start,end indecies
4440         int ssrpm         = (int)qRound( dscan->rpm * 0.01 ) * 100;
4441         int ssx           = srpms.indexOf( ssrpm );
4442         if ( ssx >= 0 )
4443         {
4444            sslscs[ ssx ]     = js;
4445         }
4446         else
4447         {
4448            srpms  << ssrpm;
4449            ssfscs << js;
4450            sslscs << js;
4451         }
4452
4453         // Accumulate average scan for the current channel
4454         for ( int jr = 0; jr < kpoint; jr++ )
4455         {
4456            ascdat[ jr ] += dscan->rvalues[ jr + irx1 ] * afact;
4457         }
4458      }
4459
4460      // Find the position of the minimum average-scan value in the range
4461      double rvmin      = 1.0e+99;
4462      int irpos         = -1;
4463      for ( int jr = 0; jr < kpoint; jr++ )
4464      {
4465         double rval       = ascdat[ jr ];
4466         if ( rval < rvmin )
4467         {
4468            rvmin             = rval;
4469            irpos             = jr;
4470         }
4471      }
4472
4473      // Meniscus radius value for the wavelength
4474      double radiusw    = rdata->xvalues[ irpos + irx1 ];
4475DbgLv(1) << "  wavelen/radpos:  " << wavelen << " / " << radiusw;
4476
4477      // Output a wavelength,radial-position line
4478      QString outline   = QString::number( wavelen ) + ","
4479                        + QString::number( radiusw ) + "\n";
4480      datxto << outline;
4481   }  // END: datasets loop
4482   dafile.close();
4483
4484   int nspeed        = srpms.count();
4485
4486   if ( nspeed > 1 )
4487   {  // If multi-speed, add search/output as "wavelen/speed/radpos"
4488      QString dapath    = impath + "/" + cech + ".wavelen.speeds-meniscus.dat";
4489      QFile dafile( dapath );
4490      dafile.open( QIODevice::WriteOnly | QIODevice::Text );
4491      QTextStream datxto( &dafile );
4492      QString outline   = tr( "Wavelength" );
4493      for ( int jq = 0; jq < nspeed; jq++ )
4494      {  // Add speeds to header line
4495         int irpm          = srpms[ jq ];
4496         outline          += "," + QString::number( irpm );
4497      }
4498      outline          += "\n";
4499      datxto << outline;
4500      for ( int jd = 0; jd < allData.count(); jd++ )
4501      {  // Get information for each dataset
4502         US_DataIO::RawData *rdata = &allData[ jd ];
4503
4504         QString dchann    = QString::number( rdata->cell )
4505                             + QString( rdata->channel );
4506         if ( dchann != cech )
4507            continue;
4508
4509         if ( irx2 == 0 )
4510         {  // Get radial range indexes
4511            irx1             = US_DataIO::index( rdata, radv1 );
4512            irx2             = US_DataIO::index( rdata, radv2 );
4513            kpoint           = irx2 - irx1 + 1;
4514         }
4515
4516         double wavelen    = rdata->scanData[ 0 ].wavelength; // Wavelength
4517         // Start data line with wavelength value
4518         outline           = QString::number( wavelen );
4519
4520         for ( int jq = 0; jq < nspeed; jq++ )
4521         {
4522            // Create an average scan value vector for the search range
4523            int irpm          = srpms [ jq ];
4524            int jsf           = ssfscs[ jq ];
4525            int jsl           = sslscs[ jq ] + 1;
4526            int nscan         = jsl - jsf;
4527            double afact      = 1.0 / (double)nscan;
4528            ascdat.fill( 0.0, kpoint );
4529            for ( int js = jsf; js < jsl; js++ )
4530            {  // Average scans in the current speed step
4531               US_DataIO::Scan* dscan = &rdata->scanData[ js ];
4532
4533               for ( int jr = 0; jr < kpoint; jr++ )
4534               {
4535                  ascdat[ jr ] += dscan->rvalues[ jr + irx1 ] * afact;
4536               }
4537            }
4538
4539            // Find the position of the minimum value in the range
4540            double rvmin      = 1.0e+99;
4541            int irpos         = -1;
4542            for ( int jr = 0; jr < kpoint; jr++ )
4543            {
4544               double rval       = ascdat[ jr ];
4545               if ( rval < rvmin )
4546               {
4547                  rvmin             = rval;
4548                  irpos             = jr;
4549               }
4550            }
4551
4552            double radiusw    = rdata->xvalues[ irpos + irx1 ];
4553DbgLv(1) << "  wavelen/speed/radpos:  " << wavelen
4554   << " / " << irpm << " / " << radiusw;
4555
4556            outline          += "," + QString::number( radiusw );
4557         }  // END: speed loop
4558         outline          += "\n";
4559         datxto << outline;
4560      }  // END: dataset loop
4561
4562      dafile.close();
4563   }  // END: multi-speed
4564
4565   le_status->setText( tr( "%1  Radial adjustment scan complete." )
4566                      .arg( cech ) );
4567   QApplication::restoreOverrideCursor();
4568   qApp->processEvents();
4569}
4570
Note: See TracBrowser for help on using the repository browser.