UltraScan III
us.cpp
Go to the documentation of this file.
1 #include <QtSingleApplication>
3 
4 #include "us.h"
5 #include "us_license_t.h"
6 #include "us_license.h"
7 #include "us_settings.h"
8 #include "us_gui_settings.h"
9 #include "us_win_data.cpp"
10 #include "us_defines.h"
11 #include "us_revision.h"
12 #include "us_sleep.h"
13 #include "us_images.h"
14 #include "us_passwd.h"
15 #include "us_db2.h"
16 
17 #if 0
18 #define EQUI_MENU
19 #endif
20 #if 1
21 #define PCSA_MENU
22 #endif
23 
24 using namespace US_WinData;
25 
38 int main( int argc, char* argv[] )
39 {
40  QtSingleApplication application( "UltraScan III", argc, argv );
41  QString options( getenv( "ULTRASCAN_OPTIONS" ) );
42 
43  // If environment variable ULTRASCAN_OPTIONS contians the
44  // word 'multiple', then we don't try to limit to one instance
45  if ( ! options.contains( "multiple" ) )
46  {
47  if ( application.sendMessage( "Wake up" ) ) return 0;
48  }
49 
50  application.initialize();
51 
52  // Set up language localization
53  QString locale = QLocale::system().name();
54 
55  QTranslator translator;
56  translator.load( QString( "us_" ) + locale );
57  application.installTranslator( &translator );
58 
59  // See if we need to update the license
60  QString ErrorMessage;
61 
62  int result = US_License_t::isValid( ErrorMessage );
63  if ( result != US_License_t::OK )
64  {
65  QMessageBox mBox;
66 
67  QPushButton* cancel = mBox.addButton( QMessageBox::Cancel );
68  QPushButton* Register = mBox.addButton( qApp->translate( "UltraScan III", "Register"),
69  QMessageBox::ActionRole);
70 
71  mBox.setDefaultButton( Register );
72  mBox.setWindowTitle ( qApp->translate( "UltraScan III", "UltraScan License Problem" ) );
73  mBox.setText ( ErrorMessage );
74  mBox.setIcon ( QMessageBox::Critical );
75  mBox.exec();
76 
77  if ( mBox.clickedButton() == cancel ) exit( -1 );
78 
79  US_License* license = new US_License();
80  license->show();
81  application.setActivationWindow( license );
82  return application.exec();
83  }
84 
85  // License is OK. Start up.
86  US_Win w;
87  w.show();
88  application.setActivationWindow( &w );
89  return application.exec();
90 }
91 
93 US_Action::US_Action( int i, const QString& text, QObject* parent)
94  : QAction( text, parent ), index( i )
95 {
96  connect( this, SIGNAL( triggered ( bool ) ),
97  this, SLOT ( onTriggered( bool ) ) );
98 }
99 
101 {
102  emit indexTriggered( index );
103 }
105 US_Win::US_Win( QWidget* parent, Qt::WindowFlags flags )
106  : QMainWindow( parent, flags )
107 {
108  // We need to handle US_Global::g here becuse US_Widgets is not a parent
109  if ( ! g.isValid() )
110  {
111  // Do something for invalid global memory
112  qDebug( "US_Win: invalid global memory" );
113  }
114 
115  g.set_global_position( QPoint( 50, 50 ) ); // Ensure initialization
116  QPoint p = g.global_position();
117  setGeometry( QRect( p, p + QPoint( 710, 532 ) ) );
118  g.set_global_position( p + QPoint( 30, 30 ) );
119 
120  setWindowTitle( "UltraScan III" );
121 
122  QIcon us3_icon = US_Images::getIcon( US_Images::US3_ICON );
123  setWindowIcon( us3_icon );
124 
125  procs = QList<procData*>(); // Initialize to an empty list
126 
128  QMenu* file = new QMenu( tr( "&File" ), this );
129 
130  //addMenu( P_CONFIG, tr( "&Configuration" ), file );
131  //addMenu( P_ADMIN , tr( "&Administrator" ), file );
132  //file->addSeparator();
133  addMenu( P_EXIT, tr( "E&xit" ), file );
134 
135  //QMenu* type1 = new QMenu( tr( "&Velocity Data" ), file );
136  //addMenu( 21, tr( "&Absorbance Data" ), type1 );
137  //addMenu( 22, tr( "&Interference Data" ), type1 );
138  //addMenu( 23, tr( "&Fluorescense Data" ), type1 );
139  //addMenu( 24, tr( "&Edit Cell ID's Data" ), type1 );
140 
142  QMenu* edit = new QMenu( tr( "&Edit" ), this );
143  //addMenu( 12, tr( "&Equilibrium Data" ) , edit );
144  //addMenu( 13, tr( "Edit &Wavelength Data" ), edit );
145  //addMenu( 14, tr( "View/Edit &Multiwavelength Data" ), edit );
146  addMenu( P_EDIT, tr( "&Edit Data" ) , edit );
147  edit->addSeparator();
148  addMenu( P_CONFIG, tr( "&Preferences" ) , edit );
149 
151  QMenu* velocity = new QMenu( tr( "&Velocity" ), this );
152  addMenu( P_VHWE , tr( "&Enhanced van Holde - Weischet" ), velocity );
153  addMenu( P_GRIDEDIT , tr( "C&ustom 2-D Grid Editor" ), velocity );
154  addMenu( P_2DSA , tr( "&2-D Spectrum Analysis" ), velocity );
155 #ifdef PCSA_MENU
156  addMenu( P_PCSA , tr( "&Parametrically Constrained Spectrum Analysis" ),
157  velocity );
158 #endif
159  addMenu( P_GAINIT , tr( "&Initialize Genetic Algorithm" ), velocity );
160  addMenu( P_DMGAINIT , tr( "&Initialize Discrete Model Genetic Algorithm" ),
161  velocity );
162  addMenu( P_SECOND , tr( "&Second Moment" ), velocity );
163  addMenu( P_DCDT , tr( "&Time Derivative" ), velocity );
164  addMenu( P_FEMA , tr( "&FE Model Viewer" ), velocity );
165  addMenu( P_PSEUDO3D , tr( "&Combine Pseudo-3D Distributions" ), velocity );
166  addMenu( P_RAMP , tr( "Speed &Ramp Analysis" ), velocity );
167 
168 #ifdef EQUI_MENU
169  QMenu* equilibrium = new QMenu( tr( "E&quilibrium" ), this );
170  addMenu( P_EQGLOBFIT, tr( "&Global Fit" ), equilibrium );
171  //addMenu( P_EQTIMEEST, tr( "Estimate Equilibrium &Times", equilibrium );
172 #endif
173 
174 // QMenu* fit = new QMenu( tr( "&Global Fit" ), this );
175 // addMenu( P_GLOBFITEQ, tr( "Global &Equilibrium Fit" ), fit );
176  //addMenu( P_GLOBFITEX, tr( "Global E&xtinction Fit" ), fit );
177  //addMenu( P_GLOBFITSP, tr( "Global &Spectrum Fit" ), fit );
178 
179  QMenu* utilities = new QMenu( tr( "&Utilities" ), this );
180  addMenu( P_CONVERT , tr( "&Import Experimental Data" ), utilities );
181  addMenu( P_EXPORT , tr( "&Export OpenAUC Data" ), utilities );
182  addMenu( P_FDSMAN , tr( "FDS File &Manager" ), utilities );
183  addMenu( P_FITMEN , tr( "&Fit Meniscus" ), utilities );
184  addMenu( P_COLORGRAD, tr( "Color &Gradient Generator" ), utilities );
185  addMenu( P_RPTGEN , tr( "&Report Generator" ), utilities );
186  addMenu( P_ROTORCAL , tr( "R&otor Calibration" ), utilities );
187  addMenu( P_LICENSE , tr( "&License Manager" ), utilities );
188  addMenu( P_VHWCOMB , tr( "Combine Distribution &Plots (vHW)" ), utilities );
189  addMenu( P_DDCOMB , tr( "Combine &Discrete Distributions" ), utilities );
190  addMenu( P_GLOMODL , tr( "Create Global &Model" ), utilities );
191  addMenu( P_VIEWMWL , tr( "&View Multiwavelength Data" ), utilities );
192  addMenu( P_VIEWMSS , tr( "View Multiwavelength &S-Spectra" ), utilities );
193 
194  QMenu* simulation = new QMenu( tr( "S&imulation" ), this );
195  addMenu( P_ASTFEM, tr( "&Finite Element Simulation (ASTFEM)" ), simulation );
197  tr( "Estimate Equilibrium &Times" ), simulation );
198  addMenu( P_SASSOC, tr( "&Self-Association Equilibrium" ), simulation );
199  addMenu( P_MODEL1, tr( "&Model s, D and f from MW for 4 basic shapes" ),
200  simulation );
201  addMenu( P_MODEL2, tr( "&Predict f and axial ratios for 4 basic shapes" ),
202  simulation );
203  addMenu( P_SOMO, tr( "S&OMO Bead Modeling" ), simulation );
204  addMenu( P_SOMOCONFIG, tr( "S&OMO Configuration" ), simulation );
205 
206  QMenu* database = new QMenu( tr( "&Database" ), this );
207  addMenu( P_INVESTIGATOR , tr( "Manage &Investigator Data" ), database );
208  addMenu( P_BUFFER , tr( "Manage &Buffer Data" ), database );
209  addMenu( P_VBAR , tr( "Manage &Analytes" ), database );
210  addMenu( P_MODEL , tr( "Manage &Models" ), database );
211  addMenu( P_MANAGEDATA , tr( "Manage &Data" ), database );
212  addMenu( P_MANAGESOLN , tr( "Manage &Solutions" ), database );
213  addMenu( P_MANAGEPROJ , tr( "Manage &Projects" ), database );
214  addMenu( P_MANAGEROTOR , tr( "Manage &Rotors" ), database );
215 
217  QMenu* help = new QMenu( tr( "&Help" ), this );
218  addMenu( HELP_HOME , tr("UltraScan &Home" ), help );
219  addMenu( HELP , tr("UltraScan &Manual" ), help );
220  addMenu( HELP_REG , tr("&Register Software" ), help );
221  addMenu( HELP_UPGRADE, tr("&Upgrade UltraScan" ), help );
222  addMenu( HELP_LICENSE, tr("UltraScan &License" ), help );
223  addMenu( HELP_ABOUT , tr("&About" ), help );
224  addMenu( HELP_CREDITS, tr("&Credits" ), help );
225  addMenu( HELP_NOTICES, tr("Show &Notices" ), help );
226 
227 #ifndef Q_WS_MAC
228  QFont bfont = QFont( US_GuiSettings::fontFamily(),
230  QFont::Bold );
231  menuBar()->setFont( bfont );
232 #endif
233  menuBar()->addMenu( file );
234  menuBar()->addMenu( edit );
235  menuBar()->addMenu( velocity );
236 #ifdef EQUI_MENU
237  menuBar()->addMenu( equilibrium );
238 // menuBar()->addMenu( fit );
239 #endif
240  menuBar()->addMenu( utilities );
241  menuBar()->addMenu( simulation );
242  menuBar()->addMenu( database );
243  menuBar()->addMenu( help );
244 
245 #ifndef Q_WS_MAC
246  QFont mfont = QFont( US_GuiSettings::fontFamily(),
248  QFont::Normal );
249  file ->setFont( mfont );
250  edit ->setFont( mfont );
251  velocity ->setFont( mfont );
252 #ifdef EQUI_MENU
253  equilibrium->setFont( mfont );
254 // fit ->setFont( mfont );
255 #endif
256  utilities ->setFont( mfont );
257  simulation ->setFont( mfont );
258  database ->setFont( mfont );
259  help ->setFont( mfont );
260 #endif
261 
262  splash();
263  statusBar()->showMessage( tr( "Ready" ) );
264 
265  notice_check(); // Check for any notices pending
266 }
267 
269 {
270  QPoint p = g.global_position();
271  g.set_global_position( p - QPoint( 30, 30 ) );
272 }
273 
274 void US_Win::addMenu( int index, const QString& label, QMenu* menu )
275 {
276  US_Action* action = new US_Action( index, label, menu );
277 
278 #ifndef Q_WS_MAC
279  QFont font = QFont( US_GuiSettings::fontFamily(),
281  QFont::Normal );
282  action->setFont( font );
283 #endif
284 
285  connect( action, SIGNAL( indexTriggered ( int ) ),
286  this, SLOT ( onIndexTriggered( int ) ) );
287 
288  menu->addAction( action );
289 }
290 
291 void US_Win::onIndexTriggered( int index )
292 {
293  if ( index == 4 ) close();
294 
295 //qDebug() << index << P_CONFIG << P_END;
296  if ( index >= P_CONFIG && index < P_END ) launch( index );
297  if ( index >= HELP && index < HELP_END ) help ( index );
298 }
299 
300 void US_Win::terminated( int code, QProcess::ExitStatus status )
301 {
302 qDebug() << "PROCESS terminated: code" << code << "status" << status;
303  QList<procData*>::iterator pr;
304 
305  for ( pr = procs.begin(); pr != procs.end(); pr++ )
306  {
307  procData* d = *pr;
308  QProcess* process = d->proc;
309  int index = d->index;
310 
311  if ( process->state() == QProcess::NotRunning )
312  {
313 qDebug() << "PROCESS NotRunning index" << index << "Proc name" << d->name;
314 
315  if ( status == QProcess::CrashExit )
316  { // Process crashed: output a message and possibly do a pop-up
317  QString msg_sb;
318  QString msg_mb;
319  QString msg_ru = p[ index ].runningMsg;
320  QString estderr = QString( process->readAllStandardError() )
321  .right( 2000 ); // End lines of STDERR
322  bool badallo = estderr.contains( "bad_alloc" );
323 qDebug() << "PROCESS status" << status << "e-stderr len" << estderr.length();
324 //qDebug() << "PROCESS bad_alloc? " << badallo;
325 
326  if ( badallo )
327  { // It was a "bad_alloc" crash
328  msg_sb = tr( "MEMORY ALLOC crash: " ) + msg_ru;
329  msg_mb = tr( "Process MEMORY ALLOCATION Crash:\n" ) + msg_ru;
330  }
331 
332  else
333  { // It was other than bad_alloc
334  int kwhat = estderr.lastIndexOf( "what(): " );
335 
336  if ( kwhat > 0 )
337  { // We have a "what():" hint in stderr
338  QString msg_wh = estderr.mid( kwhat + 7, 20 ).simplified();
339  msg_sb = "[ " + msg_wh + " ] crash: " + msg_ru;
340  msg_mb = tr( "Process Crash [ " ) + msg_wh + " ]\n" + msg_ru;
341  }
342 
343  else
344  { // Crash type is undetermined
345  msg_sb = "[ unknown type ] crash: " + msg_ru;
346  msg_mb = tr( "Process Crash [ unknown type ]\n" ) + msg_ru;
347  }
348  }
349 
350  // Report the crash in the status bar and in a message box pop-up
351  statusBar()->showMessage( msg_sb );
352  QString selines = estderr.endsWith( "\n" )
353  ? estderr.section( "\n", -4, -2 )
354  : estderr.section( "\n", -3, -1 );
355  msg_mb += tr( "\n\nLast several stderr lines --\n\n" ) + selines;
356  QMessageBox::warning( this, tr( "Process Crash" ), msg_mb );
357  }
358 
359  procs.removeOne( d );
360  p[ index ].currentRunCount--;
361  delete process; // Deleting the process structure
362  delete d; // Deleting the procData structure
363 
364  if ( index == 0 )
365  apply_prefs();
366 
367  return;
368  }
369  }
370 }
371 
372 void US_Win::launch( int index )
373 {
374  static const int trig_secs=3600;
375 // static const int trig_secs=3;
376  index -= P_CONFIG;
377  QString pname = p[ index ].name;
378 
379  // At each launch, check for notices if last check was over 24 hours ago
380  if ( ln_time.secsTo( QDateTime::currentDateTime() ) > trig_secs )
381  notice_check();
382 
383  if ( p[ index ].maxRunCount <= p[ index ].currentRunCount &&
384  p[ index ].maxRunCount > 0 )
385  {
386  if ( p[ index ].index == P_CONFIG )
387  {
388  QMessageBox::information( this,
389  tr( "Already Running" ),
390  tr( "The configuration program is already running.\n"
391  "Click on the task bar item named UltraScan "
392  "Configuration to continue." ) );
393  }
394  else
395  {
396  QMessageBox::warning( this,
397  tr( "Error" ),
398  pname + tr( " is already running." ) );
399  }
400 
401  return;
402  }
403 
404  statusBar()->showMessage(
405  tr( "Loading " ) + p[ index ].runningMsg + "..." );
406 
407  QProcess* process = new QProcess( 0 );
408  process->closeReadChannel( QProcess::StandardOutput );
409  process->closeReadChannel( QProcess::StandardError );
410  connect ( process, SIGNAL( finished ( int, QProcess::ExitStatus ) ),
411  this , SLOT ( terminated( int, QProcess::ExitStatus ) ) );
412 
413 #ifndef Q_WS_MAC
414  process->start( pname );
415 #else
416  QString procbin = US_Settings::appBaseDir() + "/bin/" + pname;
417  QString procapp = procbin + ".app";
418 
419  if ( !QFile( procapp ).exists() )
420  procapp = procbin;
421 
422  process->start( "open", QStringList(procapp) );
423 #endif
424 
425  if ( ! process->waitForStarted( 10000 ) ) // 10 second timeout
426  {
427  QMessageBox::information( this,
428  tr( "Error" ),
429  tr( "There was a problem creating a subprocess\nfor " ) + pname );
430  }
431  else
432  {
433  p[ index ].currentRunCount++;
434  procData* pr = new procData;
435  pr->proc = process;
436  pr->name = pname;
437  pr->index = index;
438 
439  procs << pr;
440  }
441 
442  statusBar()->showMessage(
443  tr( "Loaded " ) + p[ index ].runningMsg + "..." );
444 }
445 
446 void US_Win::closeProcs( void )
447 {
448  QString names;
449  QList<procData*>::iterator p;
450 
451  for ( p = procs.begin(); p != procs.end(); p++ )
452  {
453  procData* d = *p;
454  names += d->name + "\n";
455  }
456 
457  QString isAre = ( procs.size() > 1 ) ? "es are" : " is";
458  QString itThem = ( procs.size() > 1 ) ? "them" : "it";
459 
460  QMessageBox box;
461  box.setWindowTitle( tr( "Attention" ) );
462  box.setText( QString( tr( "The following process%1 still running:\n%2"
463  "Do you want to close %3?" )
464  .arg( isAre ).arg( names ).arg( itThem ) ) );
465 
466  QString killText = tr( "&Kill" );
467  QString closeText = tr( "&Close Gracefully" );
468  QString leaveText = tr( "&Leave Running" );
469 
470  QPushButton* kill = box.addButton( killText , QMessageBox::YesRole );
471  box.addButton( closeText, QMessageBox::YesRole );
472  QPushButton* leave = box.addButton( leaveText, QMessageBox::NoRole );
473 
474  box.exec();
475 
476  if ( box.clickedButton() == leave ) return;
477 
478  for ( p = procs.begin(); p != procs.end(); p++ )
479  {
480  procData* d = *p;
481  QProcess* process = d->proc;
482 
483  if ( box.clickedButton() == kill )
484  process->kill();
485  else
486  process->terminate();
487  }
488 
489  // We need to sleep slightly (one millisecond) so that the system can clean
490  // up and properly release shared memory.
491  g.scheduleDelete();
492  US_Sleep::msleep( 1 );
493 }
494 
495 void US_Win::closeEvent( QCloseEvent* e )
496 {
497  if ( ! procs.isEmpty() ) closeProcs();
498  e->accept();
499 }
500 
501 
502 void US_Win::splash( void )
503 {
504  int y = menuBar ()->size().rheight();
505  int h = 532 - y - statusBar()->size().rheight();
506  int w = 710;
507 
508  bigframe = new QLabel( this );
509  bigframe->setFrameStyle ( QFrame::Box | QFrame::Raised);
510  bigframe->setPalette ( US_GuiSettings::frameColor() );
511  bigframe->setGeometry ( 0, y, w, h );
512  bigframe->setAutoFillBackground( true );
513 
514  splash_shadow = new QLabel( this );
515  splash_shadow->setGeometry( (unsigned int)( ( w / 2 ) - 210 ) , 130, 460, 276 );
516  splash_shadow->setPalette( QPalette( Qt::black, Qt::cyan ) );
517  splash_shadow->setAutoFillBackground ( true );
518 
519  logo( w );
520 
521  //QTimer::singleShot( 6000, this, SLOT( closeSplash() ) );
522 }
523 
524 void US_Win::logo( int width )
525 {
526  // Splash image
527  QPixmap rawpix = US_Images::getImage( US_Images::US3_SPLASH );
528 
529  int ph = rawpix.height();
530  int pw = rawpix.width();
531 
532  QPixmap pixmap( pw, ph );
533  QPainter painter( &pixmap );
534 
535  painter.drawPixmap( 0, 0, rawpix );
536  painter.setPen ( QPen( Qt::white, 3 ) );
537 
538  QString version = "Version " + US_Version + " ( " REVISION
539  " ) for " OS_TITLE; // REVISON is #define "Revision: xxx"
540 
541  QFont font( "Arial" );
542  font.setWeight( QFont::DemiBold );
543  font.setPixelSize( 16 );
544  painter.setFont( font );
545  QFontMetrics metrics( font );
546 
547  int sWidth = metrics.boundingRect( version ).width();
548  int x = ( pw - sWidth ) / 2;
549 
550  painter.drawLine( 0, 111, pw, 111);
551  painter.drawText( x, 139, version );
552  painter.drawLine( 0, 153, pw, 153);
553 
554  QString s = "Author: Borries Demeler";
555  sWidth = metrics.boundingRect( s ).width();
556  painter.drawText( ( pw - sWidth ) / 2, 177, s );
557 
558  s = "The University of Texas";
559  sWidth = metrics.boundingRect( s ).width();
560  painter.drawText( ( pw - sWidth ) / 2, 207, s );
561 
562  s = "Health Science Center at San Antonio";
563  sWidth = metrics.boundingRect( s ).width();
564  painter.drawText( ( pw - sWidth ) / 2, 227, s );
565 
566  s = "Department of Biochemistry";
567  sWidth = metrics.boundingRect( s ).width();
568  painter.drawText( ( pw - sWidth ) / 2, 247, s );
569 
570  smallframe = new QLabel(this);
571  smallframe->setPixmap(pixmap);
572  smallframe->setGeometry( (unsigned int)( (width / 2) - 230 ), 110, 460, 276);
573 }
574 
576 {
577  delete smallframe;
578  delete splash_shadow;
579  bigframe->show();
580 }
581 
582 void US_Win::help( int index )
583 {
584  int i = index - HELP;
585 
586  statusBar()->showMessage( tr( h[i].loadMsg.toAscii() ) );
587  switch ( index )
588  {
589  case HELP_CREDITS:
590  QMessageBox::information( this,
591  tr( "UltraScan Credits" ),
592  tr( "The UltraScan-III and LIMS-III software were developed by:\n\n"
593  "Emre Brookes, Weiming Cao, Bruce Dubbs, Gary Gorbet, "
594  "Jeremy Mann, Suresh Marru, Shabhaz Memon, Marlon Pierce, \n"
595  "Raminder Singh and Dan Zollars.\n\n"
596  "Project Director: Borries Demeler\n\n"
597  "This development was funded by NIH Grant RR022200 "
598  "and NSF grants ACI-1339649 and TG-MCB070039.\n\n"
599 
600  "We thank the following individuals for contributions "
601  "to the UltraScan project:\n\n"
602 
603  " * Nikolay Dokholyan\n"
604  " * Jose Garcia de la Torre\n"
605  " * Brad Langford\n"
606  " * Thomas Laue\n"
607  " * Luitgard Nagel-Steger\n"
608  " * Zach Ozer\n"
609  " * Karel Planken\n"
610  " * Mattia Rocco\n"
611  " * Virgil Schirf\n"
612  " * Bruno Spotorno\n"
613  " * Giovanni Tassara\n"
614  " * Oleg Tsodikov\n"
615  " * Johannes Walter\n"
616  " * Nikola Wenta\n"
617  " * Josh Wilson" ) );
618 
619  statusBar()->showMessage( tr( "Ready" ) );
620  break;
621 
622  case HELP_ABOUT:
623  QMessageBox::information( this,
624  tr( "About UltraScan..." ),
625  tr( "UltraScan III version %1\n"
626  "%2\n"
627  "Copyright 1989 - 2014\n"
628  "Borries Demeler and the University of Texas System\n\n"
629  "For more information, please visit:\n"
630  "http://www.ultrascan.uthscsa.edu/\n\n"
631  "The author can be reached at:\n"
632  "The University of Texas Health Science Center\n"
633  "Department of Biochemistry\n"
634  "7703 Floyd Curl Drive\n"
635  "San Antonio, Texas 78229-3900\n"
636  "voice: (210) 767-3332\n"
637  "Fax: (210) 567-6595\n"
638  "E-mail: demeler@biochem.uthscsa.edu" ).arg( US_Version ).arg( REVISION ) );
639 
640  statusBar()->showMessage( tr( "Ready" ) );
641  break;
642 
643  case HELP_NOTICES:
644  ln_time = ln_time.addYears( -1 );
645  notice_check();
646  break;
647 
648  default:
649 
650  if ( h[i].type == URL )
651  {
652  showhelp.show_URL( h[i].url );
653  }
654  else
655  {
656  showhelp.show_help( h[i].url );
657  }
658 
659  statusBar()->showMessage( tr( "Loaded " ) + h[i].loadMsg.toAscii() );
660  break;
661  }
662 }
663 
664 // apply font and base frame color preferences
666 {
667 #ifndef Q_WS_MAC
668  // reset the menu bar font
669  QFont bfont = QFont( US_GuiSettings::fontFamily(),
671  QFont::Bold );
672 
673  menuBar()->setFont( bfont );
674 
675  // reset the font for all the sub-menus
676  QFont mfont = QFont( US_GuiSettings::fontFamily(),
678  QFont::Normal );
679 
680  QList< QMenu* > mens = this->findChildren< QMenu* >(); // menubar menus
681 
682  for ( int ii = 0; ii < mens.count(); ii++ )
683  { // loop to get and reset actions font for each menu
684  QList< QAction* > acts = mens.at( ii )->findChildren< QAction* >();
685 
686  for ( int jj = 0; jj < acts.count(); jj++ )
687  { // reset the font for each submenu action
688  acts.at( jj )->setFont( mfont );
689  }
690  }
691 #endif
692 
693  // reset the frame color
694  bigframe->setPalette( US_GuiSettings::frameColor() );
695 
696  show();
697 }
698 
699 // Check for posted US3 notices
701 {
702  bool do_abort = false; // Default: no abort
703  int level = 0; // Max level: information
704  QDateTime pn_time = ln_time; // Previous check time
705  ln_time = QDateTime::currentDateTime(); // Reset last notice time
706 
708  return do_abort; // If default data location is Disk, do not bother
709 
710 //do_abort=true;
711 //level=2;
712  // Query notice table in the us3_notice database
713  US_Passwd pw;
714  US_DB2 db;
715  QString host ( "uslims3.uthscsa.edu" );
716  QString dbname( "us3_notice" );
717  QString user ( "us3_notice" );
718  QString passwd( "us3_notice" );
719  QString errmsg;
720  QStringList defaultDB = US_Settings::defaultDB();
721  if ( defaultDB.size() > 3 )
722  host = defaultDB.at( 3 );
723 
724  if ( ! db.connect( host, dbname, user, passwd, errmsg ) )
725  {
726 qDebug() << "US:NOTE: Unable to connect" << errmsg;
727  return do_abort;
728  }
729 
730  QString query( "SELECT type, revision, message, lastUpdated"
731  " FROM us3_notice.notice;" );
732  db.rawQuery( query );
733 
734  // If no notices in the database, return now with no notice pop-up
735  if ( db.lastErrno() != US_DB2::OK || db.numRows() == 0 )
736  {
737 qDebug() << "US:NOTE: No DB notices" << db.lastError()
738  << "numRows" << db.numRows();
739  return do_abort;
740  }
741 
742  // Otherwise accumulate notices and associated type,revision,time
743  QStringList msgs;
744  QStringList types;
745  QStringList revs;
746  QList< int > irevs;
747  QDateTime time_d;
748  QMap< QString, QString > typeMap;
749  typeMap[ "info" ] = tr( "Information" );
750  typeMap[ "warn" ] = tr( "Warning" );
751  typeMap[ "crit" ] = tr( "Critical" );
752  int nnotice = 0;
753  int nn_info = 0;
754  int nn_warn = 0;
755  int nn_crit = 0;
756  int i_rev = 0;
757 
758  while ( db.next() )
759  {
760  nnotice++;
761 
762  QString type = db.value( 0 ).toString();
763  QString mrev = db.value( 1 ).toString();
764  QString msg = db.value( 2 ).toString();
765  QDateTime time_m = db.value( 3 ).toDateTime();
766 
767  if ( type == "info" ) nn_info++;
768  else if ( type == "warn" ) nn_warn++;
769  else if ( type == "crit" ) nn_crit++;
770 
771  int m_rev = QString( mrev ).replace( ".", "" ).toInt();
772  i_rev = qMax( i_rev, m_rev );
773 
774  if ( nnotice == 1 )
775  {
776  time_d = time_m;
777  }
778  else
779  {
780  time_d = time_m.secsTo( time_d ) > 0
781  ? time_d : time_m;
782  }
783 
784  types << type;
785  revs << mrev;
786  irevs << m_rev;
787  msgs << msg;
788  }
789 
790  // If current revision is at or beyond max in records, skip pop-up
791  QString srev = US_Version + "."
792  + QString( REVISION ).section( ":", 1, 1 ).simplified();
793  int s_rev = QString( srev ).replace( ".", "" ).toInt();
794 
795 qDebug() << "s_rev i_rev" << s_rev << i_rev << "srev" << srev;
796  if ( s_rev > i_rev )
797  return do_abort;
798 
799  // If lastest message time earlier than last notice time, skip pop-up
800  int n_dif = (int)time_d.secsTo( pn_time );
801 qDebug() << " n_dif" << n_dif << "time_d" << time_d << "pn_time" << pn_time;
802  if ( n_dif > 0 )
803  return do_abort;
804 
805  // Build notice message
806  level = ( nn_warn > 0 ) ? 1 : level;
807  level = ( nn_crit > 0 ) ? 2 : level;
808  QString msg_note = tr( "UltraScan III notices posted (" )
809  + time_d.toString( "yyyy/MM/dd" ) + "):\n\n";
810 
811  for ( int ii = 0; ii < nnotice; ii++ )
812  {
813  // Skip messages for warn/crit same revision or any earlier than current
814  if ( ( irevs[ ii ] == s_rev && types[ ii ] != "info" ) ||
815  irevs[ ii ] < s_rev ) continue;
816 
817  // Add current message to full text
818  msg_note += typeMap[ types[ ii ] ] + " for release "
819  + revs[ ii ] + ":\n"
820  + msgs[ ii ] + "\n";
821 
822  // Critical from later revision than current means an abort
823  if ( types[ ii ] == "crit" ) do_abort = true;
824  }
825 
826  if ( do_abort )
827  { // Append an additional note if an abort is happening
828  msg_note += tr( "\n\n*** US3 Abort: UPDATE REQUIRED!!! ***\n" );
829  }
830 
831  // Display notices at level of highest level currently set
832  if ( level == 0 )
833  QMessageBox::information( this, tr( "US3 Notices" ), msg_note );
834  else if ( level == 1 )
835  QMessageBox::warning ( this, tr( "US3 Notices" ), msg_note );
836  else if ( level == 2 )
837  QMessageBox::critical ( this, tr( "US3 Notices" ), msg_note );
838 
839  // Abort if that is indicated
840  if ( do_abort )
841  exit( -77 );
842 
843  return do_abort;
844 }
845