UltraScan III
us_select_rundd.cpp
Go to the documentation of this file.
1 
3 #include "us_select_rundd.h"
4 #include "us_settings.h"
5 #include "us_gui_settings.h"
6 #include "us_matrix.h"
7 #include "us_investigator.h"
8 #include "us_passwd.h"
9 #include "us_db2.h"
10 #include "us_util.h"
11 #include "us_editor.h"
12 #include "us_constants.h"
13 #include "us_report.h"
14 #include "us_sleep.h"
15 
16 // Main constructor with flags for select-runID dialog
17 
18 US_SelectRunDD::US_SelectRunDD( bool dbase, QStringList& runIDs,
19  QStringList& mdescrs ) : US_WidgetsDialog( 0, 0 ),
20  runIDs( runIDs ), mDescrs( mdescrs )
21 {
22  sel_db = dbase;
24  nimodel = mDescrs.count();
25  mcounted = false;
26 
27  setWindowTitle( tr( "Select Run ID(s) for Discrete Distributions (%1)" )
28  .arg( sel_db ? "DB" : "Local" ) );
29  setPalette ( US_GuiSettings::frameColor() );
30  setMinimumSize( 480, 300 );
31 DbgLv(1) << "SE:sel_db" << sel_db;
32 
33  // Main layout
34  QVBoxLayout* main = new QVBoxLayout( this );
35  main->setContentsMargins( 2, 2, 2, 2 );
36  main->setSpacing ( 2 );
37 
38  // Top layout: buttons and fields above list widget
39  QGridLayout* top = new QGridLayout;
40 
43  pb_invest = us_pushbutton( tr( "Select Investigator" ) );
44  QString invnum = QString::number( US_Settings::us_inv_ID() ) + ": ";
45  QString invusr = US_Settings::us_inv_name();
46  le_invest = us_lineedit( invnum + invusr, 0, true );
47  pb_invest->setEnabled( sel_db );
48 
49  // Search line
50  QLabel* lb_filtdata = us_label( tr( "Search" ) );
51 
53 
54  connect( dkdb_cntrls, SIGNAL( changed( bool ) ),
55  this, SLOT( update_disk_db( bool ) ) );
56  connect( pb_invest, SIGNAL( clicked() ),
57  SLOT ( get_person() ) );
58  connect( le_dfilter, SIGNAL( textChanged( const QString& ) ),
59  SLOT ( search ( const QString& ) ) );
60 
61  int row = 0;
62  top->addLayout( dkdb_cntrls, row++, 0, 1, 3 );
63  top->addWidget( pb_invest, row, 0, 1, 1 );
64  top->addWidget( le_invest, row++, 1, 1, 2 );
65  top->addWidget( lb_filtdata, row, 0, 1, 1 );
66  top->addWidget( le_dfilter, row++, 1, 1, 2 );
67 
68  main->addLayout( top );
69 
71 
72  // List widget to show data choices
73  lw_data = new QListWidget( this );
74  lw_data->setFrameStyle ( QFrame::NoFrame );
75  lw_data->setPalette ( US_GuiSettings::editColor() );
76  lw_data->setFont ( font );
77  lw_data->setSelectionMode( QAbstractItemView::ExtendedSelection );
78  connect( lw_data, SIGNAL( itemSelectionChanged() ),
79  this, SLOT ( selectionChanged() ) );
80 
81  main->addWidget( lw_data );
82 
83  // Button Row
84  QHBoxLayout* buttons = new QHBoxLayout;
85 
86  QPushButton* pb_cancel = us_pushbutton( tr( "Cancel" ) );
87  QPushButton* pb_accept = us_pushbutton( tr( "Accept" ) );
88 
89  connect( pb_cancel, SIGNAL( clicked() ), SLOT( cancelled() ) );
90  connect( pb_accept, SIGNAL( clicked() ), SLOT( accepted() ) );
91 
92  buttons->addWidget( pb_cancel );
93  buttons->addWidget( pb_accept );
94 
95  main->addLayout( buttons );
96 
97  // Status Row
98  QFontMetrics fm( font );
99  int fhigh = fm.lineSpacing();
100  int fwide = fm.width( QChar( '6' ) );
101  int lhigh = fhigh * 4 + 12;
102  int lwide = fwide * 32;
103 
105  te_status->setMaximumHeight( lhigh );
106  te_status->resize( lwide, lhigh );
107  us_setReadOnly( te_status, true );
108  te_status->setTextColor( Qt::blue );
109 
110  main->addWidget( te_status );
111 
112  // List from disk or db source
113  list_data();
114 }
115 
116 // Hide list items that do not contain search string
117 void US_SelectRunDD::search( const QString& search_string )
118 {
119  lw_data->setCurrentItem( NULL );
120 
121  for ( int ii = 0; ii < lw_data->count(); ii++ )
122  {
123  QListWidgetItem* lwi = lw_data->item( ii );
124  bool hide = ! lwi->text().contains( search_string, Qt::CaseInsensitive );
125  lwi->setHidden( hide );
126  }
127 }
128 
129 // List data choices (from db or disk)
131 {
132  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
133  rlabels.clear();
134 
135  if ( sel_db ) // Scan database data
136  {
137  scan_dbase_runs();
138  }
139  else // Scan local disk data
140  {
141  scan_local_runs();
142  }
143 
144  QApplication::restoreOverrideCursor();
145  lw_data->clear();
146 
147  if ( rlabels.size() == 0 )
148  { // Report and return now if no items found
149  QString clabel = tr( "No data found." );
150  lw_data->addItem( new QListWidgetItem( clabel ) );
151  return;
152  }
153 DbgLv(1) << "LD:sel_db" << sel_db << "rlsize" << rlabels.size();
154 
155  for ( int ii = 0; ii < rlabels.size(); ii++ )
156  { // Propagate list widget with labels
157  QString clabel = rlabels.at( ii );
158 
159  lw_data->addItem( new QListWidgetItem( clabel ) );
160  }
161 
162  // Report list state in status box
163  count_list = lw_data->count();
164  count_seld = lw_data->selectedItems().size();
165  te_status->setText(
166  tr( "%1 scanned run IDs were used to derive the list. Of these,\n"
167  "%2 (may) have associated distributions (models), and\n"
168  "%3 %4 currently selected for combination plot components." )
169  .arg( count_allr ).arg( count_list ).arg( count_seld )
170  .arg( count_seld != 1 ? tr( "runs are" ) : tr( "run is" ) ) );
171 }
172 
173 // Cancel button: no runIDs returned
175 {
176  runIDs.clear();
177 
178  reject();
179  close();
180 }
181 
182 // Accept button: set up to return runs and associated model information
184 {
185 DbgLv(1) << "SE:accepted()";
186  QList< QListWidgetItem* > selitems = lw_data->selectedItems();
187 
188  if ( selitems.size() == 0 )
189  {
190  QMessageBox::information( this,
191  tr( "No Data Selected" ),
192  tr( "You have not selected any data.\nSelect or Cancel" ) );
193  return;
194  }
195 
196  QString slines = te_status->toPlainText() +
197  tr( "\nScanning models for selected run(s)..." );
198  te_status->setText( slines );
199  qApp->processEvents();
200 DbgLv(1) << "SE: slines" << slines;
201  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
202  runIDs.clear();
203 
204  // Get and return runIDs from selected edit items
205  for ( int ii = 0; ii < selitems.size(); ii++ )
206  {
207  QListWidgetItem* lwi_data = selitems.at( ii );
208  QString clabel = lwi_data->text();
209 DbgLv(1) << "SE: ii clabel" << ii << clabel;
210 
211  runIDs << clabel;
212  }
213 DbgLv(1) << "SE: runID0" << runIDs[0];
214 
215  // Scan models to build descriptions for selected runs
216  if ( sel_db )
218  else
220 
221  QApplication::restoreOverrideCursor();
222  qApp->processEvents();
223  int namodel = wDescrs.size();
224 
225  if ( namodel == 0 )
226  {
227  QMessageBox::warning( this,
228  tr( "No Implied Models" ),
229  tr( "There were no Discrete Distributions associated\n"
230  " with the selected run(s).\n"
231  "Cancel or select a new set of runs." ) );
232  return;
233  }
234 
235  mDescrs << wDescrs; // Append new model descriptions
236 
237  accept(); // Signal that selection was accepted
238  close();
239 }
240 
241 // Scan database for run sets
243 {
244  US_Passwd pw;
245  US_DB2 db( pw.getPasswd() );
246  count_allr = 0;
247  count_list = 0;
248  count_seld = 0;
249  rlabels.clear();
250  runIDs .clear();
251 
252  if ( db.lastErrno() != US_DB2::OK )
253  {
254  QMessageBox::critical( this,
255  tr( "DB Connection Problem" ),
256  tr( "There was an error connecting to the database:\n" )
257  + db.lastError() );
258  return;
259  }
260 
261  QStringList query;
262  QString invID = QString::number( US_Settings::us_inv_ID() );
263 QTime timer;
264 timer.start();
265 
266  // Scan experiments. getting run and experiment IDs
267  query.clear();
268  query << "get_experiment_desc" << invID;
269  db.query( query );
270 
271  while ( db.next() )
272  { // Get a list of all runs in the database
273  QString runid = db.value( 1 ).toString();
274 DbgLv(1) << "ScDB: runid" << runid;
275 
276  if ( ! runIDs.contains( runid ) )
277  {
278  count_allr++;
279  rlabels << runid; // Save run ID to list of selectable runs
280  runIDs << runid; // Save run ID to list of total runs
281  }
282  }
283 DbgLv(1) << "ScDB:count_allr" << count_allr;
284 DbgLv(1) << "ScDB:scan time(1)" << timer.elapsed();
285 
286  mcounted = false;
287 DbgLv(1) << "ScDB:counts: runIDs" << runIDs.count() << "rlabels" << rlabels.count();
288 DbgLv(1) << "ScDB:scan time(9)" << timer.elapsed();
289 }
290 
291 
292 // Scan local disk for edit sets
294 {
295 QTime timer;
296 timer.start();
297  QMap< QString, QString > ddmap;
298  QStringList mEdtIDs;
299  QString mdir = US_Settings::dataDir() + "/models";
300  QStringList mfilt( "M*.xml" );
301  QStringList f_names = QDir( mdir )
302  .entryList( mfilt, QDir::Files, QDir::Name );
303 
304  for ( int ii = 0; ii < f_names.size(); ii++ )
305  { // Examine each model file
306  QString fname( mdir + "/" + f_names[ ii ] );
307  QFile m_file( fname );
308 
309  if ( ! m_file.open( QIODevice::ReadOnly | QIODevice::Text ) )
310  continue;
311 
312  QXmlStreamReader xml( &m_file );
313 
314  while( ! xml.atEnd() )
315  {
316  xml.readNext();
317 
318  if ( xml.isStartElement() )
319  {
320  if ( xml.name() == "model" )
321  { // Get the description and GUID of model and test it
322  QXmlStreamAttributes attr = xml.attributes();
323  QString mdesc = attr.value( "description" ).toString();
324  QString ddesc = attr.value( "dataDescrip" ).toString();
325  QString mGUID = attr.value( "modelGUID" ).toString();
326  QString eGUID = attr.value( "editGUID" ).toString();
327  int kk = mdesc.lastIndexOf( ".model" );
328  mdesc = ( kk < 1 ) ? mdesc : mdesc.left( kk );
329  QString runid = mdesc.section( ".", 0, -3 );
330  // Skip the model if it has no valid runID part
331  if ( runid.isEmpty() || runid.length() < 2 ) continue;
332 
333  if ( ddesc.isEmpty() )
334  {
335  if ( ddmap.contains( eGUID ) )
336  ddesc = ddmap[ eGUID ];
337  }
338  else
339  {
340  if ( !ddmap.contains( eGUID ) )
341  ddmap[ eGUID ] = ddesc;
342  }
343 
344  // Modify the description field of any MonteCarlo
345  if ( mdesc.contains( "-MC" ) )
346  {
347  kk = mdesc.indexOf( "_mc0" );
348  if ( kk > 0 )
349  {
350  int niters = attr.value( "MCIteration" ).toString()
351  .toInt();
352  mdesc = QString( mdesc ).left( kk ) +
353  QString().sprintf( "_mcN%03d", niters ) +
354  QString( mdesc ).mid( kk + 7 );
355  }
356  }
357 
358  // Save run ID and model string of RunID+GUID+Description
359  QString odesc = runid + "\t" + mGUID + "\t" + mdesc
360  + "\t" + ddesc;
361  mRunIDs << runid;
362  mEdtIDs << eGUID;
363  wDescrs << odesc;
364 if((dbg_level>0) && (!mdesc.contains("-MC_")||mdesc.contains("_mc")))
365  DbgLv(1) << "ScLo: odesc" << odesc;
366  }
367 
368  if ( xml.name() == "analyte" )
369  break;
370  }
371  }
372  }
373 
374  // Do another pass on model descriptions to insure data description
375  // gets used for all models with the same edit GUID
376  for ( int mm = 0; mm < wDescrs.count(); mm++ )
377  {
378  QString mdesc = wDescrs[ mm ];
379  QString ddesc = mdesc.section( "\t", 3, 3 );
380 
381  if ( ddesc.isEmpty() )
382  {
383  QString eGUID = mEdtIDs[ mm ];
384  if ( ddmap.contains( eGUID ) )
385  {
386  ddesc = ddmap[ eGUID ];
387 DbgLv(1) << "ScLo: mm" << mm << "eGUID" << eGUID << "new ddesc" << ddesc;
388  mdesc = mdesc.section( "\t", 0, 2 ) + "\t" + ddesc;
389  wDescrs.replace( mm, mdesc );
390  }
391  }
392  }
393 
394 DbgLv(1) << "ScLo:scan time(1)" << timer.elapsed();
395 
396  QString rdir = US_Settings::resultDir();
397  QStringList aucdirs = QDir( rdir ).entryList(
398  QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name );
399 DbgLv(1) << "ScLo:rdir" << rdir << "aucdir count" << aucdirs.count();
400 
401  QStringList aucfilt( "*.auc" );
402  QStringList datfilt;
403  count_allr = 0;
404  count_list = 0;
405  count_seld = 0;
406  runIDs .clear();
407  rlabels.clear();
408 
409  for ( int ii = 0; ii < aucdirs.count(); ii++ )
410  { // Examine all the AUC files that exist locally
411  QString subdir = rdir + "/" + aucdirs.at( ii );
412  QStringList aucfiles = QDir( subdir ).entryList(
413  aucfilt, QDir::Files, QDir::Name );
414 DbgLv(1) << "ScLo: subdir" << subdir << "aucfiles count" << aucfiles.count();
415 
416  if ( aucfiles.count() < 1 )
417  continue;
418 
419  QString aucfbase = aucfiles.at( 0 );
420  QString runID = aucfbase.section( ".", 0, -6 );
421  count_allr++; // Bump the count of all runIDs examined
422  runIDs << runID;
423 
424  if ( mRunIDs.contains( runID ) )
425  { // If this runID is represented for models, it is selectable
426  count_list++; // Bump the count of runIDs to list
427  rlabels << runID; // Save selectable runID
428  }
429 DbgLv(1) << "ScLo: count_allr" << count_allr << "count_list" << count_list
430  << " runID" << runID;
431  }
432 DbgLv(1) << "ScLo:rlabels count" << count_list << rlabels.count();
433 DbgLv(1) << "ScLo:scan time(9)" << timer.elapsed();
434  mcounted = true;
435 }
436 
437 
438 // Investigator button clicked: get investigator from dialog
440 {
441  int invID = US_Settings::us_inv_ID();
442  US_Investigator* dialog = new US_Investigator( true, invID );
443 
444  connect( dialog, SIGNAL( investigator_accepted( int ) ),
445  SLOT( update_person( int ) ) );
446 
447  dialog->exec();
448 }
449 
450 // Slot to handle accept in investigator dialog
452 {
453  QString number = ( ID > 0 ) ? QString::number( ID ) + ": " : "";
454  le_invest->setText( number + US_Settings::us_inv_name() );
455 
456 DbgLv(1) << "UpdP: ID" << ID << "invID" << US_Settings::us_inv_ID();
457  list_data();
458  count_models();
459 DbgLv(1) << "UpdP: rlabels count" << rlabels.count();
460 }
461 
462 // Slot to update disk/db selection
464 {
465  emit changed( isDB );
466 
467  sel_db = isDB;
468  list_data();
469  count_models();
470 
471  pb_invest->setEnabled( isDB );
472  setWindowTitle( tr( "Select Run ID(s) for Discrete Distributions (%1)" )
473  .arg( sel_db ? "DB" : "Local" ) );
474 }
475 
476 // Slot to record a change in list item selection
478 {
479  QList< QListWidgetItem* > selitems = lw_data->selectedItems();
480  int kseld = selitems.size();
481  bool counted = mcounted;
482 
483  // If need be, count models and refresh the list
484  if ( ! counted )
485  {
486  QString slabel = selitems[ 0 ]->text();
487  selitems.clear();
488  lw_data->disconnect();
489 
490 DbgLv(1) << "sChg: count_models()";
491  count_models();
492 
493  count_list = rlabels.count();
494 
495 DbgLv(1) << "sChg: count_list" << count_list << "kseld" << kseld;
496  selitems = lw_data->findItems( slabel, Qt::MatchFixedString );
497  kseld = selitems.size();
498  if ( kseld > 0 )
499  lw_data->setCurrentItem( selitems[ 0 ] );
500  connect( lw_data, SIGNAL( itemSelectionChanged() ),
501  this, SLOT ( selectionChanged() ) );
502  }
503 
504  count_seld = kseld;
505  te_status->setText(
506  tr( "%1 scanned run IDs were used to derive the list. Of these,\n"
507  "%2 have associated distributions (models), and\n"
508  "%3 %4 currently selected for combination plot components." )
509  .arg( count_allr ).arg( count_list ).arg( count_seld )
510  .arg( count_seld != 1 ? tr( "runs are" ) : tr( "run is" ) ) );
511 }
512 
513 // Scan database for models associated with run sets
515 {
516  US_Passwd pw;
517  US_DB2 db( pw.getPasswd() );
518 
519  if ( db.lastErrno() != US_DB2::OK )
520  {
521  QMessageBox::information( this,
522  tr( "DB Connection Problem" ),
523  tr( "There was an error connecting to the database:\n" )
524  + db.lastError() );
525  return;
526  }
527 
528  QStringList mmIDs; // Model modelIDs
529  QStringList mmGUIDs; // Model modelGUIDs
530  QStringList meIDs; // Model editIDs;
531  QVector< QString > mmDescs; // Model descriptions
532  QMap< QString, QString > ddmap; // editID,dataDescr map
533 
534  QStringList query;
535  QString invID = QString::number( US_Settings::us_inv_ID() );
536  int ntmodel = 0;
537  int nmodel = 0;
538 
539 QTime timer;
540 timer.start();
541  // Accumulate model information for runs present
542  for ( int rr = 0; rr < runIDs.count(); rr++ )
543  {
544  QString runid = runIDs[ rr ];
545  query.clear();
546  query << "get_model_desc_by_runID" << invID << runid;
547  db.query( query );
548 
549  while( db.next() )
550  {
551  QString mdlid = db.value( 0 ).toString();
552  QString mdlGid = db.value( 1 ).toString();
553  QString mdesc = db.value( 2 ).toString();
554  QString edtid = db.value( 6 ).toString();
555  int kk = mdesc.lastIndexOf( ".model" );
556  mdesc = ( kk < 1 ) ? mdesc : mdesc.left( kk );
557  mmIDs << mdlid;
558  mmGUIDs << mdlGid;
559  meIDs << edtid;
560  mmDescs << mdesc;
561  nmodel++;
562  }
563 DbgLv(1) << "ScMd: runid" << runid << "nmodel" << nmodel;
564 
565  // Repeat the scan for "global-<run>%" variation
566  QString grunid = "global-" + runid + "%";
567  query.clear();
568  query << "get_model_desc_by_runID" << invID << grunid;
569  db.query( query );
570 
571  while( db.next() )
572  {
573  QString mdlid = db.value( 0 ).toString();
574  QString mdlGid = db.value( 1 ).toString();
575  QString mdesc = db.value( 2 ).toString();
576  QString edtid = db.value( 6 ).toString();
577  int kk = mdesc.lastIndexOf( ".model" );
578  mdesc = ( kk < 1 ) ? mdesc : mdesc.left( kk );
579  mmIDs << mdlid;
580  mmGUIDs << mdlGid;
581  meIDs << edtid;
582  mmDescs << mdesc;
583  nmodel++;
584  }
585 DbgLv(1) << "ScMd: runid" << runid << "nmodel" << nmodel;
586  }
587 DbgLv(1) << "ScMd:scan time(1)" << timer.elapsed();
588 
589  query.clear();
590  query << "count_models" << invID;
591  ntmodel = db.functionQuery( query );
592 DbgLv(1) << "ScMd: ntmodel" << ntmodel << "nmodel" << nmodel;
593 DbgLv(1) << "ScMd:scan time(2)" << timer.elapsed();
594 int m=nmodel-1;
595 if ( m>1 ) {
596 DbgLv(1) << "ScMd: 0: id,gid,eid,desc" << mmIDs[0] << mmGUIDs[0] << meIDs[0] << mmDescs[0];
597 DbgLv(1) << "ScMd: m: id,gid,eid,desc" << mmIDs[m] << mmGUIDs[m] << meIDs[m] << mmDescs[m]; }
598 
599  // Scan all saved models from the end back, saving any
600  // cell description by edit ID
601  for ( int mm = nmodel - 1; mm >=0; mm-- )
602  {
603  QString medtid = meIDs[ mm ];
604 
605  if ( ddmap.contains( medtid ) ) continue; // Skip if already mapped
606 
607  // Not yet mapped, so find any cell description in the model XML
608  QString mdlid = mmIDs[ mm ];
609  query.clear();
610  query << "get_model_info" << mdlid;
611  db.query( query );
612  db.next();
613  QString mxml = db.value( 2 ).toString();
614  int kk = mxml.indexOf( "dataDescrip=" );
615 DbgLv(1) << "ScMd: mm kk medtid" << mm << kk << medtid;
616 
617  if ( kk > 0 )
618  { // We have found the data description, so map it
619  QString ddesc = mxml.mid( kk + 13 );
620  kk = ddesc.indexOf( "\"" );
621  ddesc = ddesc.left( kk );
622  ddmap[ medtid ] = ddesc;
623  }
624  }
625 DbgLv(1) << "ScMd:scan time(3)" << timer.elapsed();
626 
627  // Do one more pass through all the models, completing
628  // the model descriptions
629  for ( int mm = 0; mm < nmodel; mm++ )
630  {
631  QString mID = mmIDs [ mm ];
632  QString mGUID = mmGUIDs[ mm ];
633  QString mdesc = mmDescs[ mm ];
634  QString meID = meIDs [ mm ];
635  QString ddesc = ddmap.contains( meID ) ? ddmap[ meID ] : "";
636  QString runid = mdesc.section( ".", 0, -3 );
637  QString odesc = runid + "\t" + mGUID + "\t" + mdesc + "\t" + ddesc;
638  wDescrs << odesc;
639 DbgLv(1) << "ScMd: mm meID" << mm << meID << "ddesc" << ddesc;
640  }
641 
642 DbgLv(1) << "ScMd:scan time(9)" << timer.elapsed();
643 }
644 
645 // Scan local disk for models associated with run sets
647 {
648  QStringList aDescrs = wDescrs;
649  wDescrs.clear();
650 
651  // Model scan was already done for local. All we need to do
652  // now is limit the descriptions to runIDs selected.
653  for ( int mm = 0; mm < aDescrs.count(); mm++ )
654  {
655  QString mdesc = aDescrs[ mm ];
656  QString runid = mdesc.section( "\t", 0, 0 );
657  QString grunid = "global-" + runid;
658 
659  if ( runIDs.contains( runid ) || runIDs.startsWith( grunid ) )
660  wDescrs << mdesc;
661  }
662 DbgLv(1) << "ScMl:counts: aDescrs" << aDescrs.count() << "wDescrs" << wDescrs.count();
663 }
664 
665 // Count models for database case
667 {
668  if ( mcounted || ! sel_db ) return;
669 
670  US_Passwd pw;
671  US_DB2 db( pw.getPasswd() );
672  rmodKnts.clear();
673  QStringList query;
674  QString invID = QString::number( US_Settings::us_inv_ID() );
675  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
676  te_status->setText( tr( "Scanning runs for model counts..." ) );
677  qApp->processEvents();
678 QTime timer;
679 timer.start();
680 
681  // Build run edit and run model counts lists
682  for ( int rr = 0; rr < runIDs.count(); rr++ )
683  {
684  QString runid = runIDs[ rr ];
685  query.clear();
686  query << "count_models_by_runID" << invID << runid;
687  int nrmods = db.functionQuery( query );
688  QString grunid = "global-" + runid + "%";
689  query.clear();
690  query << "count_models_by_runID" << invID << grunid;
691  nrmods += db.functionQuery( query );
692 
693  rmodKnts << nrmods;
694  }
695 DbgLv(1) << "KntM: counts: runIDs rmodKnts"
696  << runIDs.count() << rmodKnts.count();
697 DbgLv(1) << "KntM:scan time(2)" << timer.elapsed();
698 
699  // Reduce the run list to only those with associated models
700  lw_data->clear();
701  rlabels .clear();
702 
703  for ( int rr = 0; rr < runIDs.count(); rr++ )
704  {
705  if ( rmodKnts[ rr ] > 0 )
706  {
707  QString clabel = runIDs[ rr ];
708  rlabels << clabel;
709  lw_data->addItem( new QListWidgetItem( clabel ) );
710  }
711  }
712 DbgLv(1) << "KntM:scan time(3)" << timer.elapsed();
713 
714  mcounted = true;
715  QApplication::restoreOverrideCursor();
716  count_list = lw_data->count();
717  count_seld = lw_data->selectedItems().size();
718  te_status->setText(
719  tr( "%1 scanned run IDs were used to derive the list. Of these,\n"
720  "%2 have associated distributions (models), and\n"
721  "%3 %4 currently selected for combination plot components." )
722  .arg( count_allr ).arg( count_list ).arg( count_seld )
723  .arg( count_seld != 1 ? tr( "runs are" ) : tr( "run is" ) ) );
724  qApp->processEvents();
725 }
726