// $Id: QtUtils/RwFileDialog.cpp 2013/09/21 19:30:38 philw $
// A wrapper class for QFileDialog's static and instance-based APIs.
//
//  namespace RwFile
//  class RwFileDialog
//  class RwOpenFileDialog : public RwFileDialog
//  class RwSaveFileDialog : public RwFileDialog
//
//  SEE: "Configuration Constants" section, below.
//
//  Documentation Below:
//   (1) Background: QFileDialog
//   (2) RwFileDialog Wrapper Class
//   (3) RwFileDialog Automatic History Support
//   (4) Gnats 5364 Notes 
//
//  ===========================
//  (1) Background: QFileDialog
//  ===========================
//
//  The Qt4 QFileDialog file chooser dialog class has effectively two API:
//
//  (1) Static QFileDialog methods: Show and execute a file chooser
//      dialog with a single call. EXAMPLE:
//
//         QString selectedFileName =
//            QFileDialog::getOpenFileName (
//               parentWidget, windowTitle, initialSelection,
//               nameFilters, &selectedNameFilter, optionFlags);
//
//  (2) Qt Instance (QFileDialog instance) API -- broader control of the
//      file chooser dialog's configuration -- including an application-
//      level chooser history. EXAMPLE:
//
//         QFileDialog dlg (parentWidget);
//         dlg.setWindowTitle (windowTitle);
//         dlg.setAcceptMode (QFileDialog::AcceptSave);
//         dlg.setFileMode (QFileDialog::AnyFile);
//         dlg.setNameFilters (filterPatterns);
//         dlg.setHistory (historyList);
//         dlg.setLabelText (QFileDialog::Accept, tr ("Select"));
//         dlg.setOptions (QFileDialog::DontConfirmOverwrite);
//         const int dialogResult = dlg.exec();  // SHOW AND EXECUTE
//         const QStringList selFiles = dlg.selectedFiles();
//
//  For the most part,
//   - the STATIC interface shows a NATIVE WINDOWS file chooser.
//   - the QT INSTANCE interface shows a QT-IMPLEMENTED file chooser.
//
//  Major Differences between these two QFileDialog interfaces:
//
//  (1) The Qt Instance chooser supports application-level history.
//      For example, showing the most recent six RplSet files when
//      choosing a RplSet file to open. The Static (Native Windows)
//      file chooser supports just a single unified file access history,
//      not specific to RiverWare operation.
//
//  (2) The Qt Instance chooser supports custom button text for the
//      accept button (other than "Save" or "Open"). (Other dialog
//      text can also be customized). In RiverWare, this has been used 
//      when showing a dialog selector to pick a filepath for a line 
//      editor in some other dialog ("Select").
//
//  (3) There is evidence of a possible lockup/crash with the Qt
//      Instance chooser -- but not with the Static/Native chooser.
//      SEE SECTION (4) BELOW.
//
//  RiverWare 6.4 development (9-2013) had about:
//    [61] Static uses of QFileDialog
//    [23] Qt Instances of QFileDialog (plus a few subclass instances)
//
//  ==============================
//  (2) RwFileDialog Wrapper Class
//  ==============================
//
//  The RwFileDialog has an API which replicates the part of the 
//  Qt4 QFileDialog API used by RiverWare -- BOTH the Static/Native
//  functions and the Qt Instance methods.  Its API makes possible 
//  a mostly transparent port in RiverWare from QFileDialog to
//  RwFileDialog. 
//
//  The primary motivation is to (at least in the short term) port 
//  all of the 23+ "Instance" uses to the Static/Native implementation 
//  to see if this avoids the Gnats 5364 lockup/crash with Samba --
//  for users who are experiencing this problem -- (we have not been 
//  able to reproduce this problem ourselves).
//
//  This class also provides the ability to GLOBALLY SWITCH between the 
//  two QFileDialog implementations (APIs) -- for all uses of this 
//  RwFileDialog class (REGARDLESS of which RwFileDialog interface is 
//  actually used in RiverWare application code). It also provides a 
//  central place from which to customize the implementation of all uses
//  of file choosers in RiverWare, and to provide additional processing 
//  of file selections.
//
//  SEE the "Configuration Constants" below. Options include: 
//
//   (a) Which mode should be the default: "Native" or not (Qt Instance).
//   (b) Option to include a terse tag in the file chooser window
//       title to indicate the file chooser mode, initially either:
//       "[WIN]" or "[Qt]".
//   (c) Optional post-seletion processing features.
//
//  Note [9-16-2013]: The RiverWare Workspace TEST MENU now supports
//  these two test functions which (a) operate the RwFileDialog 
//  file chooser in the respective mode, and (b) SWITCHES all 
//  subsequent RwFileDialog uses to that mode. [The implementations 
//  are defined in this class, and also serve as a usage example].
//
//    (1) Test File Chooser: Native
//    (2) Test File Chooser: Qt
//
//  ==========================================
//  (3) RwFileDialog Automatic History Support
//  ==========================================
//
//  With this QFileDialog encapsulation, we have the opportunity to also
//  encapsulate the maintanence of RiverWare's application-level history
//  data.  As noted, this history is not available to the Static/Native 
//  file chooser mode. However, even when that mode is used, there is 
//  benefit to maintaining this history data -- for construction of the
//  dynamic "Reopen" submenus (e.g. the "Reopen Model" submenu under the 
//  Workspace File menu).
//
//  Automatic initialization from the application-level history -- and 
//  saving of the chosen file within the proper history type (Model, 
//  RplSet, etc.) is supported with a "Use Type" parameter added to new 
//  versions of the API. (There are also methods which lack this new 
//  parameter -- those use and save data to RiverWare's general "recent 
//  directory" history).
//
//  See the UseType enumerated type, and parameters. The available values
//  correspond to the specific histories supported by the LoadSaveMgr.
//
//  ====================
//  (4) Gnats 5364 Notes 
//  ====================
//
//  See Gnats 5364: (effectively a crash using a QFileDialog instance).
//  "Load model across Samba network, hangs just before presenting file
//  chooser. One fix: native file chooser + no history [QFileDialog::
//  setHistory(), setDirectory() passed in model directory]."
//  [Patrick, 8-23-2013, see e-mails]. [Rw 6.4 development, Qt 4.8.5].
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// *********************************
// ***  Configuration Constants  ***
// *********************************
#include <QString>

// Active/Default File Chooser Type: Windows Native? (or Qt Instance).
static const bool DEFAULT_USE_NATIVE (true);  // release: true (9-2013)

// File Chooser Dialog Type Indication in Title Bar: "[WIN]" or "[QT]".
static const bool SHOW_WINDOW_TITLE_STR_NATIVE (true);   // release: false
static const bool SHOW_WINDOW_TITLE_STR_QtINST (true);   // release: true
static const QString WINDOW_TITLE_STR_NATIVE ("[WIN]");  // Native (Static)
static const QString WINDOW_TITLE_STR_QtINST ("[QT]");   // Qt Instance

// Post-Selection Processing Features:
//  (1) Save picked filepath to application-level file history?
//  (2) Copy picked filepath to system clipboard?
//
// Note [9-2013, Rw 6.4]: Especially the SAVE HISTORY feature is 
// currently implemented where necessary in the application (client)
// code.  If and when we remove history saving from all the clients, 
// history saving -- based on UseTypes specified by the client -- 
// would be enabled here.
//
static const bool SAVE_PICKED_TO_HISTORY_ENA   (false);  // rel 6.4: false
static const bool COPY_PICKED_TO_CLIPBOARD_ENA (false);  // rel 6.4: false

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

#include "RwFileDialog.hpp"
#include "LoadSaveMgr.hpp"
#include "QGui.hpp"
#include "RwQtUtils.hpp"
#include "rwError.hpp"  //--- for rwAssert

#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>
#include <iostream>

using namespace RwFile;

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// ***********************************************
// ***  class RwFileDialog / Static Interface  ***
// ***********************************************

// static
bool RwFileDialog::_useNativeChooser (DEFAULT_USE_NATIVE);

// static
void RwFileDialog::setUseNativeChooser (bool on) 
{
   _useNativeChooser = on; 
}

// static
void RwFileDialog::setAndTestChooserType (bool native)
{
   static const char* mname ("RwFileDialog::showTest");
   static int callCnt (0);
   ++callCnt;

   // **********************************************************
   // ***  SET FILE SELECTOR TYPE:  Native? or Qt Instance?  ***
   // **********************************************************

   setUseNativeChooser (native);

   static const QString fmt (QObject::tr (
     "Active File Chooser Dialog Type: %1 \n"
     "Save picked filename to history: %2 \n"
     "Copy picked filename to clipboard: %3"));

   const char* typeStr = native ? "NATIVE" : "QT";

   const QString msg = 
     fmt .arg (typeStr)
         .arg (SAVE_PICKED_TO_HISTORY_ENA ? "ENABLED" : "DISABLED")
         .arg (COPY_PICKED_TO_CLIPBOARD_ENA ? "ENABLED" : "DISABLED");

   QMessageBox mbox;
   mbox.setWindowTitle ("RiverWare File Chooser Type Set");
   mbox.setText (msg);
   mbox.setIcon (QMessageBox::Information);
   QPushButton* testBut = 
      mbox.addButton ("Show Test Dialog", QMessageBox::YesRole);
   mbox.addButton (QMessageBox::Close);
   mbox.exec();

   QAbstractButton* userBut = mbox.clickedButton();
   if (userBut != testBut) return;
   //--------------------------->>

   // **********************************************************
   // ***  SHOW TEST FILE CHOOSER (picked file is not used)  ***
   // **********************************************************

   const QString caption = 
      QString ("Test File Chooser (%1) for Load Model File") .arg (typeStr);

   static QString selectedFilter;
   RwOpenFileDialog dlg (RwFile::For_Model);
   dlg.setWindowTitle (caption);
   dlg.setSelectedNameFilterPtr (&selectedFilter);
   const int stat = dlg.exec();

   // ****************************
   // ***  REPORT PICKED FILE  ***
   // ****************************

   const QString selFile = dlg.selectedFile();
   const char* statStr = (stat == QDialog::Accepted) ? "ACCEPT" : "CANCEL";

   // std::cout << mname << " [#" << callCnt << " " << typeStr << "] " 
   //         << statStr << " \"" << qPrintable (selFile) << "\""
   //         << std::endl;

   static const QString fmt2 ("Selected file (%1): \n \"%2\"");
   const QString msg2 = fmt2 .arg (statStr) .arg (selFile);

   QMessageBox::information (NULL, caption, msg2);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// static
QString RwFileDialog::getOpenFileName (UseType useType,
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       const QString& filter,     // = QString()
                       QString* selectedFilter,   // = NULL
                       int options)               // = 0 (Options flags)
{
   RwOpenFileDialog dlg (useType, parentWid);
   dlg.setWindowTitle (caption);

   if (!initPath.isEmpty()) dlg.selectFile (initPath);
   if (!filter.isEmpty())   dlg.setNameFilter (filter);

   dlg.setSelectedNameFilterPtr (selectedFilter);
   dlg.setOptions (options);

   // *** SHOW DIALOG ***
   const int stat = dlg.exec();
   stat; // (avoid compilation warning)

   const QString retFilePath = dlg.selectedFile();
   return (retFilePath);
}

// static
QString RwFileDialog::getOpenFileName (
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       const QString& filter,     // = QString()
                       QString* selectedFilter,   // = NULL
                       int options)               // = 0 (Options flags)
{
   const QString selFilePath =
      getOpenFileName (For_Other,
                       parentWid, caption, initPath,
                       filter, selectedFilter, options);

   return (selFilePath);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// static
QString RwFileDialog::getSaveFileName (UseType useType,
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       const QString& filter,     // = QString()
                       QString* selectedFilter,   // = NULL
                       int options)               // = 0 (Options flags)
{
   RwSaveFileDialog dlg (useType, parentWid);
   dlg.setWindowTitle (caption);

   if (!initPath.isEmpty()) dlg.selectFile (initPath);
   if (!filter.isEmpty())   dlg.setNameFilter (filter);

   dlg.setSelectedNameFilterPtr (selectedFilter);
   dlg.setOptions (options);

   // *** SHOW DIALOG ***
   const int stat = dlg.exec();
   stat; // (avoid compilation warning)

   const QString retFilePath = dlg.selectedFile();
   return (retFilePath);
}

// static
QString RwFileDialog::getSaveFileName (
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       const QString& filter,     // = QString()
                       QString* selectedFilter,   // = NULL
                       int options)               // = 0 (Options flags)
{
   const QString selFilePath =
      getSaveFileName (For_Other,
                       parentWid, caption, initPath,
                       filter, selectedFilter, options);

   return (selFilePath);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// static
QString RwFileDialog::getExistingDirectory (UseType useType,
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       int options)               // = ShowDirsOnly
{
   RwFileDialog dlg (useType, parentWid);
   dlg.setFileMode (DirectoryLoad);
   dlg.setWindowTitle (caption);

   if (!initPath.isEmpty()) 
      dlg.selectFile (initPath);

   dlg.setOptions (options);

   // *** SHOW DIALOG ***
   const int stat = dlg.exec();
   stat; // (avoid compilation warning)

   const QString retFilePath = dlg.selectedFile();
   return (retFilePath);
}

// static
QString RwFileDialog::getExistingDirectory (
                       QWidget* parentWid,        // = NULL
                       const QString& caption,    // = QString()
                       const QString& initPath,   // = QString()
                       int options)               // = ShowDirsOnly
{
   const QString selFilePath =
      getExistingDirectory (For_Other,
                            parentWid, caption, initPath, options);
   return (selFilePath);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// *************************************************
// ***  class RwFileDialog / Instance Interface  ***
// *************************************************

// constructor
RwFileDialog::RwFileDialog (UseType useType,    /*= For_Und */
                            QWidget* parentWid) /*= NULL    */ 
  : _useType (useType),
    _parentWid (parentWid),
    _windowTitle (),            // QString
    _fileMode (AnyFile),        // FileMode
    _options (0),               // int (Options flags)
    _initPath (),               // QString
    _historyPaths (),           // QStringList
    _nameFilters (),            // QString
    _buttonLabel_Accept (),     // QString
    _buttonLabel_Reject (),     // QString
    _selNameFilterLocal (),     // QString
    _selNameFilterPtr (NULL),   // QString*
    _selectedFiles ()           // QStringList
{
   setDefaultsForUseType();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

RwFileDialog::~RwFileDialog()
{
}

void RwFileDialog::setWindowTitle (const QString& winTitle)
{
   _windowTitle = winTitle;
}

void RwFileDialog::setFileMode (FileMode mode)
{
   _fileMode = mode;
}

void RwFileDialog::setOptions (int options) // Options flags
{
   _options = options;
}

void RwFileDialog::selectFile (const QString& filename)  // initPath
{
   _initPath = filename;

   if (!_initPath.isEmpty())
   {
      _historyPaths.removeAll (_initPath);
      _historyPaths.prepend (_initPath);
   }
}

void RwFileDialog::setHistory (const QStringList& paths)
{
   // History is automatically provided for many of the use types.

   // Note [9-2013, RW 4.8.5]: Application-level history is not supported 
   // in native (static function) mode. It is supported only by the Qt 
   // (QFileDialog-) Instance file chooser.

   const QStringList saveHistoryPaths = _historyPaths;
   const int saveCnt = saveHistoryPaths.count();

   _historyPaths = paths;

   for (int inx = 0; inx < saveCnt; ++inx)
   {
      const QString savePath = saveHistoryPaths [inx];
      if (!_historyPaths.contains (savePath))
         _historyPaths.append (savePath);
   }

   // If the intitial path was also set, put that as the most recent
   // file in the history.
   if (!_initPath.isEmpty())
   {
      _historyPaths.removeAll (_initPath);
      _historyPaths.prepend (_initPath);
   }
}

void RwFileDialog::setNameFilter (const QString& nameFilterSpec) 
{
   // The nameFilterSpec can contain multiple filters seperated by ";;".
   // Filter specs are automatically provided for many of the use types.

   _nameFilters = nameFilterSpec;
}

void RwFileDialog::setNameFilters (const QStringList& filterList)
{
   const QString nameFilterSpec = filterList.join (";;");
   setNameFilter (nameFilterSpec);
}

void RwFileDialog::selectNameFilter (const QString& selFilter)
{
   _selNameFilterLocal = selFilter;

   if (_selNameFilterPtr)
      *_selNameFilterPtr = selFilter;
}

void RwFileDialog::setSelectedNameFilterPtr (QString* strPtr)
{
   _selNameFilterPtr = strPtr;
   if (_selNameFilterPtr)
      _selNameFilterLocal = *_selNameFilterPtr;
}

void RwFileDialog::setLabelText (RwFile::LabelId id, const QString& text)
{
   switch (id)
   {
      case RwFile::Accept: _buttonLabel_Accept = text;  break;
      case RwFile::Reject: _buttonLabel_Reject = text;  break;
      default:
        rwAssert (("Unsupported LabelId", 0));
   }
}

QString RwFileDialog::selectedFile() const
{
   // first file, if multiple were selected.
   const QString selFile = _selectedFiles .value (0);
   return selFile;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

int RwFileDialog::exec() 
{
   // Returns QDialog::Accepted or QDialog::Rejected

   // ***************************
   // ***  Show File Chooser  ***
   // ***************************

   _selectedFiles.clear();

   const int stat = 
      _useNativeChooser ? execNative()     // Show and Execute Native Dialog
                        : execInstance();  // Show and Execute Qt Instance

   // ***********************************
   // ***  Post-Selection Processing  ***
   // ***********************************
 
   if (stat == QDialog::Accepted)
   {
      if (SAVE_PICKED_TO_HISTORY_ENA)
      {
         recordPickedFileInHistory();
      }

      if (COPY_PICKED_TO_CLIPBOARD_ENA)
      {
         const QString selFile = selectedFile();
         if (!selFile.isEmpty())
         {
            const QString nativeFile = QDir::toNativeSeparators (selFile);
            RwQtUtils::setClipboardText (nativeFile);
         }
      }
   }

   return (stat); // QDialog::Accepted or QDialog::Rejected
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void RwFileDialog::setDefaultsForUseType()
{
   // ******************************************************************
   // ***  Default File Filter Initializations (for some use types)  ***
   // ******************************************************************

   // Note: This method sets some of the file chooser parameter settings,
   // so should be performed before customizations performed by the 
   // client. It is called from the RwFileDialog constructor.

   // See definitions in LoadSaveMgr.cpp.
   switch (_useType)
   {
      case For_Model:   _nameFilters = FILTER_STR_MODEL_FILES;   break;
      case For_RuleSet: _nameFilters = FILTER_STR_RULESET_FILES; break;
      case For_OptSet:  _nameFilters = FILTER_STR_OPTSET_FILES;  break;
      case For_GblSet:  _nameFilters = FILTER_STR_GBLSET_FILES;  break;
   }

   // ***************************
   // ***  Default Histories  ***
   // ***************************
      
   // Note [9-2013, RW 4.8.5]: Except for the "initialization path" for a 
   // single recent file, application-level history is not supported 
   // in native (static function) mode. The full history queue is 
   // supported only by the Qt (QFileDialog-) Instance file chooser.
 
   const LoadSaveMgr* mgr = LoadSaveMgrInst;

   QString recentPath;
   switch (_useType)
   {
       case For_Model:   recentPath = mgr->recentModelPath();    break;
       case For_RuleSet: recentPath = mgr->recentRuleSetPath();  break;
       case For_OptSet:  recentPath = mgr->recentOptSetPath();   break;
       case For_GblSet:  recentPath = mgr->recentGblSetPath();   break;
       case For_Obj:     recentPath = mgr->recentObjPath();      break;
       case For_Output:  recentPath = mgr->recentOutputPath();   break;
   }

   if (!recentPath.isEmpty())
   {
      _initPath = recentPath;
      _historyPaths.append (recentPath);
   }

   switch (_useType)
   {
       case For_Model:   
          mgr->appendRecentModelDirs (_historyPaths);
          mgr->appendRecentObjDirs   (_historyPaths);
          break;

       case For_RuleSet: 
          mgr->appendRecentRuleSetDirs (_historyPaths);
          mgr->appendRecentModelDirs   (_historyPaths);
          break;

       case For_OptSet:  
          mgr->appendRecentOptSetDirs  (_historyPaths);
          mgr->appendRecentRuleSetDirs (_historyPaths);
          mgr->appendRecentModelDirs   (_historyPaths);
          break;

       case For_GblSet:  
          mgr->appendRecentGblSetDirs  (_historyPaths);
          mgr->appendRecentRuleSetDirs (_historyPaths);
          mgr->appendRecentModelDirs   (_historyPaths);
          break;

       case For_Obj:     
          mgr->appendRecentObjDirs    (_historyPaths);
          mgr->appendRecentModelDirs  (_historyPaths);
          mgr->appendRecentOutputDirs (_historyPaths);
          break;

       case For_Output:  
          mgr->appendRecentOutputDirs (_historyPaths);
          mgr->appendRecentModelDirs  (_historyPaths);
          break;

       case For_Und:   
       case For_Other:   
       default:
          mgr->appendRecentModelDirs  (_historyPaths);
          mgr->appendRecentObjDirs    (_historyPaths);
          mgr->appendRecentOutputDirs (_historyPaths);
          break;
   }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// private
int RwFileDialog::execNative()
{
   // ******************************************************
   // ***  Show QFileDialog w/static functions (Native)  ***
   // ******************************************************

   //------------------------------------------------
   // Returns QDialog::Accepted or QDialog::Rejected
   // Sets: QString     _selNameFilterLocal
   // Sets: QString*    *_selNameFilterPtr
   // Sets: QStringList _selectedFiles
   //------------------------------------------------

   // NOTE [Phil, 9-2013, Qt 4.8.5]: The QFileDialog's static function 
   // API lacks support for an application-level file history.  So the 
   // QStringList _historyPaths data is not used here.
   //
   // Ditto for overrides to the Accept and Reject button text.

   QString selFile;
   _selectedFiles.clear();

   const QString winTitle =
      SHOW_WINDOW_TITLE_STR_NATIVE 
         ? (WINDOW_TITLE_STR_NATIVE + " " + _windowTitle)
         : _windowTitle;

   QFileDialog::Options opts (0);
   if ((_options & ShowDirsOnly) != 0)
      opts |= QFileDialog::ShowDirsOnly;
   if ((_options & DontConfirmOverwrite)!= 0) 
      opts |= QFileDialog::DontConfirmOverwrite;

   switch (_fileMode)
   {
      // *******************************************************
      // ***  The name of a file, whether it exists or not.  ***
      // *******************************************************

      case AnyFile:  
      {
         selFile =
            QFileDialog::getSaveFileName (
               _parentWid,            // QWidget* parent
               winTitle,              // const QString& caption
               _initPath,             // const QString& dir
               _nameFilters,          // const QString& filter
               &_selNameFilterLocal,  // QString* selectedFilter
               opts);                 // QFileDialog::Options 

         break;
      }
    
      // *********************************************
      // ***  The name of a single existing file.  ***
      // *********************************************

      case ExistingFile:  
      {
         selFile =
            QFileDialog::getOpenFileName (
               _parentWid,            // QWidget* parent
               winTitle,              // const QString& caption
               _initPath,             // const QString& dir
               _nameFilters,          // const QString& filter
               &_selNameFilterLocal,  // QString* selectedFilter
               opts);                 // QFileDialog::Options options=0

         break;
      }

      // *********************************
      // ***  The name of a directory  ***
      // *********************************

      case DirectorySave: 
      case DirectoryLoad: 
      {
         selFile =
            QFileDialog::getExistingDirectory (
               _parentWid,    // QWidget* parent
               winTitle,      // const QString& caption
               _initPath,     // const QString& dir
               opts);         // QFileDialog::Options options=0

         break;
      }

      // ***************************************************
      // ***  The names of zero or more existing files.  ***
      // ***************************************************

      case ExistingFiles: // (multiple files). 
      {
         _selectedFiles =
            QFileDialog::getOpenFileNames (
               _parentWid,            // QWidget* parent
               winTitle,              // const QString& caption
               _initPath,             // const QString& dir
               _nameFilters,          // const QString& filter
               &_selNameFilterLocal,  // QString* selectedFilter
               opts);                 // QFileDialog::Options options=0

         break;
      }

      default:
         QApplication::beep();
   }

   // ***********************************
   // ***  Post-Selection Processing  ***
   // ***********************************

   if (_selectedFiles.isEmpty() && !selFile.isEmpty())
   {
      _selectedFiles.append (selFile);
   }

   if (_selNameFilterPtr)
   {
      *_selNameFilterPtr = _selNameFilterLocal;
   }

   return (_selectedFiles.isEmpty() ? QDialog::Rejected : QDialog::Accepted);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// private
int RwFileDialog::execInstance()
{
   // **********************************************************
   // ***  Show QFileDialog as an instance (non-native, Qt)  ***
   // **********************************************************

   //------------------------------------------------
   // Returns QDialog::Accepted or QDialog::Rejected
   // Sets: QString     _selNameFilterLocal
   // Sets: QString*    *_selNameFilterPtr
   // Sets: QStringList _selectedFiles
   //------------------------------------------------

   const QString winTitle =
      SHOW_WINDOW_TITLE_STR_QtINST 
         ? (WINDOW_TITLE_STR_QtINST + " " + _windowTitle)
         : _windowTitle;

   QFileDialog::Options opts (0);
   if ((_options & ShowDirsOnly) != 0)
      opts |= QFileDialog::ShowDirsOnly;
   if ((_options & DontConfirmOverwrite)!= 0) 
      opts |= QFileDialog::DontConfirmOverwrite;

   QFileDialog dlg (_parentWid, winTitle, _nameFilters);
   dlg.setOptions (opts);

   QGui::setWindowLogoIcon (&dlg);
   dlg.setAttribute (Qt::WA_AlwaysShowToolTips, true);

   switch (_fileMode)
   {
      case AnyFile:       dlg.setFileMode (QFileDialog::AnyFile);       break;
      case ExistingFile:  dlg.setFileMode (QFileDialog::ExistingFile);  break;
      case DirectorySave: dlg.setFileMode (QFileDialog::Directory);     break;
      case DirectoryLoad: dlg.setFileMode (QFileDialog::Directory);     break;
      case ExistingFiles: dlg.setFileMode (QFileDialog::ExistingFiles); break;
   }

   switch (_fileMode)
   {
      case AnyFile:       dlg.setAcceptMode (QFileDialog::AcceptSave);  break;
      case ExistingFile:  dlg.setAcceptMode (QFileDialog::AcceptOpen);  break;
      case DirectorySave: dlg.setAcceptMode (QFileDialog::AcceptSave);  break;
      case DirectoryLoad: dlg.setAcceptMode (QFileDialog::AcceptOpen);  break;
      case ExistingFiles: dlg.setAcceptMode (QFileDialog::AcceptOpen);  break;
   }

   if (!_historyPaths.empty())
      dlg.setHistory (_historyPaths);

   if (!_initPath.isEmpty())
      dlg.selectFile (_initPath);

   if (!_nameFilters.isEmpty())
   {
      dlg.setNameFilter (_nameFilters);

      if (!_selNameFilterLocal.isEmpty())
         dlg.selectNameFilter (_selNameFilterLocal);
   }

   if (!_buttonLabel_Accept.isEmpty())
   {
      dlg.setLabelText (QFileDialog::Accept, _buttonLabel_Accept);
   }

   if (!_buttonLabel_Reject.isEmpty())
   {
      dlg.setLabelText (QFileDialog::Reject, _buttonLabel_Reject);
   }

   // ***************************************
   // ***  Show and Execute File Chooser  ***
   // ***************************************

   const int stat = dlg.exec();  // QDialog::Accepted or QDialog::Rejected

   // ***********************************
   // ***  Post-Selection Processing  ***
   // ***********************************

   if (stat == QDialog::Accepted)
   {
      _selectedFiles = dlg.selectedFiles();
   }

   _selNameFilterLocal = dlg.selectedNameFilter();
   if (_selNameFilterPtr)
   {
      *_selNameFilterPtr = _selNameFilterLocal;
   }

   return (stat);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void RwFileDialog::recordPickedFileInHistory()
{
   // ****************************************************
   // ***  Record Selected File for RiverWare History  ***
   // ****************************************************

   // Note: Even though History is not supported in all file chooser modes.
   // (See relevant notes in this file), the History saved here IS also 
   // used by various dynamic "reload" submenus -- both recent files and 
   // directories.

   const QString firstFile = _selectedFiles .value (0);
   if (!firstFile.isEmpty())
   {
      LoadSaveMgr* mgr = LoadSaveMgrInst;

      bool saveOp (false); // or loadOp?
      switch (_fileMode)
      {
         case AnyFile:        saveOp = true;   break;   
         case ExistingFile:   saveOp = false;  break; 
         case DirectorySave:  saveOp = true;   break; 
         case DirectoryLoad:  saveOp = false;  break; 
         case ExistingFiles:  saveOp = false;  break; 
      }

      switch (_useType)
      {
         case For_Und:     mgr->recordDirPath     (firstFile, saveOp);  break; 
         case For_Other:   mgr->recordDirPath     (firstFile, saveOp);  break; 
         case For_Model:   mgr->recordModelPath   (firstFile, saveOp);  break; 
         case For_RuleSet: mgr->recordRuleSetPath (firstFile, saveOp);  break; 
         case For_OptSet:  mgr->recordOptSetPath  (firstFile, saveOp);  break; 
         case For_GblSet:  mgr->recordGblSetPath  (firstFile, saveOp);  break; 
         case For_Obj:     mgr->recordObjPath     (firstFile, saveOp);  break; 
         case For_Output:  mgr->recordOutputPath  (firstFile, saveOp);  break; 
      }
   }
}

//--- (end RwFileDialog.cpp) ---