UltraScan III
us_model_loader.cpp
Go to the documentation of this file.
1 
3 #include "us_model_loader.h"
4 #include "us_select_edits.h"
5 #include "us_settings.h"
6 #include "us_gui_settings.h"
7 #include "us_matrix.h"
8 #include "us_investigator.h"
9 #include "us_passwd.h"
10 #include "us_db2.h"
11 #include "us_editor.h"
12 
13 // Main constructor for loading a single model
14 US_ModelLoader::US_ModelLoader( bool dbSrc, QString& search,
15  US_Model& amodel, QString& adescr, const QString eGUID )
16  :US_WidgetsDialog( 0, 0 ), loadDB( dbSrc ), dsearch( search ),
17  omodel( amodel ), odescr( adescr ), omodels( wmodels ), odescrs( mdescrs ),
18  runIDs( wrunIDs )
19 {
20  multi = false;
21  editGUID = eGUID;
22 
23  build_dialog();
24 }
25 
26 // Alternate constructor for loading a single model (with runIDs)
27 US_ModelLoader::US_ModelLoader( bool dbSrc, QString& search,
28  US_Model& amodel, QString& adescr, QStringList& arunIDs )
29  :US_WidgetsDialog( 0, 0 ), loadDB( dbSrc ), dsearch( search ),
30  omodel( amodel ), odescr( adescr ), omodels( wmodels ), odescrs( mdescrs ),
31  runIDs( arunIDs )
32 {
33  multi = false;
34  editGUID = "";
35 
36  build_dialog();
37 }
38 
39 // Alternate constructor that allows loading multiple models
40 US_ModelLoader::US_ModelLoader( bool dbSrc, QString& search,
41  QList< US_Model >& amodels, QStringList& adescrs,
42  QStringList& arunIDs )
43  :US_WidgetsDialog( 0, 0 ), loadDB( dbSrc ), dsearch( search ),
44  omodel( model ), odescr( search ), omodels( amodels ), odescrs( adescrs ),
45  runIDs( arunIDs )
46 {
47  multi = true;
48  editGUID = "";
49 
50  build_dialog();
51 }
52 
53 // Alternate constructor that allows loading multiple models (no runIDs list)
54 US_ModelLoader::US_ModelLoader( bool dbSrc, QString& search,
55  QList< US_Model >& amodels, QStringList& adescrs )
56  :US_WidgetsDialog( 0, 0 ), loadDB( dbSrc ), dsearch( search ),
57  omodel( model ), odescr( search ), omodels( amodels ), odescrs( adescrs ),
58  runIDs( wrunIDs )
59 {
60  multi = true;
61  editGUID = "";
62 
63  build_dialog();
64 }
65 
66 // Main shared method to build the model loader dialog
68 {
69 qDebug() << "ML:BD: runIDs empty" << runIDs.isEmpty();
70  setWindowTitle( multi ? tr( "Load Distribution Model(s)" )
71  : tr( "Load Distribution Model" ) );
72  setPalette( US_GuiSettings::frameColor() );
73  setMinimumSize( 320, 300 );
74 
75  model_descriptions.clear();
76  model_descrs_recs .clear();
77 
78  // Main layout
79  QVBoxLayout* main = new QVBoxLayout( this );
80  main->setContentsMargins( 2, 2, 2, 2 );
81  main->setSpacing ( 2 );
82 
83  // Top layout: buttons and fields above list widget
84  QGridLayout* top = new QGridLayout( );
85  singprev = false;
86  dbP = NULL;
87 
88  int iload = loadDB ? US_Disk_DB_Controls::DB
90  dkdb_cntrls = new US_Disk_DB_Controls( iload );
91 
92  connect( dkdb_cntrls, SIGNAL( changed( bool ) ),
93  this, SLOT( select_diskdb() ) );
94 
95  QPalette gray = US_GuiSettings::editColor();
96  gray.setColor( QPalette::Base, QColor( 0xe0, 0xe0, 0xe0 ) );
97 
98  pb_investigator = us_pushbutton( tr( "Select Investigator" ) );
99  connect( pb_investigator, SIGNAL( clicked() ),
100  this, SLOT( get_person() ) );
101 
102  int inv = US_Settings::us_inv_ID();
103  QString number = ( inv > 0 ) ? QString::number( inv ) + ": " : "";
105  0, true );
106 
107  pb_filtmodels = us_pushbutton( tr( "Search" ) );
108  connect( pb_filtmodels, SIGNAL( clicked() ),
109  this, SLOT( list_models() ) );
110 
111  QString edGUID = editGUID;
112  do_single = false;
113  can_edit = !editGUID.isEmpty();
114  can_run = ( runIDs.size() > 0 );
115  do_edit = can_edit;
116  do_run = can_run;
117  do_manual = false;
118  do_unasgn = false;
119 
120  if ( ! dsearch.isEmpty() )
121  { // If an input search string is given, look for special flags
122  do_single = dsearch.contains( "=s" );
123  do_manual = dsearch.contains( "=m" );
124  do_unasgn = dsearch.contains( "=u" );
125 
126  if ( ( do_manual || do_unasgn ) && can_edit )
127  {
128  do_edit = ( edGUID == "1" );
129  }
130 
131  dsearch = dsearch.replace( "=e", "" ).simplified();
132  dsearch = dsearch.replace( "=s", "" ).simplified();
133  dsearch = dsearch.replace( "=m", "" ).simplified();
134  dsearch = dsearch.replace( "=u", "" ).simplified();
135  }
136 qDebug() << "Bld: single" << do_single << " manual" << do_manual
137  << " edit" << do_edit << " unasgn" << do_unasgn << " dsearch" << dsearch;
138 
139  le_mfilter = us_lineedit( dsearch, -1, false );
140  connect( le_mfilter, SIGNAL( returnPressed() ),
141  this, SLOT( list_models() ) );
142  connect( le_mfilter, SIGNAL( textChanged( const QString& ) ),
143  this, SLOT( msearch( const QString& ) ) );
144 
145  int row = 0;
146  top->addLayout( dkdb_cntrls, row++, 0, 1, 2 );
147  top->addWidget( pb_investigator, row, 0 );
148  top->addWidget( le_investigator, row++, 1 );
149  top->addWidget( pb_filtmodels, row, 0 );
150  top->addWidget( le_mfilter, row++, 1 );
151 
152  main->addLayout( top );
153 
154  // List widget to show model choices
155  lw_models = new US_ListWidget;
156 
157  if ( multi )
158  lw_models->setSelectionMode( QAbstractItemView::ExtendedSelection );
159 
160  lw_models->installEventFilter( this );
161  main->addWidget( lw_models );
162 
163  // Advanced Model List Options
164  QGridLayout* advtypes = new QGridLayout;
165  QLabel* lb_advopts = us_banner( tr( "Advanced Model List Options" ) );
166  lb_advopts->setMaximumHeight( le_mfilter->height() );
167 
168  QGridLayout* lo_single = us_checkbox( tr( "Monte Carlo Singles" ),
169  ck_single, do_single );
170  QGridLayout* lo_edit = us_checkbox( tr( "Filter by Edit/Run" ),
171  ck_edit, do_edit || do_run );
172  QGridLayout* lo_unasgn = us_checkbox( tr( "Edit-Unassigned Only" ),
174  int arow = 0;
175  advtypes->addWidget( lb_advopts, arow++, 0, 1, 3 );
176  advtypes->addLayout( lo_single, arow, 0, 1, 1 );
177  advtypes->addLayout( lo_edit, arow, 1, 1, 1 );
178  advtypes->addLayout( lo_unasgn, arow++, 2, 1, 1 );
179 
180  connect( ck_single, SIGNAL( toggled ( bool ) ),
181  SLOT ( change_single( bool ) ) );
182  connect( ck_edit, SIGNAL( toggled ( bool ) ),
183  SLOT ( change_edit ( bool ) ) );
184  connect( ck_unasgn, SIGNAL( toggled ( bool ) ),
185  SLOT ( change_unasgn( bool ) ) );
186 
187  main->addLayout( advtypes );
188 
189  // Button Row
190  QHBoxLayout* buttons = new QHBoxLayout;
191 
192  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
193  connect( pb_help, SIGNAL( clicked() ), this, SLOT( help() ) );
194  buttons->addWidget( pb_help );
195 
196  QPushButton* pb_cancel = us_pushbutton( tr( "Cancel" ) );
197  connect( pb_cancel, SIGNAL( clicked() ), this, SLOT( cancelled() ) );
198  buttons->addWidget( pb_cancel );
199 
200  QPushButton* pb_accept = us_pushbutton( tr( "Accept" ) );
201  connect( pb_accept, SIGNAL( clicked() ), this, SLOT( accepted() ) );
202  buttons->addWidget( pb_accept );
203 
204  main->addLayout( buttons );
205 
206  db_id1 = -2; // flag all_models start,end IDs unknown
207  db_id2 = -2;
208 
209  // Trigger models list from db or disk source
210  select_diskdb();
211 }
212 
213 // Load model data by index
214 int US_ModelLoader::load_model( US_Model& model, int index )
215 {
216  int rc = 0;
217  loadDB = dkdb_cntrls->db();
218 
219  model.components.clear();
220  model.associations.clear();
221 
222  if ( loadDB )
223  {
224  if ( dbP == NULL )
225  {
226  US_Passwd pw;
227  dbP = new US_DB2( pw.getPasswd() );
228 
229  if ( ( rc = dbP->lastErrno() ) != US_DB2::OK )
230  {
231  QMessageBox::information( this,
232  tr( "DB Connection Problem" ),
233  tr( "There was an error connecting to the database:\n" )
234  + dbP->lastError() );
235  return rc;
236  }
237  }
238 
239 qDebug() << "LdM: index" << index << "descsz" << model_descriptions.size();
240  QString modelID = model_descriptions[ index ].DB_id;
241 
242  rc = model.load( modelID, dbP );
243 qDebug() << "LdM: model load rc" << rc;
244  }
245 
246  else
247  {
248  QString filename = model_descriptions[ index ].filename;
249 
250  rc = model.load( filename );
251 qDebug() << "LdM: Dk filename" << filename;
252  }
253 qDebug() << "LdM: description" << model_descriptions[index].description;
254 
255  if ( do_single )
256  { // If selecting single from MC composite, break it out now
257  US_Model model2 = model;
258  QString sdescr = model_descriptions[ index].description;
259  QStringList xmls;
260  int nxmls = model2.mc_iter_xmls( xmls );
261 
262  for ( int jj = 0; jj < nxmls; jj++ )
263  { // Loop through iteration contents looking for match
264  QString mcont = xmls[ jj ];
265  int kk = mcont.indexOf( "description=" );
266  QString mdescr = QString( mcont ).mid( kk, 100 )
267  .section( '"', 1, 1 );
268  if ( mdescr == sdescr )
269  { // Found a matching description: load the single and break
270  model.load_string( mcont );
271 qDebug() << "LdM: match at jj" << jj << "ncomp" << model.components.size();
272  break;
273  }
274  }
275  }
276 
277  return rc;
278 }
279 
280 // Return a description string for a model by index
281 QString US_ModelLoader::description( int index )
282 {
283  QString sep = ";"; // use semi-colon as separator
284 
285  if ( model_descriptions[ index ].description.contains( sep ) )
286  sep = "^"; // use carat if semi-colon already in use
287 
288  // Create and return a composite description string
289  QString cdesc = sep + model_descriptions[ index ].description
290  + sep + model_descriptions[ index ].filename
291  + sep + model_descriptions[ index ].modelGUID
292  + sep + model_descriptions[ index ].DB_id
293  + sep + model_descriptions[ index ].editGUID;
294 
295  if ( model_descriptions[ index ].iterations > 1 )
296  cdesc = cdesc + sep
297  + QString::number( model_descriptions[ index ].iterations );
298 
299  return cdesc;
300 }
301 
302 // Slot to respond to change in disk/db radio button select
304 {
305  // Disable investigator field if from disk or normal user; Enable otherwise
306  loadDB = dkdb_cntrls->db();
307  dbP = loadDB ? dbP : NULL;
308  pb_investigator->setEnabled( loadDB && ( US_Settings::us_inv_level() > 0 ) );
309 
310  // Signal model-loader caller that Disk/DB source has changed
311  emit changed( loadDB );
312 
313  // Show the list of available models
314  list_models();
315 }
316 
317 // Investigator button clicked: get investigator from dialog
319 {
320  int invID = US_Settings::us_inv_ID();
321  US_Investigator* dialog = new US_Investigator( true, invID );
322 
323  connect( dialog,
324  SIGNAL( investigator_accepted( int ) ),
325  SLOT( update_person( int ) ) );
326 
327  dialog->exec();
328 }
329 
330 // Slot to handle accept in investigator dialog
332 {
333  QString number = ( ID > 0 ) ? QString::number( ID ) + ": " : "";
334  le_investigator->setText( number + US_Settings::us_inv_name() );
335 
336  list_models();
337 }
338 
339 // List model choices (disk/db and possibly filtered by search text)
341 {
342 qDebug() << "LIST_MODELS";
343 QDateTime time0=QDateTime::currentDateTime();
344 QDateTime time1=QDateTime::currentDateTime();
345 QDateTime time2=QDateTime::currentDateTime();
346  const QString uaGUID( "00000000-0000-0000-0000-000000000000" );
347  QString mfilt = le_mfilter->text();
348  le_mfilter->disconnect( SIGNAL( textChanged( const QString& ) ) );
349  bool listdesc = !mfilt.isEmpty(); // description filtered?
350  bool listedit = do_edit || do_run; // edit filtered?
351  bool listsing = do_single; // show singles of MC groups?
352  bool listall = !listdesc; // unfiltered by description?
353  QRegExp mpart = QRegExp( ".*" + mfilt + ".*", Qt::CaseInsensitive );
354  model_descriptions.clear(); // clear model descriptions
355 qDebug() << "LM: desc single edit" << listdesc << listsing << listedit
356  << "editGUID" << editGUID << "nruns" << runIDs.size();
357  int kmmnew = 0;
358  int kmmold = 0;
359  int kmmmod = 0;
360 
361  if ( listdesc )
362  { // filter is not empty
363  listedit = listedit | do_edit;
364 
365  if ( listedit && ! can_edit && ! can_run )
366  { // disallow edit filter if no edit GUID and no runs have been given
367  QMessageBox::information( this,
368  tr( "Edit GUID Problem" ),
369  tr( "No EditGUID/runIDs given.\nEdit filter turned off." ) );
370  listedit = false;
371  listdesc = listsing;
372  listall = !listdesc;
373  }
374 
375  if ( listsing )
376  { // if showing MC singles, re-check for filtering
377  if ( !singprev )
378  db_id1 = -2; // flag re-list when list-singles flag changes
379  }
380 
381  else if ( singprev )
382  db_id1 = -2; // flag re-list when list-singles flag changes
383  }
384 qDebug() << "listall" << listall << "do_manual" << do_manual;
385 qDebug() << " listdesc listedit listsing" << listdesc << listedit << listsing;
386 
387  if ( loadDB )
388  { // Model list from DB
389  if ( dbP == NULL )
390  {
391  US_Passwd pw;
392  dbP = new US_DB2( pw.getPasswd() );
393 
394  if ( dbP->lastErrno() != US_DB2::OK )
395  {
396  QMessageBox::information( this,
397  tr( "DB Connection Problem" ),
398  tr( "There was an error connecting to the database:\n" )
399  + dbP->lastError() );
400  return;
401  }
402  }
403 
404  QStringList query;
405  QString invID = le_investigator->text().section( ":", 0, 0 );
406 
407  int countRD = model_descrs_recs .size();
408  int countSD = model_descrs_sings.size();
409  int kid1 = -3;
410  int kid2 = -3;
411 qDebug() << " rd count" << countRD;
412 // query << "count_models" << invID;
413 // int countDB = dbP->statusQuery( query );
414 //qDebug() << " db count" << countDB;
415  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
416 
417  if ( countRD > 0 && countRD == countSD )
418  {
419  kid1 = model_descrs_recs[ 0 ].DB_id.toInt();
420  kid2 = model_descrs_recs[ countRD - 1 ].DB_id.toInt();
421  }
422 qDebug() << " kid1 kid2" << kid1 << kid2;
423 qDebug() << " db_id1 db_id2" << db_id1 << db_id2;
424 
425  if ( countRD == 0 || kid1 != db_id1 || kid2 != db_id2 )
426  { // only re-fetch all-models list if we don't yet have it
427  db_id1 = kid1; // save start,end all_models IDs
428  db_id2 = kid2;
429 qDebug() << " db_id1 db_id2" << db_id1 << db_id2;
430  model_descrs_recs.clear();
431  query.clear();
432  int nruns = runIDs.size();
433  QString editID = editGUID;
434 
435  if ( nruns == 0 && ! editGUID.isEmpty() )
436  {
437  if ( editID != "1" )
438  {
439  query.clear();
440  query << "get_editID" << editGUID;
441  dbP->query( query );
442  dbP->next();
443  editID = dbP->value( 0 ).toString();
444  }
445  }
446 qDebug() << " edit GUID,ID" << editGUID << editID;
447 
448  int kruns = listedit ? qMax( nruns, 1 ) : 1;
449 qDebug() << " kruns listedit" << kruns << listedit;
450 
451  for ( int ii = 0; ii < kruns; ii++ )
452  {
453 qDebug() << " ii kruns nruns" << ii << kruns << nruns;
454  query.clear();
455 time1=QDateTime::currentDateTime();
456 
457  if ( listedit && can_edit )
458  {
459  query << "get_model_desc_by_editID"
460  << invID << editID;
461  }
462 
463  else if ( listedit && can_run )
464  {
465  query << "get_model_desc_by_runID"
466  << invID << "%" + runIDs[ ii ] + "%";
467  }
468 
469  else if ( do_manual || do_unasgn )
470  query << "get_model_desc_by_editID" << invID << "1";
471 
472  else
473  query << "get_model_desc" << invID;
474 
475 qDebug() << " query" << query;
476  dbP->query( query );
477 qDebug() << " NumRows" << dbP->numRows();
478 time2=QDateTime::currentDateTime();
479 qDebug() << "Timing: get_model_desc" << time1.msecsTo(time2);
480 
481  while ( dbP->next() )
482  {
483  ModelDesc desc;
484  desc.DB_id = dbP->value( 0 ).toString();
485  desc.modelGUID = dbP->value( 1 ).toString();
486  desc.description = dbP->value( 2 ).toString();
487  desc.editGUID = dbP->value( 5 ).toString();
488 
489  desc.filename.clear();
490  desc.reqGUID = desc.description.section( ".", -2, -2 )
491  .section( "_", 0, 3 );
492  desc.iterations = ( desc.description.contains( "-MC" )
493  && desc.description.contains( "_mc" ) ) ? 1: 0;
494  bool skip_it = false;
495 
496  if ( desc.description.simplified().length() < 2 )
497  {
498  desc.description = " ( ID " + desc.DB_id
499  + tr( " : empty description )" );
500  }
501 //qDebug() << " desc" << desc.description << "DB_id" << desc.DB_id;
502 
503  if ( do_manual )
504  { // If MANUAL, select only type Manual
505  skip_it = ( desc.editGUID != uaGUID );
506 
507  if ( desc.description.contains( "2DSA" ) ||
508  desc.description.contains( "PCSA" ) ||
509  desc.description.contains( "GA" ) ||
510  desc.description.contains( "-GL" ) ||
511  desc.description.contains( "Custom" ) )
512  skip_it = true;
513 qDebug() << " (m)desc" << desc.description << "skip_it" << skip_it;
514  }
515 
516  else if ( do_unasgn )
517  { // If UnAssigned, select only type Manual/Custom/Global
518  skip_it = ( desc.editGUID != uaGUID );
519 qDebug() << " (u)desc" << desc.description << "skip_it" << skip_it;
520  }
521 
522  if ( skip_it )
523  continue;
524 
525 qDebug() << " desc.iters" << desc.iterations;
526  if ( desc.iterations > 0 )
527  { // Accumulate counts for MC models
528  kmmmod++;
529  int mcndx = desc.description.indexOf( "_mc" );
530 qDebug() << " mcndx" << mcndx << "descr" << desc.description;
531  if ( desc.description.contains( "_mcN" ) )
532  {
533  kmmnew++;
534  int nimods = QString( desc.description )
535  .mid( mcndx + 4, 3 ).toInt();
536  desc.iterations = nimods;
537 qDebug() << " desc.iters(nimods)" << desc.iterations;
538  }
539 
540  else if ( desc.description.contains( "_mc0001" ) )
541  kmmold++;
542  }
543 
544  model_descrs_recs << desc; // add to full models list
545  }
546  }
547 QDateTime time3=QDateTime::currentDateTime();
548 qDebug() << "a_m size" << model_descrs_recs.size()
549  << "m_d size" << model_descriptions.size();
550 
551  if ( !listsing )
552  records_list(); // Default: list based on model records
553 
554  else
555  singles_list(); // List expanded to include singles
556 QDateTime time4=QDateTime::currentDateTime();
557 qDebug() << " (2)m_d size" << model_descriptions.size();
558 qDebug() << "Timing: DB-read" << time0.msecsTo(time3) << time2.msecsTo(time3);
559 qDebug() << "Timing: Compress" << time3.msecsTo(time4) << time2.msecsTo(time4);
560  }
561 
562  QApplication::restoreOverrideCursor();
563  }
564 
565  else
566  { // Models from local disk files
567  QDir dir;
568  QString path = US_Settings::dataDir() + "/models";
569  if ( !dir.exists( path ) )
570  {
571  dir.mkpath( path );
572  }
573  dir = QDir( path );
574 
575  // Examine all "M*xml" files in models directory
576  QStringList filter( "M*.xml" );
577  QStringList f_names = dir.entryList( filter, QDir::Files, QDir::Name );
578 qDebug() << " md size" << model_descrs_recs.size();
579 qDebug() << " fn size" << f_names.size();
580 
581  if ( f_names.size() != model_descrs_recs.size() || !listsing )
582  { // only re-fetch all-models list if we don't yet have it
583  QXmlStreamAttributes attr;
584 
585  model_descrs_recs.clear();
586  int nruns = runIDs.size();
587 qDebug() << "nruns" << nruns << "editGUID" << editGUID;
588 
589  for ( int ii = 0; ii < f_names.size(); ii++ )
590  {
591  QString fname( path + "/" + f_names[ ii ] );
592 qDebug() << "fname" << f_names[ii] << "do_manual" << do_manual;
593  QFile m_file( fname );
594 
595  if ( !m_file.open( QIODevice::ReadOnly | QIODevice::Text ) )
596  continue;
597 
598  int nimods = 0;
599  QXmlStreamReader xml( &m_file );
600 
601  while ( ! xml.atEnd() )
602  { // Search XML elements until we find "model"
603  xml.readNext();
604 
605  if ( xml.isStartElement() && xml.name() == "model" )
606  { // Pick up model attributes for description
607  attr = xml.attributes();
608  QString edGUID = attr.value( "editGUID" ).toString();
609  QString descript = attr.value( "description" ).toString();
610  QString runID = QString( descript ).section( ".", 0, -4);
611  QString mCarl = attr.value( "monteCarlo" ).toString();
612  int iters = mCarl.toInt();
613  iters = descript.contains( "mcN" ) ? 1 : iters;
614 
615  // Skip save if filtering and edit/run mismatch
616  if ( ( do_edit && edGUID != editGUID ) ||
617  ( do_run && !runIDs.contains( runID ) ) )
618  continue;
619 
620 qDebug() << " nimods" << nimods << "edGUID" << edGUID << "iters" << iters;
621  if ( iters > 0 )
622  {
623  nimods++;
624  if ( nimods > 1 ) continue;
625  }
626 
627  ModelDesc desc;
628  desc.description = descript;
629  desc.modelGUID = attr.value( "modelGUID" ).toString();
630  desc.filename = fname;
631  desc.DB_id = "-1";
632  desc.editGUID = edGUID;
633  desc.reqGUID = attr.value( "requestGUID" ).toString();
634  desc.iterations = iters;
635  QString aType = attr.value( "analysisType" ).toString();
636  QString gType = attr.value( "globalType" ).toString();
637 
638  if ( desc.description.simplified().length() < 2 )
639  {
640  desc.description = " ( GUID " + desc.modelGUID.left( 8 ) +
641  "... : " + tr( "empty description )" );
642  }
643 //*DEBUG
644 //if (!listall) {
645 //qDebug() << " ddesc" << desc.description;
646 //qDebug() << " mpart" << mpart.pattern();
647 //qDebug() << " degid" << desc.editGUID;
648 //qDebug() << " edgid" << editGUID;
649 //}
650 //*DEBUG
651  if ( do_manual )
652  { // If MANUAL, select only type Manual
653  int iaType = aType.toInt();
654 //qDebug() << " iaType igType" << iaType << igType;
655  if ( iaType != US_Model::MANUAL )
656  continue;
657  }
658 
659  else if ( do_unasgn )
660  { // If UnAssigned, select only type Manual/Custom/Global
661  int iaType = aType.toInt();
662  int igType = gType.toInt();
663 //qDebug() << " iaType igType" << iaType << igType;
664  if ( iaType != US_Model::MANUAL &&
665  iaType != US_Model::CUSTOMGRID &&
666  iaType != US_Model::DMGA_CONSTR &&
667  igType != US_Model::GLOBAL &&
668  igType != US_Model::SUPERGLOBAL )
669  continue;
670  }
671 
672  if ( iters > 0 )
673  { // Accumulate counts for MC models
674  kmmmod++;
675  if ( desc.description.contains( "_mc0001" ) )
676  kmmold++;
677 qDebug() << " kmmmod" << kmmmod << "kmmold" << kmmold;
678 //if(kmmold==0) qDebug() << " desc=" << desc.description;
679  }
680 
681  model_descrs_recs << desc; // add to full models list
682 
683  if ( iters == 0 )
684  break;
685  }
686 
687  else if ( xml.isEndElement() && xml.name() == "ModelData" )
688  { // Handle end of XML for possible multi-model composite
689  if ( nimods > 1 )
690  { // If composite MC, get and delete last description
691  ModelDesc desc = model_descrs_recs.takeLast();
692  int mcndx = desc.description.indexOf( "_mc0" );
693  desc.description =
694  QString( desc.description ).left( mcndx )
695  + QString().sprintf( "_mcN%03i", nimods )
696  + QString( desc.description ).mid( mcndx + 7 );
697  desc.iterations = nimods;
698 
699  // Restore modified description to full models list
700  model_descrs_recs << desc;
701  kmmnew++;
702  kmmold--;
703  }
704  }
705  }
706 
707  m_file.close();
708  }
709 
710  if ( !listsing )
711  records_list(); // Default: list from model records
712 
713  else
714  singles_list(); // List expanded to include singles
715  }
716  db_id1 = -2; // Flag all_models start,end IDs unknown
717  db_id2 = -2;
718  }
719 
720  if ( kmmold > 0 )
721  {
722  QString msg = tr( "%1 MC model sets are old-style separate models\n"
723  "%2 MC models are new-style composite models\n"
724  "%3 total MC model records currently exist.\n"
725  "The old-style models should be converted\n"
726  " or deleted." )
727  .arg( kmmold).arg( kmmnew ).arg( kmmmod );
728  QMessageBox::information( this,
729  tr( "Deprecated MC Model Types Exist" ), msg );
730  }
731 
732  // possibly pare down models list based on search field
733 QDateTime time5=QDateTime::currentDateTime();
734 qDebug() << "Timing: Time5" << time0.msecsTo(time5) << time2.msecsTo(time5);
735 qDebug() << " (3)m_d_u size" << model_descrs_ufilt.size();
736 
737  if ( listall )
738  { // No filtering or filter by edit already done
739  for ( int jj = 0; jj < model_descrs_ufilt.size(); jj++ )
740  {
742  }
743  }
744 
745  else
746  { // Filter by model description sub-string
747  for ( int jj = 0; jj < model_descrs_ufilt.size(); jj++ )
748  {
749  if ( model_descrs_ufilt[ jj ].description.contains( mpart ) )
750  { // description filter matches
752 //ModelDesc desc = model_descrs_recs[jj];
753 //qDebug() << " ddesc" << desc.description << jj;
754 //qDebug() << " mpart" << mpart.pattern();
755  }
756  }
757  }
758 qDebug() << " (4)m_d size" << model_descriptions.size();
759 
760  lw_models->disconnect( SIGNAL( currentRowChanged( int ) ) );
761  lw_models->clear();
762  int maxlch = 0;
763 
764  if ( model_descriptions.size() > 0 )
765  {
766  for ( int ii = 0; ii < model_descriptions.size(); ii++ )
767  { // propagate list widget with descriptions
768  lw_models->addItem( model_descriptions[ ii ].description );
769  maxlch = qMax( maxlch,
770  model_descriptions[ ii ].description.length() );
771  }
772 
773  // Sort descriptions in ascending alphabetical order
774  lw_models->sortItems();
775  }
776 
777  else
778  {
779  lw_models->addItem( "No models found." );
780  }
781 QDateTime time6=QDateTime::currentDateTime();
782 qDebug() << "Timing: Time6" << time0.msecsTo(time6) << time2.msecsTo(time6);
783 
784  singprev = listsing; // save list-singles flag
785 
786  // Resize the widget to show listed items well
787  QFontMetrics fm = lw_models->fontMetrics();
788  int olwid = lw_models->width();
789  int olhgt = lw_models->height();
790  int nlines = qMin( model_descriptions.size(), 30 );
791  int width = qMin( 600, maxlch * fm.maxWidth() );
792  int height = qMin( 800, nlines * fm.lineSpacing() );
793  width = qMax( width, olwid );
794  height = ( height > olhgt ) ? height : ( ( olhgt + height ) / 2 );
795  width = this->width() + width - olwid;
796  height = this->height() + height - olhgt;
797 
798  resize( width, height );
799 
800  connect( le_mfilter, SIGNAL( textChanged( const QString& ) ),
801  this, SLOT( msearch( const QString& ) ) );
802 }
803 
804 // Cancel button: no models returned
806 {
807  modelsCount = 0;
808 
809  reject();
810  close();
811 }
812 
813 // Accept button: set up to return model information
815 {
816  QList< ModelDesc > allmods = model_descriptions;
817  QList< QListWidgetItem* > selmods = lw_models->selectedItems();
818  modelsCount = selmods.size();
819 
820  if ( modelsCount > 0 )
821  { // loop through selections
822  model_descriptions.clear();
823 
824  for ( int ii = 0; ii < modelsCount; ii++ )
825  { // get row of selection then index in original descriptions list
826  QString mdesc = selmods[ ii ]->text();
827  int mdx = modelIndex( mdesc, allmods );
828 
829  // repopulate descriptions with only selected row(s)
830  model_descriptions.append( allmods.at( mdx ) );
831  }
832  }
833 
834  else
835  {
836  QMessageBox::information( this,
837  tr( "No Model Selected" ),
838  tr( "You have not selected a model.\nSelect+Accept or Cancel" ) );
839  return;
840  }
841 
842 qDebug() << "ACC: multi" << multi;
843  if ( ! multi )
844  { // in single-select mode, load the model and set the description
845 qDebug() << "ACC: load... (single)";
846  load_model( omodel, 0 );
847 qDebug() << "ACC: ...loaded (single)";
848  odescr = description( 0 );
849  }
850 
851  else
852  { // in multiple-select mode, load all models and descriptions
853  omodels.clear();
854  odescrs.clear();
855 
856 QDateTime time1=QDateTime::currentDateTime();
857 qDebug() << "ACC: load... (multi) mCnt" << modelsCount;
858  for ( int ii = 0; ii < modelsCount; ii++ )
859  {
860  load_model( model, ii );
861 
862  omodels << model;
863  odescrs << description( ii );
864  }
865 qDebug() << "ACC: ...loaded (multi)";
866 QDateTime time2=QDateTime::currentDateTime();
867 qDebug() << "Timing: accept-load: mcount" << modelsCount
868  << "time(ms)" << time1.msecsTo(time2);
869  }
870 
871  // Return search string that reflects current state
872  dsearch = le_mfilter->text();
873 
874  if ( do_edit )
875  dsearch = "=e " + dsearch;
876  if ( do_single )
877  dsearch = "=s " + dsearch;
878  if ( do_unasgn )
879  dsearch = "=u " + dsearch;
880  if ( do_manual )
881  dsearch = "=m " + dsearch;
882 
883  dsearch = dsearch.simplified();
884 
885  accept(); // signal that selection was accepted
886  close();
887 }
888 
889 // Filter events to catch right-mouse-button-click on list widget
890 bool US_ModelLoader::eventFilter( QObject* obj, QEvent* e )
891 {
892  if ( obj == lw_models &&
893  e->type() == QEvent::ContextMenu )
894  {
895 //qDebug() << "Right-mouse list select";
896  QPoint mpos = ((QContextMenuEvent*)e)->pos();
897 //qDebug() << " pos" << mpos;
898 
899  show_model_info( mpos );
900 
901  return false;
902  }
903 
904  else
905  { // pass all other events to normal handler
906  return US_WidgetsDialog::eventFilter( obj, e );
907  }
908 }
909 
910 // Get index in model description list of a model description
911 int US_ModelLoader::modelIndex( QString mdesc, QList< ModelDesc > mds )
912 {
913  int mdx = 0;
914 
915  for ( int jj = 0; jj < mds.size(); jj++ )
916  { // search for matching description and save its index
917  if ( mdesc.compare( mds[ jj ].description ) == 0 )
918  {
919  mdx = jj;
920  break;
921  }
922  }
923 
924  return mdx;
925 }
926 
927 // Show selected-model(s) information in text dialog
929 {
931 
932  QString mdesc;
933  QString tdesc;
934  QString cdesc;
935  QString runid;
936  QString dtext;
937  QString lblid;
938  QString mdlid;
939  QString anlid;
940 
941  int row = 0;
942  int mdx = 0;
943  int iters = 1;
944  int ncomp = 0;
945  int nassoc = 0;
946 
947  bool frDisk = ( model_descriptions[ 0 ].filename.length() > 0 );
948 
949  if ( frDisk )
950  { // ID is filename
951  lblid = tr( "\n Model File Name: " );
952  }
953 
954  else
955  { // ID is DB id
956  lblid = tr( "\n Database Model ID: " );
957  }
958 
959  // get the list of selected models
960  QList< QListWidgetItem* > selmods = lw_models->selectedItems();
961  modelsCount = selmods.size();
962 
963  if ( modelsCount < 2 )
964  { // 1 or no rows selected: build information for single model
965 
966  if ( modelsCount == 1 )
967  { // info on selected model
968  row = lw_models->row( selmods[ 0 ] );
969  mdesc = selmods[ 0 ]->text();
970  }
971 
972  else
973  { // info on model at right-click row
974  row = lw_models->row( lw_models->itemAt( pos ) );
975  mdesc = lw_models->itemAt( pos )->text();
976  }
977 
978  mdx = modelIndex( mdesc, model_descriptions ); // find index
979 //qDebug() << " row" << row;
980 //qDebug() << " mdx" << mdx;
981 
982  load_model( model, mdx ); // load model
983 
984  mtype = model.analysis; // model info
985  mdesc = mdesc.length() < 50 ? mdesc :
986  mdesc.left( 23 ) + "..." + mdesc.right( 24 );
987  ncomp = model.components.size();
988  nassoc = model.associations.size();
989  tdesc = model.typeText();
990  iters = !model.monteCarlo ? 0 :
991  model_descriptions[ mdx ].iterations;
992  anlid = model_descriptions[ mdx ].reqGUID;
993  runid = mdesc.section( ".", 0, 0 );
994  int jts = runid.indexOf( "_" + tdesc );
995  runid = jts > 0 ? runid.left( jts ) : runid;
996  mdlid = frDisk ?
997  model_descriptions[ mdx ].filename : // ID is filename
998  model_descriptions[ mdx ].DB_id; // ID is DB id
999  mdlid = mdlid.length() < 50 ? mdlid :
1000  "*/" + mdlid.section( "/", -3, -1 ); // short filename
1001 
1002  dtext = tr( "Model Information:" )
1003  + tr( "\n Description: " ) + mdesc
1004  + tr( "\n Implied RunID: " ) + runid
1005  + tr( "\n Type: " ) + tdesc
1006  + " (" + QString::number( (int)mtype ) + ")"
1007  + tr( "\n Model Global ID: " ) + model.modelGUID
1008  + tr( "\n Description Global ID: " ) + model_descriptions[ mdx ]
1009  .modelGUID
1010  + tr( "\n Edit Global ID: " ) + model.editGUID
1011  + tr( "\n Request Global ID: " ) + model.requestGUID
1012  + lblid + mdlid
1013  + tr( "\n Iterations: " ) + QString::number( iters )
1014  + tr( "\n Components Count: " ) + QString::number( ncomp )
1015  + tr( "\n Associations Count: " ) + QString::number( nassoc )
1016  + tr( "\n List Row: " ) + QString::number( row )
1017  + tr( "\n Analysis Run ID: " ) + anlid
1018  + "";
1019  }
1020 
1021  else
1022  { // multiple rows selected: build multiple-model information text
1023  QString aruni;
1024  QString atype;
1025  QString aegid;
1026  QString eguid;
1027 
1028  row = lw_models->row( selmods[ 0 ] ); // 1st model values
1029  mdesc = selmods[ 0 ]->text();
1030  mdx = modelIndex( mdesc, model_descriptions ); // 1st model index
1031 
1032  load_model( model, mdx ); // load model
1033 
1034  runid = mdesc.section( ".", 0, 0 ); // model info
1035  mtype = model.analysis;
1036  nassoc = model.associations.size();
1037  tdesc = model.typeText();
1038  int jts = runid.indexOf( "_" + tdesc );
1039  runid = jts > 0 ? runid.left( jts ) : runid;
1040  aruni = runid; // potential common values
1041  atype = tdesc;
1042  aegid = model.editGUID;
1043  anlid = model_descriptions[ mdx ].reqGUID;
1044 
1045  // make a pass to see if runID and type are common
1046 
1047  for ( int jj = 1; jj < modelsCount; jj++ )
1048  {
1049  row = lw_models->row( selmods[ jj ] );
1050  mdesc = selmods[ jj ]->text();
1051  mdx = modelIndex( mdesc, model_descriptions ); // model index
1052 
1053  load_model( model, mdx ); // load model
1054 
1055  runid = mdesc.section( ".", 0, 0 );
1056  tdesc = model.typeText();
1057  eguid = model.editGUID;
1058 
1059  if ( !aruni.isEmpty() && aruni.compare( runid ) != 0 )
1060  aruni = ""; // turn off common if mismatch
1061 
1062  if ( !atype.isEmpty() && atype.compare( tdesc ) != 0 )
1063  atype = ""; // turn off common if mismatch
1064 
1065  if ( !aegid.isEmpty() && aegid.compare( eguid ) != 0 )
1066  aegid = ""; // turn off common if mismatch
1067 
1068  if ( aruni.isEmpty() && atype.isEmpty() && aegid.isEmpty() )
1069  break; // none common: break
1070  }
1071 
1072  // Report on common RunID and/or Type
1073  dtext = tr( "Common Model Information ( " )
1074  + QString::number( modelsCount )
1075  + tr( " models ):" );
1076 
1077  if ( !aruni.isEmpty() )
1078  dtext = dtext + tr( "\n Run ID: " ) + aruni;
1079 
1080  if ( !atype.isEmpty() )
1081  dtext = dtext + tr( "\n Type: " ) + atype;
1082 
1083  if ( !aegid.isEmpty() )
1084  dtext = dtext + tr( "\n Related Edit GUID: " ) + aegid;
1085 
1086  // Now loop to report on each model
1087 
1088  for ( int jj = 0; jj < modelsCount; jj++ )
1089  {
1090  row = lw_models->row( selmods[ jj ] ); // row selected
1091  mdesc = selmods[ jj ]->text();
1092  mdx = modelIndex( mdesc, model_descriptions ); // model index
1093 
1094  load_model( model, mdx ); // load model
1095 
1096  mtype = model.analysis; // model info
1097  mdesc = mdesc.length() < 50 ? mdesc :
1098  mdesc.left( 23 ) + "..." + mdesc.right( 24 );
1099  ncomp = model.components.size();
1100  nassoc = model.associations.size();
1101  tdesc = model.typeText();
1102  runid = mdesc.section( ".", 0, 0 );
1103  mdlid = frDisk ?
1104  model_descriptions[ mdx ].filename : // ID is filename
1105  model_descriptions[ mdx ].DB_id; // ID is DB id
1106  mdlid = mdlid.length() < 50 ? mdlid :
1107  "*/" + mdlid.section( "/", -3, -1 ); // short filename
1108  mdlid = mdlid.length() < 50 ? mdlid :
1109  mdlid.left( 23 ) + "..." + mdlid.right( 24 ); // short filename
1110  iters = !model.monteCarlo ? 0 :
1111  model_descriptions[ mdx ].iterations;
1112  anlid = model_descriptions[ mdx ].reqGUID;
1113 
1114  dtext = dtext + tr( "\n\nModel Information: (" )
1115  + QString::number( ( jj + 1 ) ) + "):"
1116  + tr( "\n Description: " ) + mdesc
1117  + tr( "\n Implied RunID: " ) + runid
1118  + tr( "\n Type: " ) + tdesc
1119  + " (" + QString::number( (int)mtype ) + ")"
1120  + tr( "\n Model Global ID: " ) + model.modelGUID
1121  + tr( "\n Description Global ID: " ) + model_descriptions[ mdx ]
1122  .modelGUID
1123  + tr( "\n Edit Global ID: " ) + model.editGUID
1124  + tr( "\n Request Global ID: " ) + model.requestGUID
1125  + lblid + mdlid
1126  + tr( "\n Iterations: " ) + QString::number( iters )
1127  + tr( "\n Components Count: " ) + QString::number( ncomp )
1128  + tr( "\n Associations Count: " ) + QString::number( nassoc )
1129  + tr( "\n List Row: " ) + QString::number( row )
1130  + tr( "\n Analysis Run ID: " ) + anlid
1131  + "";
1132  }
1133  }
1134 
1135  // open a dialog and display model information
1136  US_Editor* edit = new US_Editor( US_Editor::LOAD, true, "", this );
1137  edit->setWindowTitle( tr( "Model Information" ) );
1138  edit->move( this->pos() + pos + QPoint( 100, 100 ) );
1139  edit->resize( 600, 400 );
1140  edit->e->setFont( QFont( "monospace", US_GuiSettings::fontSize() ) );
1141  edit->e->setText( dtext );
1142  edit->show();
1143 }
1144 
1145 // Duplicate the models-from-records list to the full unfiltered list
1147 {
1149 }
1150 
1151 // Expand the models to include singles in the full unfiltered list
1153 {
1154  model_descrs_ufilt.clear(); // Clear the unfiltered models list
1155 
1156  for ( int ii = 0; ii < model_descrs_recs.size(); ii++ )
1157  { // Duplicate/expand each model record to the unfiltered models list
1158  ModelDesc mdesc = model_descrs_recs[ ii ];
1159  mdesc.rec_index = ii;
1160  int mindx = mdesc.description.indexOf( "_mcN" );
1161 qDebug() << "SL: ii" << ii << "mindx" << mindx;
1162 
1163  if ( mindx < 0 )
1164  { // For non-MC-composite, just duplicate
1165  model_descrs_ufilt << mdesc;
1166  }
1167 
1168  else
1169  { // For MC-composite, expand to all the single iteration models
1170  QString cdtext = mdesc.description;
1171  QString cmiter = QString( cdtext ).mid( mindx, 7 );
1172  int niters = QString( cmiter ).mid( 4 ).toInt();
1173  mdesc.iterations = niters;
1174 qDebug() << "SL: niters" << niters << "cmiter" << cmiter;
1175 
1176  for ( int jj = 1; jj <= niters; jj++ )
1177  { // Create and append a description for each iteration model
1178  QString imiter = QString().sprintf( "_mc%04d", jj );
1179  ModelDesc idesc = mdesc;
1180  idesc.description = QString( cdtext ).replace( cmiter, imiter );
1181 qDebug() << "SL: jj" << jj << "imiter" << imiter;
1182 
1183  model_descrs_ufilt << idesc;
1184  }
1185  }
1186  }
1187 }
1188 
1189 // Slot to re-list models when search text has changed
1190 void US_ModelLoader::msearch( const QString& search_string )
1191 {
1192  dsearch = search_string;
1193 
1194  if ( search_string.endsWith( "=" ) )
1195  return;
1196 
1197  list_models();
1198 }
1199 
1200 // Slot to re-list models after change in Single checkbox
1202 {
1203  do_single = cksing;
1204  db_id1 = -2; // flag re-list when list-single flag changes
1205  db_id2 = -2;
1206 
1207  list_models();
1208 }
1209 
1210 // Slot to re-list models after change in Edit checkbox
1211 void US_ModelLoader::change_edit( bool ckedit )
1212 {
1213  do_edit = ckedit;
1214  do_unasgn = ck_unasgn->isChecked();
1215  db_id1 = -2; // flag re-list when list-edit flag changes
1216  db_id2 = -2;
1217 
1218  list_models();
1219 }
1220 
1221 // Slot to re-list models after change in Unassigned checkbox
1222 void US_ModelLoader::change_unasgn( bool ckunasgn )
1223 {
1224  do_unasgn = ckunasgn;
1225  db_id1 = -2; // flag re-list when list-unasgn flag changes
1226  db_id2 = -2;
1227 
1228  if ( do_unasgn )
1229  { // If unassigned now checked, turn off edit (unless id=1)
1230  do_edit = false;
1231 
1232  if ( can_edit )
1233  {
1234  do_edit = ( editGUID == "1" );
1235  }
1236 
1237  ck_edit ->setChecked( do_edit );
1238  }
1239 
1240  list_models();
1241 }
1242 
1243