[us-commits] r2741 - in trunk: programs/us_com_project programs/us_convert programs/us_experiment programs/us_xpn_viewer sql utils

svn at svn.aucsolutions.com svn at svn.aucsolutions.com
Sat Apr 27 03:50:17 MDT 2019


Author: alexey
Date: 2019-04-27 09:50:16 +0000 (Sat, 27 Apr 2019)
New Revision: 2741

Added:
   trunk/sql/us3_autoflow_procs.sql
Modified:
   trunk/programs/us_com_project/us_com_project_gui.cpp
   trunk/programs/us_com_project/us_com_project_gui.h
   trunk/programs/us_convert/us_convert_gui.cpp
   trunk/programs/us_convert/us_convert_gui.h
   trunk/programs/us_convert/us_experiment.cpp
   trunk/programs/us_convert/us_experiment.h
   trunk/programs/us_experiment/us_experiment_gui_optima.cpp
   trunk/programs/us_experiment/us_experiment_gui_optima.h
   trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.cpp
   trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.h
   trunk/sql/us3.sql
   trunk/utils/us_db2.h
   trunk/utils/us_protocol_util.cpp
   trunk/utils/us_protocol_util.h
Log:
First hit on job reattachement for us_Comproject/data_aqcuisition
Limited test and appl. to uslims3_CCH



Modified: trunk/programs/us_com_project/us_com_project_gui.cpp
===================================================================
--- trunk/programs/us_com_project/us_com_project_gui.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_com_project/us_com_project_gui.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -13,6 +13,7 @@
 #include "us_crypto.h"
 #include "us_select_item.h"
 #include "us_images.h"
+#include "us_select_item.h"
 
 #if QT_VERSION < 0x050000
 #define setSamples(a,b,c)  setData(a,b,c)
@@ -142,8 +143,8 @@
    connect( epanExp, SIGNAL( switch_to_live_update( QMap < QString, QString > &) ), this, SLOT( switch_to_live_update( QMap < QString, QString > & )  ) );
    connect( this   , SIGNAL( pass_to_live_update( QMap < QString, QString > &) ),   epanObserv, SLOT( process_protocol_details( QMap < QString, QString > & )  ) );
 
-   connect( epanObserv, SIGNAL( switch_to_post_processing( QString &, QString &) ), this, SLOT( switch_to_post_processing( QString &, QString & )  ) );
-   connect( this, SIGNAL( import_data_us_convert( QString &, QString & ) ),  epanPostProd, SLOT( import_data_us_convert( QString &, QString & )  ) );
+   connect( epanObserv, SIGNAL( switch_to_post_processing( QString &, QString &, QString &) ), this, SLOT( switch_to_post_processing( QString &, QString &, QString &) ) );
+   connect( this, SIGNAL( import_data_us_convert( QString &, QString &, QString & ) ),  epanPostProd, SLOT( import_data_us_convert( QString &, QString &, QString & )  ) );
    connect( epanObserv, SIGNAL( switch_to_experiment( QString &) ), this, SLOT( switch_to_experiment(  QString & )  ) );
    connect( this, SIGNAL( clear_experiment( QString & ) ),  epanExp, SLOT( clear_experiment( QString & )  ) );
 
@@ -156,7 +157,7 @@
    adjustSize();
 
    /* Check for current stage & redirect to specific tab */
-   //check_current_stage();
+   check_current_stage();
 
 }
 
@@ -272,8 +273,8 @@
    connect( epanExp, SIGNAL( switch_to_live_update( QMap < QString, QString > &) ), this, SLOT( switch_to_live_update( QMap < QString, QString > & )  ) );
    connect( this   , SIGNAL( pass_to_live_update( QMap < QString, QString > &) ),   epanObserv, SLOT( process_protocol_details( QMap < QString, QString > & )  ) );
 
-   connect( epanObserv, SIGNAL( switch_to_post_processing( QString &, QString &) ), this, SLOT( switch_to_post_processing( QString &, QString & )  ) );
-   connect( this, SIGNAL( import_data_us_convert( QString &, QString & ) ),  epanPostProd, SLOT( import_data_us_convert( QString &, QString & )  ) );
+   connect( epanObserv, SIGNAL( switch_to_post_processing( QString &, QString &, QString & ) ), this, SLOT( switch_to_post_processing( QString &, QString &, QString & )));
+   connect( this, SIGNAL( import_data_us_convert( QString &, QString &, QString & ) ),  epanPostProd, SLOT( import_data_us_convert( QString &, QString &, QString & )  ) );
    connect( epanObserv, SIGNAL( switch_to_experiment( QString &) ), this, SLOT( switch_to_experiment(  QString & )  ) );
    connect( this, SIGNAL( clear_experiment( QString & ) ),  epanExp, SLOT( clear_experiment( QString & )  ) );
    
@@ -284,11 +285,12 @@
    adjustSize();
 
    /* Check for current stage & redirect to specific tab */
-   //check_current_stage();
-
+   check_current_stage();
+   
+   //connect( epanExp, SIGNAL( check_stage() ), this, SLOT( check_current_stage()  ) );
+   //emit check_stage();
 }
 
-
 // Function that checks for current program stage based on US-lims DB entry
 void US_ComProjectMain::check_current_stage( void )
 {
@@ -298,46 +300,247 @@
   // (3) Identify currDir where .auc data have been saved (unique name based on protocolName + runID)
   //     * this maybe an 'autoflow' table field recorded after stage 1 (Live Update); DEFAULT empty
 
-  /* 
-  QString currDir = QString("");
+  /*
+ 
+    1. Query 'autoflow' table - proc. 'count_autoflow_records()': 
+            if 0 - return; 
+	    else
+	       sort by OptimaName:
+	       list active Optima machines:
+	       identify which Optima is running via autoflow, which is free & offer to chose - either monitor existing run, OR submit new run on free machine
+	       When to consider Optima "free" ? (after stage 'LIVE_UPDATE' passed ?)
+    
+    2. If autoflow record exists: 
+             proc. 'read_autoflow_record()'
+  
+  */
 
-  currDir = curDirr_query.isEmprty() ? curDir : curDirr_query; 
+  // // Ling's exp. Optima 1!!!
+  // QMap < QString, QString > protocol_details;
+  // protocol_details[ "experimentId" ]   = QString("465");   
+  // protocol_details[ "protocolName" ]   = QString("CCLing-PZ5077-27k-021519");
+  // protocol_details[ "experimentName" ] = QString("some_name");
+  // protocol_details[ "CellChNumber" ]   = QString("2");
+  // protocol_details[ "TripleNumber" ]   = QString("2");
+  // protocol_details[ "OptimaName" ]     = QString("Optima 1");    // <-- Optima 1
+  // protocol_details[ "duration" ]       = QString("27000");
+  // protocol_details[ "invID_passed" ]   = QString("34"); //Ling's ID
   
+  // -------------------------------------------------------------------------------------------  
+
+  // // Nemetchek's exp. Optima 2 !!!
+  // QMap < QString, QString > protocol_details;
+  // protocol_details["experimentId"] = QString("287");   
+  // protocol_details["protocolName"] = QString("RxRPPARhet-PPRE-MWL_180419");
+  // protocol_details[ "experimentName" ] = QString("some_name");
+  // protocol_details[ "CellChNumber" ] = QString("8");
+  // protocol_details[ "TripleNumber" ] = QString("38");
+  // protocol_details[ "OptimaName" ] = QString("Optima 2");     // <-- Optima 2
+  // protocol_details[ "duration" ]   = QString("36000");
+  // protocol_details[ "invID_passed" ]  = QString("41");  //Nemetchek's ID
+  
+  // QString stage                        = "LIVE_UPDATE";
+  // QString currDir                      = "";
+  // QString ProtName                     = "";
+  // QString invID_passed                 = protocol_details[ "invID_passed" ];
+
+  // --------------------------------------------------------------------------------------------
+ 
+
+  // Query 'autoflow': get cout of records
+  int autoflow_records = get_autoflow_records();
+
+  qDebug() << "Autoflow record #: " << autoflow_records;
+
+  if ( autoflow_records < 1 )
+    return;
+
+
+  // Dialog of aexisting autoflow records
+  US_Passwd  pw;
+  US_DB2* dbP  = new US_DB2( pw.getPasswd() );
+  list_all_autoflow_records( autoflowdata, dbP );
+  
+  QString pdtitle( tr( "Select Optima Run to Follow" ) );
+  QStringList hdrs;
+  int         prx;
+  hdrs << "ID"
+       << "Run Name"
+       << "Optima"
+       << "Created"
+       << "Started";
+  
+  US_SelectItem pdiag( autoflowdata, hdrs, pdtitle, &prx, -2 );
+  QString autoflow_id_selected("");
+  
+  if ( pdiag.exec() == QDialog::Accepted )
+    autoflow_id_selected  = autoflowdata[ prx ][ 0 ];
+  else
+    return;
+  
+
+  // -------------------------------------------------------------------------------------------------
+  // Get detailed info on the autoflow record
   QMap < QString, QString > protocol_details;
-  protocol_details[ "experimentId" ] = ExpID;
-  protocol_details[ "protocolName" ] = ProtName;
-  protocol_details[ "CellChNumber" ] = CellChNumber;
-  protocol_details[ "TripleNumber" ] = TprileNumber;;
+  int autoflowID = autoflow_id_selected.toInt();
 
+  protocol_details = read_autoflow_record( autoflowID );
+
+  QString stage        = protocol_details[ "status" ];
+  QString currDir      = protocol_details[ "dataPath" ];
+  QString invID_passed = protocol_details[ "invID_passed" ];
+  QString ProtName     = protocol_details[ "protocolName" ];
+
+    
+  if ( stage == "LIVE_UPDATE" )
+    {
+      //do something
+      switch_to_live_update( protocol_details );
+      return;
+    }
   
-  switch ( stageNumber )
+  if ( stage == "EDITING" )
     {
-    case 0:       //Experiment submit
-      {
-	break;
-      }
-    case 1:       //Live Update / us_xpn_viwer
-      {
-	//do something
-	switch_to_live_update( protocol_details );
-	break;
-      }
-    case 2:       //PostProd / us_convert  
-      {
-	//do something
-	switch_to_post_processing( currDir, ProtName);
-	break;
-      }
-      //and so on...
-    } 
-  */
+      //do something
+      switch_to_post_processing( currDir, ProtName, invID_passed );
+
+      //ALEXEY: should pass investigator as well: should be saved in 'autoflow'
+      /*
+       switch_to_post_processing( currDir, ProtName, invID_passed );  
+       see us_convert:
+           void US_ConvertGui::import_data_auto( QString &currDir, QString &protocolName )
+	    {
+	       assign investigator HERE passed in (QString &currDir, QString &protocolName, QString &invID_passed) as 3rd parameter; saved in 'autoflow' table
+	       ExpData.invID = invID_passed.toInt();
+	       ....
+
+	in us_convert: use function      read_record_auto( ProtocolName_auto, &xmlstr, NULL, &db );  
+      */
+      
+      return;
+    }
+  //and so on...
+  
+  
 }
 
+// Query autoflow for # records
+int US_ComProjectMain::list_all_autoflow_records( QList< QStringList >& autoflowdata, US_DB2* dbP )
+{
+  int nrecs        = 0;   
+  autoflowdata.clear();
 
+  QStringList qry;
+  qry << "get_autoflow_desc";
+  dbP->query( qry );
+
+  if ( dbP->lastErrno() != US_DB2::OK )
+    return nrecs;
+  
+  while ( dbP->next() )
+    {
+      QStringList autoflowentry;
+      QString id                 = dbP->value( 0 ).toString();
+      QString runname            = dbP->value( 5 ).toString();
+      QString optimaname         = dbP->value( 10 ).toString();
+      
+      QDateTime time_started     = dbP->value( 11 ).toDateTime().toUTC();
+
+      QDateTime time_created     = dbP->value( 13 ).toDateTime().toUTC();
+      QDateTime local(QDateTime::currentDateTime());
+
+      autoflowentry << id << runname << optimaname  << time_created.toString(); // << time_started.toString(); // << local.toString( Qt::ISODate );
+
+      if ( time_started.toString().isEmpty() )
+	autoflowentry << "not started";
+      else
+	autoflowentry << time_started.toString();
+      
+      autoflowdata  << autoflowentry;
+      nrecs++;
+    }
+
+  return nrecs;
+}
+
+    
+// Query autoflow for # records
+int US_ComProjectMain::get_autoflow_records( void )
+{
+   // Check DB connection
+   US_Passwd pw;
+   QString masterpw = pw.getPasswd();
+   US_DB2* db = new US_DB2( masterpw );
+
+   int record_number = 0;
+   
+   if ( db->lastErrno() != US_DB2::OK )
+     {
+       QMessageBox::warning( this, tr( "Connection Problem" ),
+			     tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
+       return record_number;
+     }
+
+   QStringList qry;
+   qry << "count_autoflow_records";
+   
+   record_number = db->functionQuery( qry );
+
+   return record_number;
+}
+
+
+// Query autoflow for # records
+QMap< QString, QString> US_ComProjectMain::read_autoflow_record( int autoflowID  )
+{
+   // Check DB connection
+   US_Passwd pw;
+   QString masterpw = pw.getPasswd();
+   US_DB2* db = new US_DB2( masterpw );
+
+   QMap <QString, QString> protocol_details;
+   
+   if ( db->lastErrno() != US_DB2::OK )
+     {
+       QMessageBox::warning( this, tr( "Connection Problem" ),
+			     tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
+       return protocol_details;
+     }
+
+   QStringList qry;
+   qry << "read_autoflow_record"
+       << QString::number( autoflowID );
+   
+   db->query( qry );
+
+   if ( db->lastErrno() == US_DB2::OK )      // Autoflow record exists
+     {
+       while ( db->next() )
+	 {
+	   protocol_details[ "protocolName" ]   = db->value( 0 ).toString();
+	   protocol_details[ "CellChNumber" ]   = db->value( 1 ).toString();
+	   protocol_details[ "TripleNumber" ]   = db->value( 2 ).toString();
+	   protocol_details[ "duration" ]       = db->value( 3 ).toString();
+	   protocol_details[ "experimentName" ] = db->value( 4 ).toString();
+	   protocol_details[ "experimentId" ]   = db->value( 5 ).toString();
+	   protocol_details[ "runID" ]          = db->value( 6 ).toString();
+	   protocol_details[ "status" ]         = db->value( 7 ).toString();
+           protocol_details[ "dataPath" ]       = db->value( 8 ).toString();   
+	   protocol_details[ "OptimaName" ]     = db->value( 9 ).toString();
+	   protocol_details[ "runStarted" ]     = db->value( 10 ).toString();
+	   protocol_details[ "invID_passed" ]   = db->value( 11 ).toString(); 
+	 }
+     }
+
+   return protocol_details;
+}
+
+
+
 // Slot to pass submitted to Optima run info to the Live Update tab
 void US_ComProjectMain::switch_to_live_update( QMap < QString, QString > & protocol_details)
 {
-   tabWidget->setCurrentIndex( 1 );   // Maybe lock this panel from now on? i.e. tabWidget->tabBar()-setEnabled(false) ?? 
+  tabWidget->setCurrentIndex( 1 );   // Maybe lock this panel from now on? i.e. tabWidget->tabBar()-setEnabled(false) ?? 
 
    // ALEXEY:
    // (1) Make a record to 'autoflow' table - stage# = 1;
@@ -347,22 +550,22 @@
 }
 
 // Slot to switch from the Live Update to Editing tab
-void US_ComProjectMain::switch_to_post_processing( QString  & currDir, QString & protocolName)
+void US_ComProjectMain::switch_to_post_processing( QString  & currDir, QString & protocolName,  QString & invID_passed )
 {
    tabWidget->setCurrentIndex( 2 );   // Maybe lock this panel from now on? i.e. tabWidget->tabBar()-setEnabled(false) ??
 
    // ALEXEY: Make a record to 'autoflow' table: stage# = 2; 
 
-   emit import_data_us_convert( currDir, protocolName );
+   emit import_data_us_convert( currDir, protocolName, invID_passed );
 }
      
 // Slot to switch back from the Live Update to Experiment tab
-void US_ComProjectMain::switch_to_experiment( QString & protocolName)
+void US_ComProjectMain::switch_to_experiment( QString & protocolName )
 {
    tabWidget->setCurrentIndex( 0 );   // Maybe lock this panel from now on? i.e. tabWidget->tabBar()-setEnabled(false) ??
 
-   // ALEXEY: Make a record to 'autoflow' table: stage# = 2; 
-
+   //delete_autoflow_record( runID );
+   
    emit clear_experiment( protocolName );
 }
    
@@ -454,7 +657,6 @@
    // Open US_Experiment without button...  
    //US_ExperimentMain* sdiag = new US_ExperimentMain;
 
-  
    sdiag = new US_ExperimentMain;
 
    sdiag->setParent(this, Qt::Widget);
@@ -480,6 +682,7 @@
      sdiag->us_mode_passed();
    
    sdiag->show();
+
    
 }
 
@@ -633,7 +836,7 @@
    connect( this, SIGNAL( to_xpn_viewer( QMap < QString, QString > &) ), sdiag, SLOT( check_for_data ( QMap < QString, QString > & )  ) );
 
    //ALEXEY: devise SLOT saying what to do upon completion of experiment and exporting AUC data to hard drive - Import Experimental Data  !!! 
-   connect( sdiag, SIGNAL( experiment_complete_auto( QString &, QString & ) ), this, SLOT( to_post_processing ( QString &, QString &) ) );
+   connect( sdiag, SIGNAL( experiment_complete_auto( QString &, QString &, QString & ) ), this, SLOT( to_post_processing ( QString &, QString &, QString &) ) );
 
    //ALEXEY: return to 1st panel when exp. aborted & no data saved..
    connect( sdiag, SIGNAL( return_to_experiment( QString & ) ), this, SLOT( to_experiment ( QString &) ) );
@@ -692,9 +895,9 @@
   emit to_xpn_viewer( protocol_details );
 }
 
-void US_ObservGui::to_post_processing( QString & currDir, QString & protocolName )
+void US_ObservGui::to_post_processing( QString & currDir, QString & protocolName, QString & invID_passed )
 {
-  emit switch_to_post_processing( currDir, protocolName );
+  emit switch_to_post_processing( currDir, protocolName, invID_passed );
 }
 
 void US_ObservGui::to_experiment( QString & protocolName )
@@ -745,7 +948,7 @@
    sdiag = new US_ConvertGui("AUTO");
    sdiag->setParent(this, Qt::Widget);
 
-   connect( this, SIGNAL( to_post_prod( QString &, QString & ) ), sdiag, SLOT( import_data_auto ( QString &, QString & )  ) );
+   connect( this, SIGNAL( to_post_prod( QString &, QString &, QString & ) ), sdiag, SLOT( import_data_auto ( QString &, QString &, QString & )  ) );
    //ALEXEY: switch to Analysis
    connect( sdiag, SIGNAL( saving_complete_auto( QString &, QString & ) ), this, SLOT( to_analysis ( QString &, QString &) ) );
    
@@ -759,9 +962,9 @@
 
 }
 
-void US_PostProdGui::import_data_us_convert( QString & currDir, QString & protocolName )
+void US_PostProdGui::import_data_us_convert( QString & currDir, QString & protocolName, QString & invID_passed )
 {
-  emit to_post_prod( currDir, protocolName );
+  emit to_post_prod( currDir, protocolName, invID_passed );
 }
 
 void US_PostProdGui::to_analysis( QString & currDir, QString & protocolName )

Modified: trunk/programs/us_com_project/us_com_project_gui.h
===================================================================
--- trunk/programs/us_com_project/us_com_project_gui.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_com_project/us_com_project_gui.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -94,7 +94,7 @@
       void switch_to_live_update( QMap < QString, QString > & protocol_details );
       void set_auto_mode( void );
       void reset_experiment( QString & protocolName);
-      
+      void check_stage( void );
 };
 
 
@@ -117,11 +117,11 @@
       
  private slots:
       void process_protocol_details( QMap < QString, QString > & protocol_details );
-      void to_post_processing( QString & currDir, QString & protocolName );
+      void to_post_processing( QString & currDir, QString & protocolName, QString & invID_passed );
       void to_experiment( QString & protocolName );
  signals:
       void to_xpn_viewer( QMap < QString, QString > & protocol_details );
-      void switch_to_post_processing( QString & currDir, QString & protocolName );
+      void switch_to_post_processing( QString & currDir, QString & protocolName, QString & invID_passed  );
       void switch_to_experiment( QString & protocolName );
 };
 
@@ -145,11 +145,11 @@
     void resizeEvent(QResizeEvent *event) override;
       
   private slots:
-    void import_data_us_convert( QString & currDir, QString & protocolName );
+    void import_data_us_convert( QString & currDir, QString & protocolName, QString & invID_passed  );
     void to_analysis( QString & currDir, QString & protocolName );
     
   signals:
-    void to_post_prod( QString & currDir, QString & protocolName );
+    void to_post_prod( QString & currDir, QString & protocolName, QString & invID_passed  );
     void switch_to_analysis( QString & currDir, QString & protocolName );
 };
 
@@ -222,7 +222,9 @@
   QString           icon_path;
 
   bool us_mode_bool;
-  
+
+  QList< QStringList >  autoflowdata;
+    
  private:
   US_ExperGui*      epanExp;         // US_Exp panel
   US_ObservGui*     epanObserv;      // US_Observ panel
@@ -234,8 +236,10 @@
   //int         dbg_level;       // Debug print flag
   int         curr_panx;       // Current panel index (0-7)
 
-  void check_current_stage( void );
-
+  //void check_current_stage( void );
+  int  get_autoflow_records( void );
+  QMap < QString, QString > read_autoflow_record( int );
+  static int list_all_autoflow_records( QList< QStringList >&, US_DB2* );
    
 private slots:
   //void reset     ( void );
@@ -248,18 +252,18 @@
   //void unable_tabs_buttons( void);  // Slot to unable Tabs and Buttons when user level is low
   //void enable_tabs_buttons( void);  // Slot to enable Tabs and Buttons after protocol is loaded
   void switch_to_live_update( QMap < QString, QString > & protocol_details );
-  void switch_to_post_processing( QString & currDir, QString & protocolName );
+  void switch_to_post_processing( QString & currDir, QString & protocolName, QString & invID_passed  );
   void switch_to_analysis( QString & currDir, QString & protocolName );
   void switch_to_experiment( QString & protocolName );
+  void check_current_stage( void );
   
 signals:
   void pass_to_live_update( QMap < QString, QString > & protocol_details ); 
-  void import_data_us_convert( QString & currDir, QString & protocolName );
+  void import_data_us_convert( QString & currDir, QString & protocolName, QString & invID_passed );
   void pass_to_analysis( QString & currDir, QString & protocolName );
   void clear_experiment( QString & protocolName);
+  //void check_stage( void );
 };
 
 
-
-
 #endif

Modified: trunk/programs/us_convert/us_convert_gui.cpp
===================================================================
--- trunk/programs/us_convert/us_convert_gui.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_convert/us_convert_gui.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -1104,9 +1104,20 @@
    reimport();
 }
 
-void US_ConvertGui::import_data_auto( QString &currDir, QString &protocolName )
+void US_ConvertGui::import_data_auto( QString &currDir, QString &protocolName, QString &invID_passed )
 {
   // ALEXEY TO BE ADDED...
+  /* 
+     assign investigator HERE passed in (QString &currDir, QString &protocolName, QString &invID_passed) as 3rd parameter; saved in 'autoflow' table
+
+     ExpData.invID = invID_passed.toInt();
+  */
+
+  //ExpData.invID = 41; // Nemetchek's ID
+  ExpData.invID = invID_passed.toInt();
+
+  qDebug() << "US_CONVERT: ExpData.invID, invID_passed: " << ExpData.invID << ", " << invID_passed;
+  
   int impType = getImports_auto( currDir );
   ProtocolName_auto = protocolName;   
 
@@ -1830,6 +1841,139 @@
    pb_saveUS3 ->setEnabled( completed );
 }
 
+
+// copy of :enableSaveBtn for autoflow
+void US_ConvertGui::enableSaveBtn_auto( void )
+{
+   lw_todoinfo->clear();
+   int count = 0;
+   bool completed = true;
+DbgLv(1) << " enabCtl: tLx infsz" << tripListx << out_chaninfo.count();
+   cb_centerpiece->setLogicalIndex( out_chaninfo[ tripListx ].centerpiece );
+
+   if ( allData.size() == 0 )
+   {
+      count++;
+      lw_todoinfo->addItem( QString::number( count )
+            + tr( ": Load or import some AUC data" ) );
+      completed = false;
+   }
+
+   // Do we have any triples?
+   if ( all_tripinfo.size() == 0 )
+   {
+      count++;
+      lw_todoinfo->addItem( QString::number( count )
+            + tr( ": Load or import some AUC data" ) );
+      completed = false;
+   }
+
+   // Is the run info defined?
+   QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
+
+   // Not checking operator on disk -- defined as "Local"
+   if ( ( ExpData.rotorID == 0 )              ||
+        ( ExpData.calibrationID == 0 )        ||
+        ( ExpData.labID == 0 )                ||
+        ( ExpData.instrumentID == 0 )         ||
+        ( ExpData.label.isEmpty() )           ||
+        ( ! rx.exactMatch( ExpData.project.projectGUID ) ) )
+   {
+      if ( ! referenceDefined )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count )
+               + tr( ": Modify run ID (optional)" ) );
+      }
+      count++;
+      lw_todoinfo->addItem( QString::number( count )
+            + tr( ": Edit run information" ) );
+      completed = false;
+   }
+
+   // Have we filled out all the c/c/w info?
+   // Check GUIDs, because solutionID's may not be present yet.
+   foreach ( US_Convert::TripleInfo tripinfo, out_chaninfo )
+   {
+      if ( ! rx.exactMatch( tripinfo.solution.solutionGUID ) )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count ) +
+                               tr( ": Select solution for triple " ) +
+                               tripinfo.tripleDesc );
+         completed = false;
+      }
+   }
+
+   foreach ( US_Convert::TripleInfo tripinfo, out_chaninfo )
+   {
+      if ( tripinfo.centerpiece == 0 )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count ) +
+                               tr( ": Select centerpiece for triple " ) +
+                               tripinfo.tripleDesc );
+         completed = false;
+      }
+   }
+
+   if ( disk_controls->db() )
+   {
+      // Verify connectivity
+      US_Passwd pw;
+      QString masterPW = pw.getPasswd();
+      US_DB2 db( masterPW );
+
+      if ( db.lastErrno() != US_DB2::OK )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count ) +
+                               tr( ": Verify database connectivity" ) );
+         completed = false;
+      }
+
+      // Information is there, but we need to see if the runID exists in the
+      // DB. If we didn't load it from there, then we shouldn't be able to sync
+      int recStatus = ExpData.checkRunID_auto( ExpData.invID, &db );
+
+      // if a record is found but saveStatus==BOTH,
+      //  then we are editing that record
+      if ( ( recStatus == US_DB2::OK ) && ( saveStatus != BOTH ) ) // ||
+           // ( ! ExpData.syncOK ) )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count ) +
+                               tr( ": Select a different runID" ) );
+         completed = false;
+      }
+
+      // Not checking operator on disk -- defined as "Local"
+      if ( ExpData.operatorID == 0 )
+      {
+         count++;
+         lw_todoinfo->addItem( QString::number( count )
+               + tr( ": Select operator in run information" ) );
+         completed = false;
+      }
+
+   }
+
+   // This can go on the todo list, but should not prevent user from saving
+   if ( ( runType == "RI" ) && ( ! referenceDefined ) )
+   {
+      count++;
+      lw_todoinfo->addItem( QString::number( count ) +
+                            tr( ": Define reference scans" ) );
+
+      if ( count == 1 )
+         pb_reference->setEnabled( true );
+   }
+
+   // If we made it here, user can save
+   pb_saveUS3 ->setEnabled( completed );
+}
+
+
 // Process when the user changes the runID
 void US_ConvertGui::runIDChanged( void )
 {
@@ -1894,8 +2038,8 @@
 
    
    QString xmlstr( "" );
-   //US_ProtocolUtil::read_record( pname, &xmlstr, NULL, &db );
-   US_ProtocolUtil::read_record( ProtocolName_auto, &xmlstr, NULL, &db );
+   //US_ProtocolUtil::read_record( ProtocolName_auto, &xmlstr, NULL, &db );
+   US_ProtocolUtil::read_record_auto( ProtocolName_auto, ExpData.invID,  &xmlstr, NULL, &db );
    
    qDebug() << "Protocol READ !!! ";
     
@@ -2069,9 +2213,11 @@
 
 
    //Investigator
-   ExpData.invID = US_Settings::us_inv_ID();     // just to be sure
+   // ExpData.invID = US_Settings::us_inv_ID();     // just to be sure
    ExpData.name  = US_Settings::us_inv_name();
 
+   qDebug() << "Investigator ID: " <<  ExpData.invID;
+   
    if ( db.lastErrno() == US_DB2::OK )
      {
        QStringList q( "get_person_info" );
@@ -2397,7 +2543,7 @@
    //le_centerpieceDesc ->setText( QString::number(out_chaninfo[ tripListx ].centerpiece) );
    le_centerpieceDesc ->setText( out_chaninfo[ tripListx ].centerpieceName );
 
-   enableSaveBtn();
+   enableSaveBtn_auto();
 }
 
 // Function to generate a new guid for experiment, and associate with DB
@@ -2939,8 +3085,9 @@
       }
 
       // Check if the run ID already exists in the DB
-      int recStatus = ExpData.checkRunID( &db );
-
+      //int recStatus = ExpData.checkRunID( &db );
+      int recStatus = ExpData.checkRunID_auto( ExpData.invID, &db );
+      
       // if saveStatus == BOTH, then we are editing the record from the database
       if ( ( recStatus == US_DB2::OK ) && ( saveStatus != BOTH ) )
       {

Modified: trunk/programs/us_convert/us_convert_gui.h
===================================================================
--- trunk/programs/us_convert/us_convert_gui.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_convert/us_convert_gui.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -247,7 +247,8 @@
       void enableRunIDControl( bool );
       void enableScanControls( void );
       void enableSaveBtn   ( void );
-
+      void enableSaveBtn_auto   ( void );
+      
       void getExpInfo      ( void );
       void readProtocol_auto ( void );
       bool readProtocolRotor_auto ( QXmlStreamReader& );
@@ -295,7 +296,7 @@
       */
       void assign_investigator( int );
 
-      void import_data_auto  (QString &, QString &);
+      void import_data_auto  (QString &, QString &, QString &);
       
       void import            ( void );
       void reimport          ( void );

Modified: trunk/programs/us_convert/us_experiment.cpp
===================================================================
--- trunk/programs/us_convert/us_experiment.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_convert/us_experiment.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -40,6 +40,24 @@
    return US_DB2::OK;
 }
 
+// Copy of checkRunID when invID propagated in autoflow
+int US_Experiment::checkRunID_auto( int invID_passed, US_DB2* db )
+{
+   // Let's see if we can find the run ID
+   expID = 0;
+   QStringList q( "get_experiment_info_by_runID" );
+   q << runID
+     << QString::number( invID_passed );
+   db->query( q );
+   if ( db->lastErrno() == US_DB2::NOROWS )
+      return US_DB2::NOROWS;
+   
+   // Ok, let's update the experiment ID
+   db->next();
+   expID = db->value( 1 ).toString().toInt();
+   return US_DB2::OK;
+}
+
 int US_Experiment::saveToDB( bool update, US_DB2* db,
                              QVector< SP_SPEEDPROFILE >& speedsteps )
 {

Modified: trunk/programs/us_convert/us_experiment.h
===================================================================
--- trunk/programs/us_convert/us_experiment.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_convert/us_experiment.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -83,6 +83,7 @@
           \param    db For database access, an open database connection
       */
       int checkRunID( US_DB2* = 0 );
+      int checkRunID_auto( int invID_passed, US_DB2* = 0 );
 
       /*! \brief    Function to save the experiment information to db
 

Modified: trunk/programs/us_experiment/us_experiment_gui_optima.cpp
===================================================================
--- trunk/programs/us_experiment/us_experiment_gui_optima.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_experiment/us_experiment_gui_optima.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -5303,6 +5303,7 @@
          protocol_details[ "protocolName" ]   = currProto->protoname;             // pass also to Live Update/PostProd protocol name
          protocol_details[ "CellChNumber" ]   = QString::number(rpSolut->nschan); // this can be read from protocol in US-lims DB
 	 protocol_details[ "duration" ]       = QString::number(Total_duration);
+	 protocol_details[ "invID_passed" ]   = QString::number(US_Settings::us_inv_ID());
 	 
          int nwavl_tot = 0;
          for ( int kk = 0; kk < rpRange->nranges; kk++ )
@@ -5335,10 +5336,6 @@
    }
    //submitted    = true;
 
-   // Make DB record on what protocol was submitted and what runname it's  associated with ...
-   // suggested table name is 'protocolExperiment';
-   //
-
    ck_sub_done->setChecked( true );
 
    if ( !mainw->automode )
@@ -5347,10 +5344,46 @@
        QString message_done   = tr( "Protocol has been successfully submitted to Optima DB." );
        QMessageBox::information( this, mtitle_done, message_done );
      }
+
+   //Make 'autoflow' table record:
+   if ( mainw->automode )
+     add_autoflow_record( protocol_details );
    
    emit expdef_submitted( protocol_details );
 }
 
+// Read Protocol details
+void US_ExperGuiUpload::add_autoflow_record( QMap< QString, QString> & protocol_details )
+{
+  // Check DB connection
+   US_Passwd pw;
+   QString masterpw = pw.getPasswd();
+   US_DB2* db = new US_DB2( masterpw );
+   
+   if ( db->lastErrno() != US_DB2::OK )
+     {
+       QMessageBox::warning( this, tr( "Connection Problem" ),
+			     tr( "Read protocol: Could not connect to database \n" ) + db->lastError() );
+       return;
+     }
+
+    if ( db != NULL )
+      {
+	QStringList qry;
+	qry << "add_autoflow_record"
+	    << protocol_details[ "protocolName" ]
+	    << protocol_details[ "CellChNumber" ]
+	    << protocol_details[ "TripleNumber" ]
+	    << protocol_details[ "duration" ]
+	    << protocol_details[ "experimentName" ]
+	    << protocol_details[ "experimentId" ]
+	    << protocol_details[ "OptimaName" ]
+	    << protocol_details[ "invID_passed" ];
+
+	db->query( qry );
+      }
+}
+
 // Function to build a Json object and document holding experiment controls
 QString US_ExperGuiUpload::buildJson( void )
 {

Modified: trunk/programs/us_experiment/us_experiment_gui_optima.h
===================================================================
--- trunk/programs/us_experiment/us_experiment_gui_optima.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_experiment/us_experiment_gui_optima.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -799,7 +799,8 @@
       void    submitExperiment( void );  // Submit the experiment
       void    saveRunProtocol ( void );  // Save the Run Protocol
       QString buildJson       ( void );  // Build the JSON
-
+      void    add_autoflow_record( QMap< QString, QString> &protocol_details );
+      
    signals:
       void expdef_submitted( QMap < QString, QString > &protocol_details );
 };

Modified: trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.cpp
===================================================================
--- trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -711,6 +711,19 @@
    // protocol_details[ "OptimaName" ] = QString("Optima 1"); 
    // protocol_details[ "duration" ]   = QString("27000");
    
+   //3. Temporary test - Harmen's experiment:  ExpID = 286 (ExperimentDefinition, Postgres, Optima 2); ProtocolID = 286 (Us-lims, Mysql);
+   // description = HarmenS_20180417_Purity_Run_6;
+   // 8 cells (16 channels); 29 wvls; 29 triples - for absorbance ONLY!! 
+   // QMap < QString, QString > protocol_details;
+   // protocol_details["experimentId"] = QString("286");   
+   // protocol_details["protocolName"] = QString("HarmenS_20180417_Purity_Run_6");
+   // protocol_details[ "experimentName" ] = QString("some_name");
+   // protocol_details[ "CellChNumber" ] = QString("16");
+   // protocol_details[ "TripleNumber" ] = QString("29");
+   // protocol_details[ "OptimaName" ] = QString("Optima 2"); 
+   // protocol_details[ "duration" ]   = QString("43200");
+      
+
    // check_for_data( protocol_details );
    // End of test
    
@@ -1459,6 +1472,9 @@
       timer_data_init->stop();
       disconnect(timer_data_init, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
       msg_data_avail->close();
+      
+      //ALEXEY: need to update 'autoflow' table with the unique  RunID_to_retrieve && Start Run Time fields !!!
+      
       //ALEXEY: elapsed timer start
       elapsed_timer = new QElapsedTimer;
       elapsed_timer->start();
@@ -1494,14 +1510,13 @@
       timer_check_sysdata = new QTimer(0); // parent to 0 !
       timer_check_sysdata->setInterval(2000);
       timer_check_sysdata->moveToThread(sys_thread);
-      connect( timer_check_sysdata, SIGNAL(timeout()), this, SLOT( check_for_sysdata( )  ) );
+      connect( timer_check_sysdata, SIGNAL(timeout()), this, SLOT( check_for_sysdata( )  ), Qt::QueuedConnection ) ; //Qt::DirectConnection );
       //QThread's started() SIGNAL: before the run()/exec() function is called!!! Is this a potential issue, timer is started from a thread???
       connect( sys_thread, SIGNAL( started() ), timer_check_sysdata, SLOT( start() ));      
       sys_thread->start();
       // How to stop sys_thread?
       
-      
-      
+            
       // Check if all triple info is available
       timer_all_data_avail = new QTimer;
       connect(timer_all_data_avail, SIGNAL(timeout()), this, SLOT( retrieve_xpn_raw_auto ( ) ));
@@ -1518,6 +1533,7 @@
 void US_XpnDataViewer::check_for_sysdata( void )
 {
   qDebug() << "sys_timer IS RUNNING here: ";
+  qDebug() << "sys_timer IS RUNNING here: in_reload_check_sysdata " << in_reload_check_sysdata;
   
   if ( in_reload_check_sysdata )            // If already doing a reload,
     return;                                //  skip starting a new one
@@ -1547,10 +1563,12 @@
   //RPM speed
   double rpm_for_meter = double(rpm/1000.0);
   rpm_box->setSpeed(rpm_for_meter);
-
+  qApp->processEvents();
+  
   //Temperature
   temperature_box->setTemp(temperature);
-
+  qApp->processEvents();
+  
   //Running Time
   QList< int > dhms_r;
   int running_time = exp_time;// + etimoff; //ALEXEY: OR elapsed_time + etimoff? OR just exp_time ???? //ALEXEY: etimoff < 0 ?
@@ -1561,7 +1579,9 @@
   //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
   running_time_text = QString::number(dhms_r[1]) + ":" + QString::number(dhms_r[2]) + ":" + QString::number(dhms_r[3]);
   le_running->setText( running_time_text );
+  qApp->processEvents();
 
+  
   //Elapsed Time
   QList< int > dhms_e;
   int elapsed_time = int( elapsed_timer->elapsed() / 1000 );
@@ -1571,7 +1591,8 @@
   //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
   elapsed_time_text = QString::number(dhms_e[1]) + ":" + QString::number(dhms_e[2]) + ":" + QString::number(dhms_e[3]);
   le_elapsed->setText( elapsed_time_text );
-   
+  qApp->processEvents();
+  
   //Remaining Time
   QList< int > dhms_remain;
   int remaining_time = TotalDuration.toInt() - ( exp_time ); //+ etimoff );
@@ -1580,7 +1601,8 @@
   //ALEXEY: hh:mm:ss - OR do we need dd:hh:mm instead ?
   remaining_time_text = QString::number(dhms_remain[1]) + ":" + QString::number(dhms_remain[2]) + ":" + QString::number(dhms_remain[3]);
   le_remaining->setText( remaining_time_text );
-
+  qApp->processEvents();
+  
   //RPM/Temp. Plots:
 
   //counter_mins += 500; //temporary for testing only
@@ -1616,36 +1638,61 @@
   data_plot_rpm->setAxisScale( QwtPlot::yRight, temp_min, temp_max );  //Y-Temp.
   
   //ALEXEY: no plot rescaling to bounds...
+
+  qDebug() << "SYS_STAT: BEFORE replot(), BEFORE CheExpStat!! ";
+   
   data_plot_rpm->replot();
+  qApp->processEvents();
 
+  qDebug() << "SYS_STAT: After replot(), BEFORE CheExpStat!! ";
+  
   int exp_status = CheckExpComplete_auto( RunID_to_retrieve  );
    
   if ( exp_status == 5 )
     {
+      timer_check_sysdata->stop();
+      disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
+      
+      qDebug() << "ExpStat: 5  - sys_timer STOPPED here: ";
+      
+      rpm_box->setSpeed( 0 );
+      le_remaining->setText( "00:00:00" );   
+
       expStatFive();
       return;
     }
+  
    if ( exp_status == 2 )
     {
+      
+      timer_check_sysdata->stop();
+      disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
+      
+      qDebug() << "ExpStat: 2  - sys_timer STOPPED here: ";
+      
+      rpm_box->setSpeed( 0 );
+      le_remaining->setText( "00:00:00" );
+
       expStatTwo();
       return;
     } 
+
+   qDebug() << "sys_timer RAN here: ";
+   in_reload_check_sysdata   = false;
   
-  in_reload_check_sysdata   = false;
-  
-  qDebug() << "sys_timer RAN here: ";
+  //qDebug() << "sys_timer RAN here: ";
 }
 
 // Stop/reset all system panels and pass to stage 3 when exp_Status == 5
 void US_XpnDataViewer::expStatFive( void )
 {
-  timer_check_sysdata->stop();
-  disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
+  // timer_check_sysdata->stop();
+  // disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
   
-  qDebug() << "ExpStat: 5  - sys_timer STOPPED here: ";
+  // qDebug() << "ExpStat: 5  - sys_timer STOPPED here: ";
   
-  rpm_box->setSpeed( 0 );
-  le_remaining->setText( "00:00:00" );
+  // rpm_box->setSpeed( 0 );
+  // le_remaining->setText( "00:00:00" );
   
   if ( !timer_all_data_avail->isActive() ) // Check if reload_data Timer is stopped
     {
@@ -1658,7 +1705,7 @@
 	  QString message_done     = tr( "Experiment was completed. Optima data saved..." );
 	  QMessageBox::information( this, mtitle_complete, message_done );
 	  
-	  emit experiment_complete_auto( currentDir, ProtocolName  );  // Updtade later: what should be passed with signal ??
+	  emit experiment_complete_auto( currentDir, ProtocolName, invID_passed  );  // Updtade later: what should be passed with signal ??
 	  
 	  return;
 	}
@@ -1668,13 +1715,13 @@
 // Stop/reset all system panels and pass to stage 3 when exp_Status == 2
 void US_XpnDataViewer::expStatTwo( void )
 {
-  timer_check_sysdata->stop();
-  disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
+  // timer_check_sysdata->stop();
+  // disconnect(timer_check_sysdata, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
   
-  qDebug() << "ExpStat: 2  - sys_timer STOPPED here: ";
+  // qDebug() << "ExpStat: 2  - sys_timer STOPPED here: ";
   
-  rpm_box->setSpeed( 0 );
-  le_remaining->setText( "00:00:00" );
+  // rpm_box->setSpeed( 0 );
+  // le_remaining->setText( "00:00:00" );
 
   if ( !timer_all_data_avail->isActive() ) // Check if reload_data Timer is stopped
     {
@@ -1699,7 +1746,7 @@
 	      QString mtitle_complete  = tr( "Complete!" );
 	      QString message_done     = tr( "Experiment was completed. Optima data saved..." );
 	      QMessageBox::information( this, mtitle_complete, message_done );
-	      emit experiment_complete_auto( currentDir, ProtocolName  );  // Updtade later: what should be passed with signal ??
+	      emit experiment_complete_auto( currentDir, ProtocolName, invID_passed  );  // Updtade later: what should be passed with signal ??
 	      return;
 	    }
 	  
@@ -1750,8 +1797,10 @@
   CellChNumber   = protocol_details[ "CellChNumber" ];
   TripleNumber = protocol_details[ "TripleNumber" ];
   OptimaName   = protocol_details[ "OptimaName" ];               //New
-  TotalDuration = protocol_details[ "duration" ];   
+  TotalDuration = protocol_details[ "duration" ];
 
+  invID_passed = protocol_details[ "invID_passed" ];
+
   selectOptimaByName_auto( OptimaName );                         //New  
   
   timer_data_init = new QTimer;
@@ -3365,7 +3414,9 @@
 DbgLv(1) << "RLd:       NO CHANGE";
 
       /*** Check Experiement Status: if completed, kill the timer, export the data into AUC format, return, signal to switch panels in US_comproject ***/
-      if ( CheckExpComplete_auto( RunID_to_retrieve  ) == 5 )
+      int statusExp = CheckExpComplete_auto( RunID_to_retrieve  );
+
+      if ( statusExp == 5 )
 	{
 	  timer_data_reload->stop();
 	  disconnect(timer_data_reload, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
@@ -3380,7 +3431,7 @@
 	      QString message_done     = tr( "Experiment was completed. Optima data saved..." );
 	      QMessageBox::information( this, mtitle_complete, message_done );
 	      
-	      emit experiment_complete_auto( currentDir, ProtocolName  );  // Updtade later: what should be passed with signal ??
+	      emit experiment_complete_auto( currentDir, ProtocolName, invID_passed  );  // Updtade later: what should be passed with signal ??
 	      //QString temp_protname("DemchukA_exosomes40K_111418");
 	      //emit experiment_complete_auto( currentDir, temp_protname  );  
 	  
@@ -3389,7 +3440,7 @@
 	}
 
       /** Experiment Aborted ***/
-      if ( CheckExpComplete_auto( RunID_to_retrieve  ) == 2 )
+      if ( statusExp == 2 )
 	{
 	  timer_data_reload->stop();
 	  disconnect(timer_data_reload, SIGNAL(timeout()), 0, 0);   //Disconnect timer from anything
@@ -3415,7 +3466,7 @@
 		  QString mtitle_complete  = tr( "Complete!" );
 		  QString message_done     = tr( "Experiment was completed. Optima data saved..." );
 		  QMessageBox::information( this, mtitle_complete, message_done );
-		  emit experiment_complete_auto( currentDir, ProtocolName  );  // Updtade later: what should be passed with signal ??
+		  emit experiment_complete_auto( currentDir, ProtocolName, invID_passed  );  // Updtade later: what should be passed with signal ??
 		  return;
 		}
 	      
@@ -3459,6 +3510,7 @@
    in_reload_auto   = false;         // Flag no longer in the midst of reload
 }
 
+
 // Slot to respond to a timer event (auto-reload)
 void US_XpnDataViewer::timerEvent( QTimerEvent *event )
 {

Modified: trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.h
===================================================================
--- trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/programs/us_xpn_viewer/us_xpn_viewer_gui.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -279,6 +279,7 @@
      QString        TripleNumber;
      QString        OptimaName;          //New
      QString        TotalDuration;       //New
+     QString        invID_passed;  
 
      void           timeToList( int&, QList< int >& );
 	 
@@ -341,7 +342,7 @@
      void test_optima_connection( void );              //New
      
    signals:
-     void experiment_complete_auto( QString &, QString & );
+     void experiment_complete_auto( QString &, QString &, QString & );
      void return_to_experiment( QString & );
 };
 #endif

Modified: trunk/sql/us3.sql
===================================================================
--- trunk/sql/us3.sql	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/sql/us3.sql	2019-04-27 09:50:16 UTC (rev 2741)
@@ -80,6 +80,32 @@
 ENGINE = InnoDB;
 
 
+-----------------------------------------------------
+-- Table autoflow--
+-----------------------------------------------------
+
+DROP TABLE IF EXISTS autoflow;
+
+CREATE  TABLE IF NOT EXISTS autoflow (
+  ID int(11) NOT NULL AUTO_INCREMENT ,
+  protName varchar(80) NULL,
+  cellChNum int(10) NULL,
+  tripleNum int(10) NULL,
+  duration int(10)  NULL,
+  runName varchar(300) NULL,
+  expID  int(10) NULL,
+  runID  int(10) NULL,
+  status enum('LIVE_UPDATE','EDITING','ANALYSIS','REPORT') NOT NULL,
+  dataPath varchar(300) NULL,
+  optimaName varchar(300) NULL,
+  runStarted TIMESTAMP NULL,
+  invID  INT NULL,
+  created TIMESTAMP NULL,
+  PRIMARY KEY (ID) )
+ENGINE = InnoDB;
+
+
+
 -- -----------------------------------------------------
 -- Table instrument
 -- -----------------------------------------------------

Added: trunk/sql/us3_autoflow_procs.sql
===================================================================
--- trunk/sql/us3_autoflow_procs.sql	                        (rev 0)
+++ trunk/sql/us3_autoflow_procs.sql	2019-04-27 09:50:16 UTC (rev 2741)
@@ -0,0 +1,321 @@
+--
+-- us3_autoflow_procs.sql
+--
+-- Script to set up the MySQL stored procedures for the US3 system
+--   These are related to various tables pertaining to autoflow
+-- Run as root
+--
+
+DELIMITER $$
+
+--
+-- Autoflow procedures
+--
+
+
+-- Returns the count of autoflow records in db
+DROP FUNCTION IF EXISTS count_autoflow_records$$
+CREATE FUNCTION count_autoflow_records ( p_personGUID CHAR(36),
+                                       p_password   VARCHAR(80) )
+                                       
+  RETURNS INT
+  READS SQL DATA
+
+BEGIN
+
+  DECLARE count_records INT;
+
+  CALL config();
+  SET count_records = 0;
+
+       
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    SELECT    COUNT(*)
+    INTO      count_records
+    FROM      autoflow;
+    
+  END IF;
+
+  RETURN( count_records );
+
+END$$
+
+-- adds autoflow record
+DROP PROCEDURE IF EXISTS add_autoflow_record$$
+CREATE PROCEDURE add_autoflow_record ( p_personGUID  CHAR(36),
+                                     p_password      VARCHAR(80),
+                                     p_protname      VARCHAR(80),
+                                     p_cellchnum     INT,
+                                     p_triplenum     INT,
+				     p_duration      INT,
+				     p_runname       VARCHAR(80),
+				     p_expid         INT,
+				     p_optimaname    VARCHAR(80),
+				     p_invID         INT )
+                                    
+  MODIFIES SQL DATA
+
+BEGIN
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+  SET @LAST_INSERT_ID = 0;
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    INSERT INTO autoflow SET
+      protname          = p_protname,
+      cellChNum         = p_cellchnum,
+      tripleNum         = p_triplenum,
+      duration          = p_duration,
+      runName           = p_runname,
+      expID             = p_expid,
+      optimaName        = p_optimaname,
+      invID             = p_invID,
+      created           = NOW();
+
+    SET @LAST_INSERT_ID = LAST_INSERT_ID();
+
+  END IF;
+
+  SELECT @US3_LAST_ERRNO AS status;
+
+END$$
+
+
+-- DELETE  autoflow record ( when Optima run aborted manually )
+DROP PROCEDURE IF EXISTS delete_autoflow_record$$
+CREATE PROCEDURE delete_autoflow_record ( p_personGUID    CHAR(36),
+                                     	p_password      VARCHAR(80),
+                			p_runID         INT )
+  MODIFIES SQL DATA
+
+BEGIN
+  DECLARE count_records INT;	
+	
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    
+    -- Find out if record exists for associated runID 
+    SELECT COUNT(*) INTO count_records 
+    FROM autoflow 
+    WHERE runID = p_runID;
+
+    IF ( count_records = 0 ) THEN
+      SET @US3_LAST_ERRNO = @NO_AUTOFLOW_RECORD;
+      SET @US3_LAST_ERROR = 'Record cannot be deleted as it does not exist for current experiment run';   
+
+    ELSE
+      DELETE FROM autoflow
+      WHERE runID = p_runID;
+    
+    END IF;  
+
+  END IF;
+      
+  SELECT @US3_LAST_ERRNO AS status;
+
+END$$
+
+
+
+-- Returns complete information about autoflow record
+DROP PROCEDURE IF EXISTS read_autoflow_record$$
+CREATE PROCEDURE read_autoflow_record ( p_personGUID    CHAR(36),
+                                       	p_password      VARCHAR(80),
+                                       	p_autoflowID  INT )
+  READS SQL DATA
+
+BEGIN
+  DECLARE count_records INT;
+
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+  SELECT     COUNT(*)
+  INTO       count_records
+  FROM       autoflow
+  WHERE      ID = p_autoflowID;
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    IF ( count_records = 0 ) THEN
+      SET @US3_LAST_ERRNO = @NO_AUTOFLOW_RECORD;
+      SET @US3_LAST_ERROR = 'MySQL: no rows returned';
+
+      SELECT @US3_LAST_ERRNO AS status;
+
+    ELSE
+      SELECT @OK AS status;
+
+      SELECT   protName, cellChNum, tripleNum, duration, runName, expID, 
+      	       runID, status, dataPath, optimaName, runStarted, invID, created
+      FROM     autoflow
+      WHERE    ID = p_autoflowID;
+
+    END IF;
+
+  ELSE
+    SELECT @US3_LAST_ERRNO AS status;
+
+  END IF;
+
+END$$
+
+
+-- Returns information about autoflow records for listing
+DROP PROCEDURE IF EXISTS get_autoflow_desc$$
+CREATE PROCEDURE get_autoflow_desc ( p_personGUID    CHAR(36),
+                                       	p_password      VARCHAR(80) )
+                                     
+  READS SQL DATA
+
+BEGIN
+  DECLARE count_records INT;
+
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+  SELECT     COUNT(*)
+  INTO       count_records
+  FROM       autoflow;
+
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    IF ( count_records = 0 ) THEN
+      SET @US3_LAST_ERRNO = @NO_AUTOFLOW_RECORD;
+      SET @US3_LAST_ERROR = 'MySQL: no rows returned';
+
+      SELECT @US3_LAST_ERRNO AS status;
+
+    ELSE
+      SELECT @OK AS status;
+
+      SELECT   ID, protName, cellChNum, tripleNum, duration, runName, expID, 
+      	       runID, status, dataPath, optimaName, runStarted, invID, created  
+      FROM     autoflow;
+     
+    END IF;
+
+  ELSE
+    SELECT @US3_LAST_ERRNO AS status;
+
+  END IF;
+
+END$$
+
+
+-- Update autoflow record with Optima's RunID
+DROP PROCEDURE IF EXISTS update_autoflow_runid_starttime$$
+CREATE PROCEDURE update_autoflow_runid_starttime ( p_personGUID    CHAR(36),
+                                         	 p_password      VARCHAR(80),
+                                       	 	 p_expID    	 INT,
+					 	 p_runid    	 INT  )
+  MODIFIES SQL DATA  
+
+BEGIN
+  DECLARE count_records INT;
+
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+SELECT     COUNT(*)
+  INTO       count_records
+  FROM       autoflow
+  WHERE      expID = p_expID;
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    IF ( count_records = 0 ) THEN
+      SET @US3_LAST_ERRNO = @NO_AUTOFLOW_RECORD;
+      SET @US3_LAST_ERROR = 'MySQL: no rows returned';
+
+    ELSE
+      UPDATE   autoflow
+      SET      runID = p_runid, runStarted = NOW()
+      WHERE    expID = p_expID;
+
+    END IF;
+
+  END IF;
+
+  SELECT @US3_LAST_ERRNO AS status;
+
+END$$
+
+
+-- Update autoflow record with next stage && curDir at LIVE_UPDATE
+DROP PROCEDURE IF EXISTS update_autoflow_at_live_update$$
+CREATE PROCEDURE update_autoflow_at_live_update ( p_personGUID    CHAR(36),
+                                             	p_password      VARCHAR(80),
+                                       	     	p_runID    	 INT,
+					  	p_curDir        VARCHAR(80)  )
+  MODIFIES SQL DATA  
+
+BEGIN
+  DECLARE count_records INT;
+
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+SELECT     COUNT(*)
+  INTO       count_records
+  FROM       autoflow
+  WHERE      runID = p_runID AND status = 'LIVE_UPDATE';
+
+  IF ( verify_user( p_personGUID, p_password ) = @OK ) THEN
+    IF ( count_records = 0 ) THEN
+      SET @US3_LAST_ERRNO = @NO_AUTOFLOW_RECORD;
+      SET @US3_LAST_ERROR = 'MySQL: no rows returned';
+
+    ELSE
+      UPDATE   autoflow
+      SET      dataPath = p_curDir, status = 'EDITING'
+      WHERE    runID = p_runID AND status = 'LIVE_UPDATE';
+
+    END IF;
+
+  END IF;
+
+  SELECT @US3_LAST_ERRNO AS status;
+
+END$$
+
+
+----  get initial elapsed time upon reattachment ----------------------------- 
+DROP FUNCTION IF EXISTS read_autoflow_times$$
+CREATE FUNCTION read_autoflow_times ( p_personGUID CHAR(36),
+                                       p_password   VARCHAR(80), 
+				       p_runID      INT )
+                                       
+  RETURNS INT
+  READS SQL DATA
+
+BEGIN
+  DECLARE count_records INT;
+  DECLARE l_sec_difference INT; 
+
+  SET l_sec_difference = 0;
+
+  CALL config();
+  SET @US3_LAST_ERRNO = @OK;
+  SET @US3_LAST_ERROR = '';
+
+  SELECT     COUNT(*)
+  INTO       count_records
+  FROM       autoflow
+  WHERE      runID = p_runID;
+
+  SELECT TIMESTAMPDIFF( SECOND, runStarted, NOW() ) 
+  INTO l_sec_difference 
+  FROM autoflow WHERE runID = p_runID;
+
+
+  RETURN( l_sec_difference );
+
+END$$
+

Modified: trunk/utils/us_db2.h
===================================================================
--- trunk/utils/us_db2.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/utils/us_db2.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -92,7 +92,8 @@
       NO_REPORT_DOCUMENT = 522, //!< No report document with the specified ID exists
 
       INSTRUMENT_IN_USE = 553,
-      PROTOCOL_IN_USE = 554, 
+      PROTOCOL_IN_USE = 554,
+      NO_AUTOFLOW_RECORD = 555,
       UNKNOWN_ERR    = 999      //!< No project with the specified ID exists
     };
 

Modified: trunk/utils/us_protocol_util.cpp
===================================================================
--- trunk/utils/us_protocol_util.cpp	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/utils/us_protocol_util.cpp	2019-04-27 09:50:16 UTC (rev 2741)
@@ -398,6 +398,113 @@
    return idprot;
 }
 
+// Copy of the read_record for autoflow when inv_ID is propagated 
+int US_ProtocolUtil::read_record_auto( const QString protname, int invID_passed, QString* xml,
+				       QStringList* protentry, US_DB2* dbP )
+{
+   int idprot       = -1;
+
+   if ( xml != NULL )
+      xml      ->clear();
+   if ( protentry != NULL )
+      protentry->clear();
+
+   if ( dbP != NULL )
+   {  // Find the record in the database with a matching name
+      QStringList qry;
+      qry << "get_protocol_desc" << QString::number( invID_passed );
+      dbP->query( qry );
+
+      if ( dbP->lastErrno() != US_DB2::OK )
+         return idprot;    // Error exit:  unable to read DB record
+
+      while ( dbP->next() )
+      {
+         QString pname    = dbP->value( 2 ).toString();
+
+         if ( pname == protname )
+         {  // Name match:  store information and break out
+            QString pdbid    = dbP->value( 0 ).toString();
+            QString pguid    = dbP->value( 1 ).toString();
+            QDateTime date   = dbP->value( 5 ).toDateTime().toUTC();
+            QString pdate    = US_Util::toUTCDatetimeText( date
+                                  .toString( Qt::ISODate ), true )
+                                  .section( " ", 0, 0 ).simplified();
+
+            // Return entry, xml, and protocol ID
+            if ( protentry != NULL )
+               *protentry << pname << pdate << pdbid << pguid;
+            if ( xml != NULL )
+               *xml             = dbP->value( 3 ).toString();
+
+            idprot           = pdbid.toInt();
+            break;
+         }
+      }  // END: db records
+   }  // END: from database
+
+   else
+   {  // Find the record in a local file with a matching name
+      QString datdir      = US_Settings::dataDir() + "/projects/";
+      datdir.replace( "\\", "/" );        // Possible Windows fix
+      QStringList rfilt( "R*.xml" );      // "~/ultrascan/data/projects/R*.xml"
+      QStringList pfiles  = QDir( datdir ).entryList(
+                                              rfilt, QDir::Files, QDir::Name );
+      int nfiles          = pfiles.count();
+
+      for ( int ii = 0; ii < nfiles; ii++ )
+      {  // Examine each "R000*.xml" file in the directory
+         QString pname;
+         QString pguid;  
+         QString pfname      = pfiles[ ii ];
+         QString pfpath      = datdir + pfname;
+         QFile pfile( pfpath );
+         // Skip if there is a file-open problem
+         if ( ! pfile.open( QIODevice::ReadOnly ) )  continue;
+
+         // Capture the XML as a string and start XML reader
+         QTextStream tsi( &pfile );
+         QString xmlstr      = tsi.readAll();
+         pfile.close();
+         QXmlStreamReader xmli( xmlstr );
+
+         while( ! xmli.atEnd() )
+         {  // Parse XML for description and guid
+            xmli.readNext();
+            QString ename       = xmli.name().toString();
+            if ( xmli.isStartElement()  &&  ename == "protocol" )
+            {
+               QXmlStreamAttributes attr = xmli.attributes();
+               pname               = attr.value( "description" ).toString();
+               pguid               = attr.value( "guid" ).toString();
+               break;
+            }
+         }
+
+         if ( pname == protname )
+         {  // Name match:  store information and break out
+            QString fdate       = US_Util::toUTCDatetimeText(
+                                  QFileInfo( pfpath ).lastModified().toUTC()
+                                  .toString( Qt::ISODate ), true )
+                                  .section( " ", 0, 0 ).simplified();
+
+            // Return entry, xml, and protocol ID (filename numeric)
+            if ( protentry != NULL )
+               *protentry << pname << fdate << pfname << pguid;
+            if ( xml != NULL )
+               *xml             = xmlstr;
+
+            idprot           = QString( pfname ).section( ".", 0, 0 ).mid( 1 ).toInt();
+            break;
+         }
+      }  // END: file loop
+   }  // END: local disk
+
+   return idprot;
+}
+
+
+
 // Delete a protocol record from the database or local disk.
 //
 // This function uses a protocol ID (database record ID or "R*.xml"

Modified: trunk/utils/us_protocol_util.h
===================================================================
--- trunk/utils/us_protocol_util.h	2019-04-25 14:13:07 UTC (rev 2740)
+++ trunk/utils/us_protocol_util.h	2019-04-27 09:50:16 UTC (rev 2741)
@@ -66,6 +66,10 @@
       static int read_record( const QString protname, QString* xml,
                               QStringList*, US_DB2* );
 
+      static int read_record_auto( const QString protname,
+				   int invID_passed, QString* xml,
+				   QStringList*, US_DB2* );
+
       //! \brief Delete a protocol record from the database or local disk.
       //!
       //! This function uses a protocol DB ID (or GUID if local disk)



More information about the us-commits mailing list