// $Id: SctSetSumFuncDlg.cpp,v 1.7 2011/05/10 19:41:01 philw Exp $
//=======================================================
//+class
//
// This module:
//   class SctSetSumFuncDlg          : public QDialog
//   class SctSetSumFuncDlg::RowItem : public QObject
//
// See also data model module:
//   class SctSumFuncAssignSpec
//   class SctSumFuncAssignSpec::Item
//
// Dialog to edit a SctSumFuncAssignSpec instance, which represents the
// inputs to the operation to reassign of Aggregation Summary Functions
// to all of the Slots in an SCT. This dialog also includes an operation
// to perform that assignment.
//
// Operation Buttons:
//   "Restore RiverWare Default"
//   "Cancel Changes:
//   "Apply to SCT"
//   "Close"
//
//-

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

static const int MIN_ROW_ITEMS (3); 
static const int MAX_ROW_ITEMS (30);

static const int AdjustDelayMsecs (200);  // milliseconds

static const int COL_UNIT_ENA   ( 0);  // Unit Type
static const int COL_UNIT_COMBO ( 1);  //  
static const int COL_SPACER_1   ( 2);  //-----
static const int COL_SLOT_ENA   ( 3);  // Slot Name (Part)
static const int COL_SLOT_EDIT  ( 4);  // 
static const int COL_GUS        ( 5);  //
static const int COL_SPACER_2   ( 6);  //-----
static const int COL_FUNC_COMBO ( 7);  // Summary Function 
static const int COL_SPACER_3   ( 8);  //-----
static const int COL_BUT_INSERT ( 9);  // 
static const int COL_BUT_DELETE (10);  //
static const int COL_SLOT_CNT   (11);  // Slots (Count)

static const int LINE_EDIT_EXTRA_WIDTH (12);

static const QString TitleLabelText (QObject::tr (
  "Each slot in the SCT will be assigned a summary function "
  "based on the first matching Unit Type or Slot Name in the "
  "following list."));

static const QString BotDescLabelText (QObject::tr (
  "Note: Slot Name matches are based on the slot's name "
  "<i>containing</i> the specified string."));

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

#ifndef SctSetSumFuncDlgINCLUDED
#include "SctSetSumFuncDlg.hpp"
#endif

#include "qt/ui_SctSetSumFuncWidgets.h"

#include <QAction>
#include <QApplication>
#include <QButtonGroup>
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QRegExp>
#include <QRegExpValidator>
#include <QSpacerItem>
#include <QTimer>

#ifndef SctDialogINCLUDED
#include "SctDialog.hpp"
#endif

#ifndef DlgGeometryMgrINCLUDED
#include "DlgGeometryMgr.hpp"
#endif

#ifndef RootSelectionINCLUDED
#include "RootSelection.hpp"
#endif

#ifndef GusSelectorINCLUDED
#include "GusSelector.hpp"
#endif

#undef slots

///////////////////////// end of qt includes /////////////////////////

#ifndef SctConfigINCLUDED
#include "SctConfig.hpp"
#endif

#ifndef SctModelDataINCLUDED
#include "SctModelData.hpp"
#endif

#ifndef SystemINCLUDED
#include "System.hpp"
#endif

#ifndef rwErrorINCLUDED
#include "rwError.hpp"
#endif

#ifndef cwEnvINCLUDED
#include "cwEnv.hpp"
#endif

// #ifndef SimWorkspaceINCLUDED
// #include "SimWS.hpp"
// #endif

#ifndef QGuiINCLUDED
#include "QGui.hpp"
#endif

#ifndef RwQtUtilsINCLUDED
#include "RwQtUtils.hpp"
#endif

#ifndef RwQPixmap16INCLUDED
#include "RwQPixmap16.hpp"
#endif

#ifndef RwQtIconsINCLUDED
#include "RwQtIcons.hpp"
#endif

#include <iostream>
#include "rwStr.hpp"

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

// static data
RootSelection* SctSetSumFuncDlg::RowItem::_slotNamePickerRootSel (NULL);

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

// ********************************************
// ***  class  SctSetSumFuncDlg :: QDialog  ***
// ********************************************

// constructor
SctSetSumFuncDlg::SctSetSumFuncDlg (SctDialog* sctDlg,
                                    const SctSumFuncAssignSpec& origSpec)
   : QDialog (NULL, "SctSetSumFuncDlg"),
     _sctDlg (sctDlg),
     _origSpec (origSpec),

     _ui (*(new Ui_SctSetSumFuncWidgets())),
     _itemWidgetsGrid (NULL),
     _colLabel_unitType (NULL),
     _colLabel_slotName (NULL),
     _colLabel_sumFunc (NULL),
     _colLabel_slotCount (NULL),
     _colSpacer1 (NULL),
     _colSpacer2 (NULL),
     _colSpacer3 (NULL),

     _itemWidgetRows(),
     _processingUserEdit_inProgress (false),
     _settingGui_inProgress (false),
     _slotNameValidator (NULL),
     _adjustSizeTimer (NULL)
{
   static const char (*mname) ("SctSetSumFuncDlg ctor");

   // *************************************
   // ***  Build and Configure Widgets  ***
   // *************************************

   _ui.setupUi (this);

   _itemWidgetsGrid = new QGridLayout (_ui._itemWidgetsContainer);
   _itemWidgetsGrid->setObjectName ("_itemWidgetsGrid");

   // Create Slot Name Item String Validator, for QLineEdit.
   const QRegExp goodCharsRE ("[a-zA-Z_][a-zA-Z0-9_ ]*");
   _slotNameValidator = new QRegExpValidator (goodCharsRE, this);
   _slotNameValidator -> setObjectName ("_slotNameValidator");

   // This is only for QMainWindows, not QDialogs
   //-- QWidget* cenWid = centralWidget();
   //-- QLayout* cenLayout (cenWid ? cenWid->layout() : NULL);
   //-- if (cenLayout)
   //-- {
   //--    cenLayout->setContentsMargins (11,11,11,11); // (lft, top, rgt, bot)
   //-- }

   buildGridHeader();
   initWidgets();
   initConnections();

   // Set Window Icon, and Stuff.
   QGui::setWindowLogoIcon (this);
   setAttribute (Qt::WA_AlwaysShowToolTips, true);
   setAttribute (Qt::WA_DeleteOnClose, true);

   // ******************
   // ***  Load GUI  ***
   // ******************

   setGuiSpec (_origSpec);
   updateSensitivity();

   updateGeometry();
   adjustSize();
}

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

// destructor
SctSetSumFuncDlg::~SctSetSumFuncDlg ()
{
   // Note: Qt child Widgets are deleted automatically.

   cancelAdjustSize();

   // Delete ui structure built from Qt4 Designer
   Ui_SctSetSumFuncWidgets* uiPtr (&_ui);
   delete uiPtr;
}

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

void SctSetSumFuncDlg::recomputeSlotCounts()
{
   static const char* mname ("SctSetSumFuncDlg::recomputeSlotCounts");
   static int callCnt (0);
   ++callCnt;

   // std::cout << mname << " [#" << callCnt << "]" << std::endl;

   if (!rwAssert (_sctDlg != NULL)) return;
   //------------------------------------>>

   SctConfig* sctCfg = _sctDlg->sctConfig();
   SctModelData* mDat = _sctDlg->sctModelDat();

   if (!rwAssert (sctCfg != NULL)) return;
   if (!rwAssert (mDat != NULL)) return;
   //----------------------------------->>

   // Note: This deals only with the series (and table series) slots in 
   // the SCT.  Aggregation Summary Functions are not relevant for Scalar, 
   // Table, and List slots on the other SCT tabs.

   // ****************************************************
   // ***  (1) Clear SctSumFuncAssignSpec Slot Counts  ***
   // ****************************************************

   const int rowCnt = _itemWidgetRows.count();
   for (int rowInx1 = 0;  rowInx1 < rowCnt;  ++rowInx1)
   {
      RowItem* rowItem = _itemWidgetRows [rowInx1];
      if (rowItem)
         rowItem->clearSlotCount();
   }

   // ****************************
   // ***  (2) Prepare Counts  ***
   // ****************************
   
   const int slotCnt = sctCfg->slotCnt();
   for (int slotInx = 0;  slotInx < slotCnt;  ++slotInx)
   {
      const SlotColRef scRef = mDat->getSlotColRef (slotInx);

      for (int rowInx2 = 0;  rowInx2 < rowCnt;  ++rowInx2)
      {
         RowItem* rowItem = _itemWidgetRows [rowInx2];
         if (rowItem)
         {
            const bool matched = rowItem->countSlotMatch (scRef);
            if (matched) break;
            //----------------- 
         }
      }
   }

   // ***************************************
   // ***  (3) Update Count Value Labels  ***
   // ***************************************

   for (int rowInx3 = 0;  rowInx3 < rowCnt;  ++rowInx3)
   {
      RowItem* rowItem = _itemWidgetRows [rowInx3];
      if (rowItem)
         rowItem->updateSlotCountLabel();
   }
}

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

void SctSetSumFuncDlg::buildGridHeader()
{
   _colLabel_unitType  = new QLabel (this);
   _colLabel_slotName  = new QLabel (this);
   _colLabel_sumFunc   = new QLabel (this);
   _colLabel_slotCount = new QLabel (this);

   _colLabel_unitType  -> setObjectName ("_colLabel_unitType");
   _colLabel_slotName  -> setObjectName ("_colLabel_slotName");
   _colLabel_sumFunc   -> setObjectName ("_colLabel_sumFunc");
   _colLabel_slotCount -> setObjectName ("_colLabel_slotCount");
   
   _colLabel_unitType  -> setTextFormat (Qt::RichText);
   _colLabel_slotName  -> setTextFormat (Qt::RichText);
   _colLabel_sumFunc   -> setTextFormat (Qt::RichText);
   _colLabel_slotCount -> setTextFormat (Qt::RichText);
   
   _colLabel_unitType  -> setText (tr ("<b>Unit Type</b>"));
   _colLabel_slotName  -> setText (tr ("<b>Slot Name (Part)</b>"));
   _colLabel_sumFunc   -> setText (tr ("<b>Summary Function</b>"));
   _colLabel_slotCount -> setText (tr ("<b>Slots</b>"));

   _colSpacer1 = 
     new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed);
   _colSpacer2 = 
     new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed);
   _colSpacer3 = 
     new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed);

   QGridLayout* gl = _itemWidgetsGrid;

   gl->addWidget (_colLabel_unitType,  0, COL_UNIT_ENA,  1, 2); // colspan=2
   gl->addItem   (_colSpacer1,         0, COL_SPACER_1);
   gl->addWidget (_colLabel_slotName,  0, COL_SLOT_ENA,  1, 3); // colspan=3
   gl->addItem   (_colSpacer2,         0, COL_SPACER_2);
   gl->addWidget (_colLabel_sumFunc,   0, COL_FUNC_COMBO);
   gl->addItem   (_colSpacer3,         0, COL_SPACER_3);
   gl->addWidget (_colLabel_slotCount, 0, COL_SLOT_CNT);
}

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

void SctSetSumFuncDlg::initWidgets()
{
   // This is only for QMainWindows, not QDialogs
   //--  // Hide the status bar at the bottom of the QMainWindow
   //--  QStatusBar* sbar = statusBar();
   //--  if (sbar)
   //--     sbar->hide();

   _ui._itemWidgetsContainer -> 
      setSizePolicy (QSizePolicy::MinimumExpanding,  // horizontal
                     QSizePolicy::Fixed);            // vertical

   _ui._restoreDefaultsButton -> setDefault (false);
   _ui._cancelChangesButton   -> setDefault (false);
   _ui._applyButton           -> setDefault (false);
   _ui._closeButton           -> setDefault (false);

   _ui._restoreDefaultsButton -> setAutoDefault (false);
   _ui._cancelChangesButton   -> setAutoDefault (false);
   _ui._applyButton           -> setAutoDefault (false);
   _ui._closeButton           -> setAutoDefault (false);

   _ui._titleLabel   -> setTextFormat (Qt::RichText);
   _ui._botDescLabel -> setTextFormat (Qt::RichText);
   _ui._titleLabel   -> setWordWrap (true);
   _ui._botDescLabel -> setWordWrap (true);
   _ui._titleLabel   -> setText (TitleLabelText);
   _ui._botDescLabel -> setText (BotDescLabelText);
}

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

void SctSetSumFuncDlg::initConnections()
{
   // *****************************
   // ***  QPushButton Signals  ***
   // *****************************

   connect (_ui._restoreDefaultsButton, SIGNAL (clicked()),
            SLOT (restoreDefaultsButton_clicked()));

   connect (_ui._cancelChangesButton, SIGNAL (clicked()),
            SLOT (cancelChangesButton_clicked()));

   connect (_ui._applyButton, SIGNAL (clicked()),
            SLOT (applyButton_clicked()));

   connect (_ui._closeButton, SIGNAL (clicked()),
            SLOT (closeButton_clicked()));
}

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

void SctSetSumFuncDlg::updateSensitivity()
{
   static const char* mname ("SctSetSumFuncDlg::updateSensitivity");

   const SctSumFuncAssignSpec guiSpecRec = guiSpec(); 
   const int itemListCnt = guiSpecRec.itemListCount();
   itemListCnt;  // (avoid compilation warning)

   // *********************
   // ***  PushButtons  ***
   // *********************

   const bool isAlreadyFactoryValue = guiSpecRec.isFactoryValue();
   _ui._restoreDefaultsButton->setEnabled (!isAlreadyFactoryValue);

   const bool isOrigSpec (guiSpecRec == _origSpec);
   _ui._cancelChangesButton->setEnabled (!isOrigSpec);

   // ***************
   // ***  Items  ***
   // ***************

   const int rowCnt = _itemWidgetRows.count();
   // std::cout << mname << " rowCnt: " << rowCnt << std::endl;

   for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
   {
      RowItem* rowItem = _itemWidgetRows [rowInx];
      if (rowItem)
         rowItem->updateSensitivity();
   }
}

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

SctSumFuncAssignSpec SctSetSumFuncDlg::guiSpec() const
{
   // Read widget values in _ui._itemWidgetsContainer
   const QList<SctSumFuncAssignSpec::Item> itemList = readItemRows();

   SctSumFuncAssignSpec retSpec;
   retSpec.setItemList (itemList);

   return retSpec;
}

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

void SctSetSumFuncDlg::setGuiSpec (const SctSumFuncAssignSpec& spec)
{
   //-------------------------------------------------
   const bool inProgressSave = _settingGui_inProgress;
   _settingGui_inProgress = true;
   //-------------------------------------------------

   // Rebuild widgets in _ui._itemWidgetsContainer
   const int rowChange = rebuildItemRows (spec.itemList());
   rowChange;  // (avoid compilation warning)

   updateSensitivity();
   recomputeSlotCounts();

   //-------------------------------------------------
   _settingGui_inProgress = inProgressSave;
   //-------------------------------------------------

   updateGeometry();

   if (rowChange > 0)
   {
      // Resize the dialog only if the number of rows has increased.
      schedAdjustSize();
   }
}

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

void SctSetSumFuncDlg::restoreOrigSpec()
{
   setGuiSpec (_origSpec);
   updateSensitivity();
}

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

void SctSetSumFuncDlg::processUserEdit()
{
   static const char* mname ("SctSetSumFuncDlg::processUserEdit");
   // std::cout << mname << std::endl;

   if (_settingGui_inProgress) return;
   //------------------------------->>

   //-----------------------------------------------------
   const bool inProgressSave = _processingUserEdit_inProgress;
   _processingUserEdit_inProgress = true;
   //-----------------------------------------------------

   updateSensitivity();
   recomputeSlotCounts();

   //------------------------------------------
   _processingUserEdit_inProgress = inProgressSave; 
   //------------------------------------------
}

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

// Returns the change in the number of rows.
int SctSetSumFuncDlg::rebuildItemRows (
                         const QList<SctSumFuncAssignSpec::Item>& itemList)
{
   static const char* mname ("SctSetSumFuncDlg::rebuildItemRows");

   const int newRowCnt = itemList.count();

   // std::cout << mname << " [rows " << newRowCnt << "]" << std::endl;

   int growCnt (0);
   int shrinkCnt (0);

   // Grow the Item Widget Row List, as necessary.
   while (_itemWidgetRows.count() < newRowCnt)
   {
      appendItemWidgetRow();
      ++growCnt;
   }

   // Shrink the Item Widget Row List, as necessary.
   while (_itemWidgetRows.count() > newRowCnt)
   {
      deleteLastItemWidgetRow();
      ++shrinkCnt;
   }

   // Copy the given Item List Data into the QComboBox and QLineEdits.
   const int itemWidgetRowsCnt = _itemWidgetRows.count();
   for (int rowInx = 0;  rowInx < newRowCnt;  ++rowInx)
   {
      const SctSumFuncAssignSpec::Item& itemData = itemList [rowInx];

      // Note: The code at the beginning of this method is intended to
      // insure that the Item Widget Row List is the same length as the
      // given Item List (newRowCnt).  So this check isn't supposed 
      // to be necessary.  It is just a "safety".
      //   
      if (rowInx < itemWidgetRowsCnt) 
      {
         RowItem* rowItem = _itemWidgetRows [rowInx];
         if (rwAssert (rowItem != NULL))
            rowItem -> setRowItemData (itemData);
      }
   }

   enableInsertButtons (newRowCnt < MAX_ROW_ITEMS);
   enableDeleteButtons (newRowCnt > MIN_ROW_ITEMS);

   // Return the change in the number of rows.
   return (growCnt - shrinkCnt);
}

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

QList<SctSumFuncAssignSpec::Item> SctSetSumFuncDlg::readItemRows() const
{
   QList<SctSumFuncAssignSpec::Item> itemList;

   const int rowCnt = _itemWidgetRows.count();
   for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
   {
      const RowItem* rowItem = _itemWidgetRows [rowInx];
      if (rwAssert (rowItem != NULL))
      {
         SctSumFuncAssignSpec::Item itemVal = rowItem->rowItemDataRef();
         itemVal.setIsLastItem (rowInx == (rowCnt-1));
         itemList.append (itemVal);
      }
   }

   return (itemList);
}

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

void SctSetSumFuncDlg::appendItemWidgetRow()
{
   static const char* mname ("SctSetSumFuncDlg::appendItemWidgetRow");

   // ******************************************
   // ***  Create and Append New Widget Row  ***
   // ******************************************

   const int newInx = _itemWidgetRows.count();

   RowItem* newRowItem = 
      new RowItem (this, _itemWidgetsGrid, newInx); // [0..]

   connect (newRowItem, SIGNAL (valueChanged (RowItem*, int)),
            SLOT (rowItem_valueChanged (RowItem*, int)));

   connect (newRowItem, SIGNAL (insertAboveRequest (RowItem*, int)),
            SLOT (rowItem_insertAboveRequest (RowItem*, int)));

   connect (newRowItem, SIGNAL (removeRequest (RowItem*, int)),
            SLOT (rowItem_removeRequest (RowItem*, int)));

   _itemWidgetRows.append (newRowItem);
}

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

void SctSetSumFuncDlg::deleteLastItemWidgetRow()
{
   // ********************************
   // ***  Delete Last Widget Row  ***
   // ********************************

   const int rowCnt = _itemWidgetRows.count();
   if (rowCnt > 0)
   {
      // Remove first widget row item
      RowItem* delRowItem = _itemWidgetRows.takeLast();
      if (delRowItem)
      {
         delete delRowItem;
      }
   }
   else
   {
      QApplication::beep();
   }
}

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

int SctSetSumFuncDlg::rowIndexOfWidget (const QObject* qobj) const
{
   const int rowCnt = _itemWidgetRows.count();
   for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
   {
      const RowItem* rowItem = _itemWidgetRows [rowInx];
      if (rowItem && rowItem->containsQObject (qobj))
      {
         return (rowInx);  // [0..]
      }
   }

   return (-1);  // Widget not found
}

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

void SctSetSumFuncDlg::enableInsertButtons (bool ena)
{
   const int rowCnt = _itemWidgetRows.count();
   for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
   {
      RowItem* rowItem = _itemWidgetRows [rowInx];
      if (rowItem)
         rowItem->enableInsertButton (ena);
   }
}

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

void SctSetSumFuncDlg::enableDeleteButtons (bool ena)
{
   const int rowCnt = _itemWidgetRows.count();
   for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
   {
      RowItem* rowItem = _itemWidgetRows [rowInx];
      if (rowItem)
         rowItem->enableDeleteButton (ena);
   }
}

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

void SctSetSumFuncDlg::schedAdjustSize()
{
   if (_adjustSizeTimer == NULL)
   {
      _adjustSizeTimer = new QTimer (this);
      _adjustSizeTimer->setObjectName ("_adjustSizeTimer");

      connect (_adjustSizeTimer, SIGNAL (timeout()),
               SLOT (doAdjustSize()));
   }
   else
   {
      _adjustSizeTimer->stop();
   }

   _adjustSizeTimer->setSingleShot (true);
   _adjustSizeTimer->start (AdjustDelayMsecs); // [milliseconds]
}

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

void SctSetSumFuncDlg::cancelAdjustSize()
{
   if (_adjustSizeTimer != NULL)
   {
      _adjustSizeTimer->stop();
      delete _adjustSizeTimer;
      _adjustSizeTimer = NULL;
   }
}

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

void SctSetSumFuncDlg::showEvent (QShowEvent* evt)
{
   // Call base class method
   QDialog::showEvent (evt);

   // Conditionally restore dialog geometry from prior hide.
   DlgGeometryMgr::processShow ("SctSetSumFuncDlg", NULL, this, evt);
}

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

void SctSetSumFuncDlg::hideEvent (QHideEvent* evt)
{
   // Save dialog geometry.
   DlgGeometryMgr::processHide ("SctSetSumFuncDlg", NULL, this, evt);

   // Call base class method
   QDialog::hideEvent (evt);
}

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

// private slot
void SctSetSumFuncDlg::doAdjustSize()
{
   static const char* mname ("SctSetSumFuncDlg::doAdjustSize");
   // std::cout << mname << std::endl;

   adjustSize();
}

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

// private slot
void SctSetSumFuncDlg::rowItem_valueChanged (RowItem*, int rowInx)
{
   static const char* mname ("SctSetSumFuncDlg::rowItem_valueChanged");

   // std::cout << mname << " [" << rowInx << "]" 
   //           << std::endl;

   processUserEdit();
}

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

// private slot
void SctSetSumFuncDlg::rowItem_insertAboveRequest (RowItem* rowItem, 
                                                   int rowInx)
{
   static const char* mname ("SctSetSumFuncDlg::insertAboveRequest");

   // std::cout << mname << " [" << rowInx << "]" 
   //           << std::endl;

   if (rowInx < 0) return;
   //-------------------->>

   SctSumFuncAssignSpec spec = guiSpec();
   QList<SctSumFuncAssignSpec::Item> itemList = spec.itemList();
   const int itemCnt = itemList.count();

   const Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();  
   const bool shiftPressed = (mods & Qt::ShiftModifier) != 0;
   const bool doDuplicate = shiftPressed;

   // Define a new Spec Item value.
   SctSumFuncAssignSpec::Item newItem;  // initially Empty
   if (doDuplicate)
   {
      newItem = itemList [rowInx];

      if (rowInx == (itemCnt-1))
      { 
         newItem.setIsLastItem (false);
         newItem.setUnitType (FLOW, true);  // setEnabled
      }
   }
   else if (rowInx > 0)
   {
      newItem = itemList [rowInx-1];
   }
   else 
   {
      newItem.setUnitType (FLOW, true);  // setEnabled
   }
   
   // Insert new Spec Item value at the Line Index
   itemList.insert (rowInx, newItem);
   spec.setItemList (itemList);

   setGuiSpec (spec);
   updateSensitivity();
}

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

// private slot
void SctSetSumFuncDlg::rowItem_removeRequest (RowItem*, int rowInx)
{
   static const char* mname ("SctSetSumFuncDlg::rowItem_removeRequest");

   // std::cout << mname << " [" << rowInx << "]" 
   //           << std::endl;

   if (rowInx < 0) return;
   //-------------------->>

   SctSumFuncAssignSpec spec = guiSpec();
   QList<SctSumFuncAssignSpec::Item> itemList = spec.itemList();
   const int itemListCnt = itemList.count();

   if ((itemListCnt > 0) && (rowInx < itemListCnt))
   {
      // Remove the Spec Item at the Line Index
      itemList.removeAt (rowInx);
      spec.setItemList (itemList);
   
      setGuiSpec (spec);
   }

   updateSensitivity();
}

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

// private slot
void SctSetSumFuncDlg::restoreDefaultsButton_clicked()
{
   static const char* mname 
      ("SctSetSumFuncDlg::restoreDefaultsButton_clicked");
   // std::cout << mname << std::endl;

   // Acquire Factory Settings Spec
   SctSumFuncAssignSpec factorySpec;
   factorySpec.setFactoryValue();
      
   setGuiSpec (factorySpec);

   updateSensitivity();
   updateGeometry();
   schedAdjustSize();
}

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

// private slot
void SctSetSumFuncDlg::cancelChangesButton_clicked()
{
   static const char* mname 
      ("SctSetSumFuncDlg::cancelChangesButton_clicked");
   // std::cout << mname << std::endl;

   restoreOrigSpec();

   updateGeometry();
   updateSensitivity();
   schedAdjustSize();
}

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

// private slot
void SctSetSumFuncDlg::applyButton_clicked()
{
   static const char* mname ("SctSetSumFuncDlg::applyButton_clicked");

   const SctSumFuncAssignSpec guiSpecRec = guiSpec(); 
   _origSpec = guiSpecRec;

   if (!rwAssert (_sctDlg != NULL)) return;
   //------------------------------------>>

   SctConfig* sctCfg = _sctDlg->sctConfig();
   SctModelData* mDat = _sctDlg->sctModelDat();

   if (!rwAssert (sctCfg != NULL)) return;
   if (!rwAssert (mDat != NULL)) return;
   //----------------------------------->>

   const int rowCnt = _itemWidgetRows.count();
   const int slotCnt = sctCfg->slotCnt();

   RwQtAutoWaitCursor waitInst (slotCnt > 30); 

   // *************************************************
   // ***  Save the Current Spec in the SCT Config  ***
   // *************************************************

   sctCfg->setSumFuncAssignSpec (guiSpecRec);

   // ************************************************
   // ***  Apply Current Spec to Slots in the SCT  ***
   // ************************************************

   // Note: This deals only with the series (and table series) slots in 
   // the SCT.  Aggregation Summary Functions are not relevant for Scalar, 
   // Table, and List slots on the other SCT tabs.

   int slotSetCnt (0);
   for (int slotInx = 0;  slotInx < slotCnt;  ++slotInx)
   {
      const SlotColRef scRef = mDat->getSlotColRef (slotInx);
      if (!scRef.valid()) continue;
      //---------------------------

      for (int rowInx = 0;  rowInx < rowCnt;  ++rowInx)
      {
         RowItem* rowItem = _itemWidgetRows [rowInx];
         if (rowItem)
         {
            const bool matched = rowItem->matchesSlot (scRef);
            if (matched)
            {
               const SctSumFuncAssignSpec::Item& rowData = 
                  rowItem->rowItemDataRef();

               const SctSumFuncSpec spec = rowData.sumFuncSpec();
               sctCfg->setSumFuncSpec (slotInx, spec);

               ++slotSetCnt;
               break;
               //----------------- 
            }
         }
      }
   }

   // ****************************************
   // ***  Emit sumFuncSpecApplied Signal  ***
   // ****************************************

   // std::cout << mname << " emitting sumFuncSpecApplied" << std::endl;

   emit sumFuncSpecApplied (guiSpecRec);

   updateSensitivity();
   schedAdjustSize();
}

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

// private slot
void SctSetSumFuncDlg::closeButton_clicked()
{
   static const char* mname ("SctSetSumFuncDlg::closeButton_clicked");
   // std::cout << mname << std::endl;

   setAttribute (Qt::WA_DeleteOnClose, true);
   close();
}

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

// ***********************************************************
// ***  class SctSetSumFuncDlg::RowItem  --  a Widget Row  ***
// ***********************************************************

// static
int SctSetSumFuncDlg::RowItem::_instCnt (0);

// constructor
SctSetSumFuncDlg::RowItem::RowItem (SctSetSumFuncDlg* dlg, 
                                    QGridLayout* gridLayout,
                                    int rowInx) // [0..]
  : QObject (dlg),
    _dlg (dlg),
    _gridLayout (gridLayout),
    _instNum (++_instCnt),
    _rowIndex (rowInx),             // [0..]
    _data(),                        // SctSumFuncAssignSpec::Item
    _slotNamePickerSelector (NULL), // GUS Selector
    _enaFiltersButGroup (NULL),     // QButtonGroup :
    _enaUnitTypeRadioBut (NULL),    // QRadioButton : Unit Type
    _unitTypeCombo (NULL),          // QComboBox    : Unit Type
    _enaSlotNameRadioBut (NULL),    // QRadioButton : Slot Name
    _slotNameLineEdit (NULL),       // QLineEdit    : Slot Name
    _gusSelectNameBut (NULL),       // QPushButton  : Slot Name (for GUS)
    _sumFuncCombo (NULL),           // QComboBox    : Summary Function
    _insertHereBut (NULL),          // QPushButton  : (+) Insert Row
    _deleteHereBut (NULL),          // QPushButton  : (-) Delete Row
    _slotCntLabel (NULL),           // QLabel       : Slots (count)
    _settingWidgets_inProgress (false)
{
   static const char* mname ("RowItem ctor");

   // Create a RowItem, including it's contained Widgets for the
   // specified Widget Row, and place in the given QGridLayout.

   // std::cout << mname 
   //           << " [inst " << _instNum << "]"
   //           << " [row "  << _rowIndex << "]" 
   //           << std::endl; 

   _enaFiltersButGroup  = new QButtonGroup (_dlg);   //  1
   _enaUnitTypeRadioBut = new QRadioButton (_dlg);   //  2
   _unitTypeCombo       = new QComboBox (_dlg);      //  3
   _enaSlotNameRadioBut = new QRadioButton (_dlg);   //  4
   _slotNameLineEdit    = new QLineEdit (_dlg);      //  5
   _gusSelectNameBut    = new QPushButton (_dlg);    //  6
   _sumFuncCombo        = new QComboBox (_dlg);      //  7
   _insertHereBut       = new QPushButton (_dlg);    //  8
   _deleteHereBut       = new QPushButton (_dlg);    //  9
   _slotCntLabel        = new QLabel (_dlg);         //  10

   const QString wn1  = QString ("_enaFiltersButGroup %1")  .arg (_instNum);
   const QString wn2  = QString ("_enaUnitTypeRadioBut %1") .arg (_instNum);
   const QString wn3  = QString ("_unitTypeCombo %1")       .arg (_instNum);
   const QString wn4  = QString ("_enaSlotNameRadioBut %1") .arg (_instNum);
   const QString wn5  = QString ("_slotNameLineEdit %1")    .arg (_instNum);
   const QString wn6  = QString ("_gusSelectNameBut %1")    .arg (_instNum);
   const QString wn7  = QString ("_sumFuncCombo %1")        .arg (_instNum);
   const QString wn8  = QString ("_insertHereBut %1")       .arg (_instNum);
   const QString wn9  = QString ("_deleteHereBut %1")       .arg (_instNum);
   const QString wn10 = QString ("_slotCntLabel %1")        .arg (_instNum);

   _enaFiltersButGroup  -> setObjectName (wn1);
   _enaUnitTypeRadioBut -> setObjectName (wn2);
   _unitTypeCombo       -> setObjectName (wn3);
   _enaSlotNameRadioBut -> setObjectName (wn4);
   _slotNameLineEdit    -> setObjectName (wn5);
   _gusSelectNameBut    -> setObjectName (wn6);
   _sumFuncCombo        -> setObjectName (wn7);
   _insertHereBut       -> setObjectName (wn8);
   _deleteHereBut       -> setObjectName (wn9);
   _slotCntLabel        -> setObjectName (wn10);

   QList<QObject*> qobjs;
   qobjs << _enaFiltersButGroup
         << _enaUnitTypeRadioBut
         << _unitTypeCombo
         << _enaSlotNameRadioBut
         << _slotNameLineEdit
         << _gusSelectNameBut
         << _sumFuncCombo
         << _insertHereBut
         << _deleteHereBut
         << _slotCntLabel;

   while (!qobjs.isEmpty())
   {
      QObject* qobj = qobjs.takeFirst();
      connect (qobj, SIGNAL (destroyed (QObject*)), 
               SLOT (childDestroyed (QObject*))); 
   }

   _enaFiltersButGroup -> addButton (_enaUnitTypeRadioBut, 1); // Id
   _enaFiltersButGroup -> addButton (_enaSlotNameRadioBut, 2); // Id
   _enaFiltersButGroup -> setExclusive (true);

   connect (_enaFiltersButGroup, 
            SIGNAL (buttonClicked (QAbstractButton*)),
            SLOT (enaFiltersButGroup_buttonClicked (QAbstractButton*)));

   // GUS slot selector button
   _gusSelectNameBut->setText ("...");
   RwQtUtils::qButtonLimitWidth (_gusSelectNameBut);
   _gusSelectNameBut->setToolTip (
      tr ("Choose Slot Name with the Slot Selector..."));
   _gusSelectNameBut->setDefault (false);
   _gusSelectNameBut->setAutoDefault (false);

   // Radio buttons have too much space on the right when used without
   // a text label.  Limiting the width seems to work.
   _enaUnitTypeRadioBut -> setMaximumWidth (16); 
   _enaSlotNameRadioBut -> setMaximumWidth (16);

   _insertHereBut->setPixmap (RwQPixmap16::greenPlus());
   _deleteHereBut->setPixmap (RwQPixmap16::redMinus());
   _insertHereBut->setText (QString::null);
   _deleteHereBut->setText (QString::null);
   _insertHereBut->setToolTip (tr ("Insert Row"));
   _deleteHereBut->setToolTip (tr ("Remove Row"));

   const QSize plusSize = RwQPixmap16::greenPlus().size();
   const QSize butSize = plusSize + QSize (4,4);
   _insertHereBut->setMaximumSize (butSize);
   _deleteHereBut->setMaximumSize (butSize);
   _gusSelectNameBut->setMaximumHeight (butSize.height());

   _insertHereBut->setDefault (false);
   _deleteHereBut->setDefault (false);
   _insertHereBut->setAutoDefault (false);
   _deleteHereBut->setAutoDefault (false);

   // If this is the maximum allowed row, disable the PLUS button.
   _insertHereBut -> setEnabled (_rowIndex < MAX_ROW_ITEMS);

   _slotCntLabel -> setAlignment (Qt::AlignRight | Qt::AlignVCenter);

   // Place Widgets in Grid Layout. The first row (index 0) is used for
   // column header labels.
   //
   gridLayout->addWidget (_enaUnitTypeRadioBut, rowInx + 1, COL_UNIT_ENA);
   gridLayout->addWidget (_unitTypeCombo,       rowInx + 1, COL_UNIT_COMBO);
   gridLayout->addWidget (_enaSlotNameRadioBut, rowInx + 1, COL_SLOT_ENA);
   gridLayout->addWidget (_slotNameLineEdit,    rowInx + 1, COL_SLOT_EDIT);
   gridLayout->addWidget (_gusSelectNameBut,    rowInx + 1, COL_GUS);
   gridLayout->addWidget (_sumFuncCombo,        rowInx + 1, COL_FUNC_COMBO);
   gridLayout->addWidget (_insertHereBut,       rowInx + 1, COL_BUT_INSERT);
   gridLayout->addWidget (_deleteHereBut,       rowInx + 1, COL_BUT_DELETE);
   gridLayout->addWidget (_slotCntLabel,        rowInx + 1, COL_SLOT_CNT);

   // **************************************
   // ***  Populate Unit Type QComboBox  ***
   // **************************************

   rebuildUnitTypeCombo (true);  // withTheAnyItem

   connect (_unitTypeCombo, SIGNAL (activated (int)),
            SLOT (unitTypeCombo_activated (int)));

   // **************************
   // ***  Set Up QLineEdit  ***
   // **************************

   _slotNameLineEdit->setValidator (_dlg->_slotNameValidator);

   connect (_slotNameLineEdit, SIGNAL (textEdited (const QString&)),
            SLOT (slotNameLineEdit_textEdited (const QString&)));

   // *****************************
   // ***  Set Up "GUS" Button  ***
   // *****************************

   connect (_gusSelectNameBut, SIGNAL (clicked ()),
            SLOT (gusSelectNameBut_clicked ()));

   // *****************************
   // *********************************************
   // ***  Populate Summary Function QComboBox  ***
   // *********************************************

   SctSumFuncSpec::initSumFuncCombo (_sumFuncCombo, 0);

   connect (_sumFuncCombo, SIGNAL (activated (int)),
            SLOT (sumFuncCombo_activated (int)));

   // ****************************************
   // ***  Set Up Insert / Delete Buttons  ***
   // ****************************************

   connect (_insertHereBut, SIGNAL (clicked()),
            SLOT (insertHereBut_clicked()));

   connect (_deleteHereBut, SIGNAL (clicked()),
            SLOT (deleteHereBut_clicked()));
}

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

SctSetSumFuncDlg::RowItem::~RowItem()
{
   // Note: The widgets managed "within" this row item are actually
   // parented by the containing dialog (so that a single QGridLayout
   // can be used to lay out all of the QWidgets in a sequence of 
   // RowItems.  So, we explicitly delete the row's QWidgets here.
   //
   deleteWidgets();
}

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

void SctSetSumFuncDlg::RowItem::deleteWidgets()
{
   static const char* mname ("RowItem::deleteWidgets");

   // Delete the Widgets in one Widget Row.  Note that the Widgets don't
   // have to be explicitly removed from the QGridLayout.  We just have 
   // to delete them.

   // std::cout << mname 
   //           << " [inst " << _instNum << "]"
   //           << " [row "  << _rowIndex << "]" 
   //           << std::endl; 

   // ************************************
   // ***  Remove and Delete QWidgets  ***
   // ************************************

   QList<QWidget*> wids;

   wids << _enaUnitTypeRadioBut; _enaUnitTypeRadioBut = NULL;
   wids << _unitTypeCombo;       _unitTypeCombo       = NULL;
   wids << _enaSlotNameRadioBut; _enaSlotNameRadioBut = NULL;
   wids << _slotNameLineEdit;    _slotNameLineEdit    = NULL;
   wids << _gusSelectNameBut;    _gusSelectNameBut    = NULL;
   wids << _sumFuncCombo;        _sumFuncCombo        = NULL;
   wids << _insertHereBut;       _insertHereBut       = NULL;
   wids << _deleteHereBut;       _deleteHereBut       = NULL;
   wids << _slotCntLabel;        _slotCntLabel        = NULL;

   while (!wids.isEmpty())
   {
      QWidget* wid = wids.takeFirst();
      if (wid)
      {
         if (_gridLayout)
         {
            _gridLayout->removeWidget (wid);
         }
             
         delete wid;
      }
   }

   // *****************************
   // ***  Delete QButtonGroup  ***
   // *****************************

   if (_enaFiltersButGroup)
   {
      delete _enaFiltersButGroup;
      _enaFiltersButGroup = NULL;
   }
}

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

void SctSetSumFuncDlg::RowItem::rebuildUnitTypeCombo (bool withTheAnyItem)
{
   static const char* mname 
      ("SctSetSumFuncDlg::RowItem::rebuildUnitTypeCombo");

   // std::cout << mname << " "
   //           << (withTheAnyItem ? "With 'Any'" : "Without 'Any'")
   //           << std::endl;

   const int firstUnitTypeInt = withTheAnyItem ? (int) NOUNITS
                                               : (int) (NOUNITS+1);
   QComboBox* cb = _unitTypeCombo;
   cb->clear();

   for (int utypInt = firstUnitTypeInt;
        utypInt < (int) NUMUNITS;
        ++utypInt)
   {
      const QString utypStr = unitTypeStr ((unit_type) utypInt);
      cb->addItem (utypStr, QVariant (utypInt));
   }
}

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

void SctSetSumFuncDlg::RowItem::updateUnitTypeCombo()
{
   const bool utypEna    = _data.unitTypeFilterEnabled();
   const unit_type utyp  = _data.activeUnitType();
   const QString utypStr = unitTypeStr (utyp);

   static const QString TheAnyTypeStr = unitTypeStr (NOUNITS);
   const bool needTheAnyItem = (utypStr == TheAnyTypeStr);
   const bool hasTheAnyItem = (_unitTypeCombo->findText (TheAnyTypeStr) >= 0);

   if (needTheAnyItem != hasTheAnyItem)
   { 
      rebuildUnitTypeCombo (needTheAnyItem);
   }

   RwQtUtils::qComboSetCurrentItem (_unitTypeCombo, utypStr);
   _unitTypeCombo -> setEnabled (utypEna);
}

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

void SctSetSumFuncDlg::RowItem::updateSlotNameEdit()
{
   const bool sNamEna = _data.slotNameFilterEnabled();
   const QString sNamStr = _data.activeSlotNamePart();

   const int nameTextWidth = 
      RwQtUtils::stringPixelWidth (_slotNameLineEdit, sNamStr)
      + LINE_EDIT_EXTRA_WIDTH;

   _slotNameLineEdit -> setMinimumWidth (nameTextWidth);
   _slotNameLineEdit -> setText (sNamStr);
   _slotNameLineEdit -> setEnabled (sNamEna);
}

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

bool SctSetSumFuncDlg::RowItem::containsQObject (const QObject* qobj) const
{
   // Does this RowItem instance contain the given Widget (qobj)?

   if (qobj == NULL) return (false);

   if (qobj == _enaFiltersButGroup)  return (true);
   if (qobj == _enaUnitTypeRadioBut) return (true);
   if (qobj == _unitTypeCombo)       return (true);
   if (qobj == _enaSlotNameRadioBut) return (true);
   if (qobj == _slotNameLineEdit)    return (true);
   if (qobj == _gusSelectNameBut)    return (true);
   if (qobj == _sumFuncCombo)        return (true);
   if (qobj == _insertHereBut)       return (true);
   if (qobj == _deleteHereBut)       return (true);
   if (qobj == _slotCntLabel)        return (true);

   return (false);
}

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

void SctSetSumFuncDlg::RowItem::setRowItemData (
                               const SctSumFuncAssignSpec::Item& itemData)
{
   static const char* mname ("SctSetSumFuncDlg::RowItem::setRowItemData");

   _data = itemData;
   
   if (_enaFiltersButGroup == NULL)
   {
      // std::cout << mname << " ABORTING: Widgets Deleted" << std::endl;
      return;  //------>>
   }

   //-----------------------------------------------------
   const bool inProgressSave = _settingWidgets_inProgress;
   _settingWidgets_inProgress = true;
   //-----------------------------------------------------

   const bool isLast = _data.isLastItem();

   // std::cout << mname 
   //           << " isLast? " << (isLast ? "YES" : "no")
   //           << std::endl;
   
   // **********************************
   // ***  Set Filter Radio Buttons  ***
   // **********************************

   const bool utypEna = _data.unitTypeFilterEnabled();
   const bool sNamEna = _data.slotNameFilterEnabled();
   
   _enaUnitTypeRadioBut -> setChecked (utypEna);
   _enaSlotNameRadioBut -> setChecked (sNamEna);
   
   // *********************************
   // ***  Set Unit Type QComboBox  ***
   // *********************************

   updateUnitTypeCombo();

   // ****************************************
   // ***  Set Slot Name (Part) QLineEdit  ***
   // ****************************************

   updateSlotNameEdit();

   // ****************************************
   // ***  Set Summary Function QComboBox  ***
   // ****************************************

   const SctSumFuncSpec funcSpec = _data.sumFuncSpec();
   const QString funcStr = funcSpec.getFuncString();
   RwQtUtils::qComboSetCurrentItem (_sumFuncCombo, funcStr);

   // **********************************************************
   // ***  Special Support for the Last (Default Value) Row  ***
   // **********************************************************

   // The last row doesn't show the Unit Type and Slot Name filters.
   // And it cannot be removed.  So, those controls are hidden in the 
   // last row.
   
   _enaUnitTypeRadioBut -> setVisible (!isLast);
   _unitTypeCombo       -> setVisible (!isLast);
   _enaSlotNameRadioBut -> setVisible (!isLast);
   _slotNameLineEdit    -> setVisible (!isLast);
   _gusSelectNameBut    -> setVisible (!isLast);
   _deleteHereBut       -> setVisible (!isLast);

   //-------------------------------------------------
   _settingWidgets_inProgress = inProgressSave;
   //-------------------------------------------------
}

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

void SctSetSumFuncDlg::RowItem::updateSensitivity()
{
   const bool utypOn = _enaUnitTypeRadioBut -> isChecked();
   const bool sNamOn = _enaSlotNameRadioBut -> isChecked();

   _unitTypeCombo    -> setEnabled (utypOn);
   _slotNameLineEdit -> setEnabled (sNamOn);
}

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

void SctSetSumFuncDlg::RowItem::enableInsertButton (bool ena)
{
   // If this is the maximum allowed row, unconditionally disable the 
   // ROW PLUS button.  Otherwise, enable or disable the ROW PLUS button 
   // based on the given "ena" parameter.

   const bool enableThisButton = ena && (_rowIndex < MAX_ROW_ITEMS);

   _insertHereBut -> setEnabled (enableThisButton);
}

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

void SctSetSumFuncDlg::RowItem::enableDeleteButton (bool ena)
{
   // Enable or disable the ROW MINUS button.
   _deleteHereBut -> setEnabled (ena);
}

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

// **************************************************
// ***  Slot Filtering                            ***
// ***  (Deferred to SctSumFuncAssignSpec::Item)  ***
// **************************************************

bool SctSetSumFuncDlg::RowItem::matchesSlot (const SlotColRef& scRef) const
{
   return (_data.matchesSlot (scRef));
}

bool SctSetSumFuncDlg::RowItem::countSlotMatch (const SlotColRef& scRef)
{
   // if match, increments slotCount
   return (_data.countSlotMatch (scRef));
}

void SctSetSumFuncDlg::RowItem::updateSlotCountLabel()
{
   const int cnt = _data.slotCount(); 
   const QString cntStr = QString::number (cnt);
   _slotCntLabel->setText (cntStr);
}

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

// static
QString SctSetSumFuncDlg::RowItem::unitTypeStr (unit_type utyp)
{
   if (utyp == NOUNITS)
   {
      return (tr ("Any"));
   }

   const QString utypStr = unitMgr->getUnitType (utyp);
   return (utypStr);
}

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

void SctSetSumFuncDlg::RowItem::showGusSlotSelector()
{
   static const char* mname ("SctSetSumFuncDlg::RowItem::showGusSlotSelector");

   if (_slotNamePickerRootSel == NULL)
   {
      RootSelection* sel = new RootSelection();
      sel->setName (tr ("Slot for Slot Name Filter"));
      sel->setRootSubclassType (Root::SUBCLASS_SLOT);
      sel->setAllowSlots_physical (true);
      sel->setAllowSlots_accounting (true);
      sel->addAllAvailableFilters();

      // We're interested only in series-like slots
      sel->constrainSlots_IncludeOnlySeriesLikeSlots();

      _slotNamePickerRootSel = sel;
   }

   if (!_slotNamePickerSelector)
   {
      GusOptions gusOpts;
      gusOpts._singleTerminalSelection  = true;
      gusOpts._showApplyButton          = true;

      _slotNamePickerSelector = 
         new GusSelector (_slotNamePickerRootSel, gusOpts);

      _slotNamePickerSelector->setListener (this);
      _slotNamePickerSelector->setEmptySelectionOk (false);
   }

   _slotNamePickerSelector->show();
}

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

void SctSetSumFuncDlg::RowItem::closeGusSlotSelector()
{
   if (_slotNamePickerSelector != NULL)
   {
      _slotNamePickerSelector->close();
      _slotNamePickerSelector = NULL;
   }
}

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

void SctSetSumFuncDlg::RowItem::gusProcessSelectedSlot (GusSelector*)
{
   static const char* mname (
      "SctSetSumFuncDlg::RowItem::gusProcessSelectedSlot");
   // std::cout << mname << std::endl;

   Slot* gusSlotPtr = 
      _slotNamePickerRootSel ? _slotNamePickerRootSel->firstSlot() : NULL;
   
   if (gusSlotPtr)
   {
      const QString gusSlotName = gusSlotPtr->getName().trimmed();

      const bool changed = (gusSlotName != _data.slotNamePart());
      if (changed)
      {
         //-------------------------------------------------
         const bool inProgressSave = _settingWidgets_inProgress;
         _settingWidgets_inProgress = true;
         //-------------------------------------------------

         _data.setSlotNamePart (gusSlotName);
         updateSlotNameEdit();

         _slotNameLineEdit->setFocus (Qt::OtherFocusReason);

         //-------------------------------------------------
         _settingWidgets_inProgress = inProgressSave;
         //-------------------------------------------------

         if (!_settingWidgets_inProgress)
         {
            emit valueChanged (this, _rowIndex);
         }
      }
   }
}

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

// virtual from GusListener
void SctSetSumFuncDlg::RowItem::gusOk (GusSelector* gus, GusClientData*)
{
   // Note: The selector will automatically close and be deleted after
   // returning to the caller of this method. Drop our Gus pointer.
   if (_slotNamePickerSelector && rwAssert (gus == _slotNamePickerSelector))
      _slotNamePickerSelector = NULL;

   // Use the name of the picked slot
   gusProcessSelectedSlot (gus);
}

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

// virtual
void SctSetSumFuncDlg::RowItem::gusApply (GusSelector* gus, GusClientData*)
{
   // Use the name of the picked slot
   gusProcessSelectedSlot (gus);
}

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

// virtual from GusListener
void SctSetSumFuncDlg::RowItem::gusCancel (GusSelector* gus, GusClientData*)
{
   // Note: The selector will automatically close and be deleted after
   // returning to the caller of this method. Drop our Gus pointer.
   if (_slotNamePickerSelector && rwAssert (gus == _slotNamePickerSelector))
      _slotNamePickerSelector = NULL;
}

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

// private slot
void SctSetSumFuncDlg::RowItem::childDestroyed (QObject* qobj)
{
   if      (qobj == _enaFiltersButGroup)   _enaFiltersButGroup  = NULL;
   else if (qobj == _enaUnitTypeRadioBut)  _enaUnitTypeRadioBut = NULL;
   else if (qobj == _unitTypeCombo)        _unitTypeCombo       = NULL;
   else if (qobj == _enaSlotNameRadioBut)  _enaSlotNameRadioBut = NULL;
   else if (qobj == _slotNameLineEdit)     _slotNameLineEdit    = NULL;
   else if (qobj == _gusSelectNameBut)     _gusSelectNameBut    = NULL;
   else if (qobj == _sumFuncCombo)         _sumFuncCombo        = NULL;
   else if (qobj == _insertHereBut)        _insertHereBut       = NULL;
   else if (qobj == _deleteHereBut)        _deleteHereBut       = NULL;
   else if (qobj == _slotCntLabel)         _slotCntLabel        = NULL;
}

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

// private slot
void SctSetSumFuncDlg::RowItem::enaFiltersButGroup_buttonClicked 
                                                       (QAbstractButton*)
{
   const bool utypOn = _enaUnitTypeRadioBut -> isChecked();
   const bool sNamOn = _enaSlotNameRadioBut -> isChecked();
   const bool utypWasOn = _unitTypeCombo    -> isEnabled();
   const bool sNamWasOn = _slotNameLineEdit -> isEnabled();

   int changeCnt (0);

   //-------------------------------------------------
   const bool inProgressSave = _settingWidgets_inProgress;
   _settingWidgets_inProgress = true;
   //-------------------------------------------------

   _data.setUnitTypeFilterEnabled (utypOn);
   _data.setSlotNameFilterEnabled (sNamOn);

   if (utypOn != utypWasOn)
   {
      updateUnitTypeCombo();
      ++changeCnt;
   }

   if (sNamOn != sNamWasOn)
   {
      updateSlotNameEdit();

      if (sNamOn)
      {
         _slotNameLineEdit->setFocus (Qt::OtherFocusReason);
      }

      ++changeCnt;
   }

   //-------------------------------------------------
   _settingWidgets_inProgress = inProgressSave;
   //-------------------------------------------------

   // If this QRadioBox change notification wasn't triggered from a
   // QRadioBox setting operation, then emit a valueChanged signal.
   // 
   if (!inProgressSave)
   {
      emit valueChanged (this, _rowIndex);
   }
}

// private slot
void SctSetSumFuncDlg::RowItem::unitTypeCombo_activated (int index)
{
   if (_data.unitTypeFilterEnabled())
   {
      const QString utypStr = _unitTypeCombo->currentText().trimmed();
      const unit_type utyp = unitMgr->getUnitType (utypStr);
   
      const bool changed = (utyp != _data.unitType());
      if (changed)
      {
         _data.setUnitType (utyp);

         if (!_settingWidgets_inProgress)
         {
            emit valueChanged (this, _rowIndex);
         }
      }
   }
}

// private slot
void SctSetSumFuncDlg::RowItem::slotNameLineEdit_textEdited (const QString&)
{
   if (_data.slotNameFilterEnabled())
   {
      const QString slotNamePartStr = _slotNameLineEdit->text().trimmed();

      const bool changed = (slotNamePartStr != _data.slotNamePart());
      if (changed)
      {
         _data.setSlotNamePart (slotNamePartStr);

         if (!_settingWidgets_inProgress)
         {
            emit valueChanged (this, _rowIndex);
         }
      }
   }
}

// private slot
void SctSetSumFuncDlg::RowItem::gusSelectNameBut_clicked()
{
   const bool sNamOn = _enaSlotNameRadioBut->isChecked();
   if (!sNamOn)
   {
      // Turn on the Slot Name Filter
      _enaSlotNameRadioBut->setChecked (true);
      _data.setSlotNameFilterEnabled (true);
      updateSensitivity(); // force correct state of other toggle

      // Resolve other state information by round-tripping state
      const SctSumFuncAssignSpec::Item& rowData = rowItemDataRef();
      setRowItemData (rowData);

      _slotNameLineEdit->setFocus (Qt::OtherFocusReason);

      emit valueChanged (this, _rowIndex);
   }
   
   showGusSlotSelector();
}

// private slot
void SctSetSumFuncDlg::RowItem::sumFuncCombo_activated (int index)
{
   const QString funcStr = _sumFuncCombo->currentText().trimmed();
   const SctSumFuncSpec sumFuncSpec (funcStr);
   
   const bool changed = (sumFuncSpec != _data.sumFuncSpec());
   if (changed)
   {
      _data.setSumFuncSpec (sumFuncSpec);

      if (!_settingWidgets_inProgress)
      {
         emit valueChanged (this, _rowIndex);
      }
   }
}

// private slot
void SctSetSumFuncDlg::RowItem::insertHereBut_clicked()
{
   static const char* mname 
      ("SctSetSumFuncDlg::RowItem::insertHereBut_clicked");
   // std::cout << mname << " [row " << _rowIndex << "]" << std::endl;

   emit insertAboveRequest (this, _rowIndex);  // [0..]
}

// private slot
void SctSetSumFuncDlg::RowItem::deleteHereBut_clicked()
{
   static const char* mname 
      ("SctSetSumFuncDlg::RowItem::deleteHereBut_clicked");
   // std::cout << mname << " [row " << _rowIndex << "]" << std::endl;

   emit removeRequest (this, _rowIndex);  // [0..]
}

//--- (end SctSetSumFuncDlg.cpp) ---