//----------------------------------------------------------------------------- // $Id: QtSCT/EditSctSlotListTreeView.cpp 2014/11/07 19:53:29 philw $ //----------------------------------------------------------------------------- // // CLASSES: // class EditSctSlotListTreeView : public QTreeWidget // class EditSctSlotListTreeView::SlotItem : public QTreeWidgetItem // //-- static const bool SINGLE_CLICK_EDIT (false); // for Value Column static const bool SHOW_SERIAL_NUM_COL (false); // diagnostics static const bool SHOW_INDEX_DEBUG_COL (false); // diagnostics #include static const bool YELLOW_BG_FOR_EDITABLE_CELLS (false); static const QColor YELLOW_COLOR (0xEE, 0xDD, 0x82); // Light Goldenrod // Column Index Symbols static const int COL_ItemLabel (0); // Slot or Divider Item Label static const int COL_SlotName (1); // Actual Slot or Slot Column Name static const int COL_UnitType (2); // Unit Type static const int COL_StepSize (3); // Series Timestep Size static const int COL_COUNT (4); // --- NUMBER OF COLUMNS --- // These diagnostic columns ARE implemented, but are not currently included // in the COL_COUNT. If you want to use them, adjust the COL_COUNT to span // these indices (i.e. change to one greater than the last index). // static const int COL_SerNum (4); // Serial Number static const int COL_InxDebug (5); // Index Debug //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #include "EditSctSlotListTreeView.hpp" // this module #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for std::max #include "Account.hpp" #include "QGui.hpp" #include "RunIcons.hpp" #include "RwQPixmap16.hpp" #include "RwQtIcons.hpp" #include "RwQtUtils.hpp" #include "RwQt4Utils.hpp" #include "SctManager.hpp" #include "SimObj.hpp" #include "SimWS.hpp" #include "System.hpp" //--- for rwWorkspace #include "UnitMgr.hpp" #include "cwEnv.hpp" //--- for cwSubstEnv #include "cwFile.hpp" //--- for posixPath #include "libEngrObjsClassIds.hpp" #include "rwError.hpp" //--- for rwAssert #include "rwStr.hpp" // #include "modeltest.hpp" //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ***************************************************** // *** class EditSctSlotListTreeView : QTreeWidget *** // ***************************************************** // constructor 1 of 1 EditSctSlotListTreeView::EditSctSlotListTreeView ( EditSctSlotListPanel* parentPanel) : QTreeWidget (parentPanel), _parentPanel (parentPanel), // EditSctSlotListPanel* _slotDataList(), // QList _slotItemList(), // QList _topLevelRows(), // QList _rebuildTree_inProgress (false), _setSelection_inProgress (false), _setExpanded_inProgress (false) { static const char* mname ("EditSctSlotListTreeView ctor"); // std::cout << mname << std::endl; QStringList colLabs; colLabs << tr ("Slot or Divider Label"); rwAssert (0 == COL_ItemLabel); colLabs << tr ("Slot Name"); rwAssert (1 == COL_SlotName); colLabs << tr ("Unit Type"); rwAssert (2 == COL_UnitType); colLabs << tr ("Step Size"); rwAssert (3 == COL_StepSize); setColumnCount (COL_COUNT); setHeaderLabels (colLabs); QHeaderView* hdrView = header(); hdrView->setSectionHidden (COL_SerNum, !SHOW_SERIAL_NUM_COL); hdrView->setSectionHidden (COL_InxDebug, !SHOW_INDEX_DEBUG_COL); hdrView->setSortIndicatorShown (false); hdrView->setMovable (false); hdrView->setStretchLastSection (false); hdrView->setResizeMode (QHeaderView::Interactive); setSelectionMode (QAbstractItemView::ExtendedSelection); setSortingEnabled (false); setAllColumnsShowFocus (true); setMouseTracking (true); // For Status Tips setRootIsDecorated (true); setItemsExpandable (true); if (SINGLE_CLICK_EDIT) { // Note: editing is explicitly started from the slotItemClicked slot. setEditTriggers (QAbstractItemView::NoEditTriggers); } else { setEditTriggers ( QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed ); } const QSize maxSize = maxIconSize(); setIconSize (maxSize); // Default: Initially hide Slot Name Column showSlotNameColumn (false); initConnections(); // // Assert QAbstractItemModel problems only on Windows // #ifdef Q_WS_WIN32 // { // new ModelTest (model(), this); // } // #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // destructor EditSctSlotListTreeView::~EditSctSlotListTreeView() { static const char* mname ("EditSctSlotListTreeView dtor"); // std::cout << mname << std::endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- SctConfig* EditSctSlotListTreeView::sctConfig() const { SctConfig* cfg = _parentPanel ? _parentPanel->sctConfig() : NULL; return cfg; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::loadSctConfigSlotDataList ( const QList& slotDataList) { static const char* mname ( "EditSctSlotListTreeView::loadSctConfigSlotDataList"); _slotDataList = slotDataList; rebuildTree(); resizeAllColumns(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::rebuildTree() { static const char* mname ("EditSctSlotListTreeView::rebuildTree"); //--------------------------------------------------- // INPUT: QList _slotDataList; // COMPUTED: QList _slotItemList; // COMPUTED: QList _topLevelRows; // COMPUTED: This QTreeWidget's QTreeWidgetItems //--------------------------------------------------- //------------------------------- blockSignals (true); setUpdatesEnabled (false); _rebuildTree_inProgress = true; //------------------------------- const int rowCnt = _slotDataList.count(); const QSet selRowSerNums = selectedRowSerialNums(); clear(); // [QTreeWidget] _slotItemList.clear(); _topLevelRows.clear(); _slotItemList.reserve (std::max (1, rowCnt)); ensureFirstItemIsDivider (false); // Don't doRebuildTree; we're doing it. SlotItem* priorTabItem (NULL); // tab divider SlotItem* priorDivItem (NULL); // tab or slot divider int priorTabRow (-1); // tab divider int priorDivRow (-1); // tab or slot divider for (int row = 0; row < rowCnt; ++row) { SctConfigSlotData& rowData = _slotDataList [row]; SlotItem* newItem = new SlotItem (this, rowData); _slotItemList.append (newItem); if (rowData.isTabDivider()) { // Tab Dividers are ALWAYS top-level items. const int topInx = _topLevelRows.count(); _topLevelRows.append (row); // Set SlotItem rowItem: (itemRow, parentRow, sibInx). newItem->setItemTreeData (row, (-1), topInx); addTopLevelItem (newItem); // [QTreeWidget] priorTabItem = newItem; // tab divider priorDivItem = newItem; // tab or slot divider priorTabRow = row; // tab divider priorDivRow = row; // tab or slot divider } else if (rowData.isSlotDivider()) { // Slot Dividers are top-level items ONLY if there is not any // preceding Tab Divider item. const bool isTopLevel = (priorTabItem == NULL); if (isTopLevel) { const int topInx = _topLevelRows.count(); _topLevelRows.append (row); // Set SlotItem rowItem: (itemRow, parentRow, sibInx). newItem->setItemTreeData (row, (-1), topInx); addTopLevelItem (newItem); // [QTreeWidget] } else // (NOT topLevel) { const int sibInx = priorTabItem->childCount(); // Set SlotItem rowItem: (itemRow, parentRow, sibInx). newItem->setItemTreeData (row, priorTabRow, sibInx); priorTabItem->addChild (newItem); // [QTreeWidgetItem] } priorDivItem = newItem; // tab or slot divider priorDivRow = row; // tab or slot divider } else // (Slot Item) { // Since we have ensured that there is SOME type of divider above // regular slot items, we do expect that the 'priorDiv' is defined. if (rwAssert (priorDivItem != NULL)) { const int sibInx = priorDivItem->childCount(); // Set SlotItem rowItem: (itemRow, parentRow, sibInx). newItem->setItemTreeData (row, priorDivRow, sibInx); priorDivItem->addChild (newItem); // [QTreeWidgetItem] } } } // for (int row) // Diagnostics Dump //-- for (int row = 0; row < rowCnt; ++row) //-- { //-- SlotItem* rowItem = _slotItemList [row]; //-- std::cout << mname << " [row " << row << "] " //-- << qPrintable (rowItem->indexDebugStr()) //-- << std::endl; //-- } applyItemExpandedStates(); selectRowsBySerialNum (selRowSerNums); const int colCnt = columnCount(); for (int col = 0; col < colCnt; ++col) { if (!isColumnHidden (col)) resizeColumnToContents (col); } //------------------------------- _rebuildTree_inProgress = false; setUpdatesEnabled (true); blockSignals (false); //------------------------------- scrollToSelection(); if (_parentPanel) { _parentPanel->notifySlotSelectionChanged(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QList EditSctSlotListTreeView::sctConfigSlotDataList() const { const int slotItemCnt = _slotItemList.count(); if (slotItemCnt < 1) return QList(); // empty QList slotDataList; slotDataList.reserve (slotItemCnt); const int itemCnt = _slotItemList.count(); for (int inx = 0; inx < slotItemCnt; ++inx) { slotDataList .append (_slotItemList [inx]->slotDataRef()); } // Refresh series slot tab index fields (void) SctConfig::serTabCnt (slotDataList, true); // alsoRefresh return slotDataList; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QSet EditSctSlotListTreeView::sctConfigSlotDataListSerNums() const { const int slotItemCnt = _slotItemList.count(); if (slotItemCnt < 1) return QSet(); // empty QSet serNums; serNums.reserve (slotItemCnt + 10); for (int inx = 0; inx < slotItemCnt; ++inx) { const int serNum = _slotItemList [inx] -> slotDataRef().serNum(); serNums .insert (serNum); } return serNums; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::showSlotNameColumn (bool showCol) { if (showCol) { showColumn (COL_SlotName); resizeColumnToContents (COL_SlotName); } else { hideColumn (COL_SlotName); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::saveTreeWidgetItemSelections() { static const char* mname ( "EditSctSlotListTreeView::saveTreeWidgetItemSelections"); // std::cout << mname << std::endl; const int itemCnt = _slotItemList.count(); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = _slotItemList [inx]; if (slotItem) { const bool sel = slotItem->isSelected(); slotItem->setSelected (sel); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::selectRowsBySerialNum (const QSet& serNums) { static const char* mname ("EditSctSlotListTreeView::selectRowsBySerialNum"); //--------------------------------------------------- const bool saveSelInProg = _setSelection_inProgress; _setSelection_inProgress = true; //--------------------------------------------------- const int itemCnt = _slotItemList.count(); int minSelRow (-1); int maxSelRow (-1); int selRowCnt (0); clearSelection(); // [QTreeWidget] QItemSelectionModel* selModel = selectionModel(); selModel->clear(); QSet::const_iterator iter; for (iter = serNums.constBegin(); iter != serNums.constEnd(); ++iter) { const int serNum = (*iter); const int selRow = findSerialNumRow (serNum); if ((selRow >= 0) && (selRow < itemCnt)) { SlotItem* slotItem = _slotItemList [selRow]; if (slotItem) { slotItem->setSelected (true); } } } //--------------------------------------------------- _setSelection_inProgress = saveSelInProg; //--------------------------------------------------- if (_parentPanel) { _parentPanel->notifySlotSelectionChanged(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QSet EditSctSlotListTreeView::selectedRowSerialNums() const { const QList selItems = selectedItems(); const int selItemCnt = selItems.count(); QSet selSerNums; selSerNums.reserve (selItemCnt + 10); for (int inx = 0; inx < selItemCnt; ++inx) { const QTreeWidgetItem* item = selItems [inx]; const SlotItem* slotItem = dynamic_cast (item); if (slotItem) { selSerNums.insert (slotItem->serNum()); } } return (selSerNums); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QList EditSctSlotListTreeView::locateSelectedSlots() const { const QList selItems = selectedItems(); const int selItemCnt = selItems.count(); if (selItemCnt < 1) return QList(); // empty QList retSlotList; retSlotList.reserve (selItemCnt); for (int inx = 0; inx < selItemCnt; ++inx) { const QTreeWidgetItem* item = selItems [inx]; const SlotItem* slotItem = dynamic_cast (item); if (slotItem) { const SctConfigSlotData& slotDat = slotItem->slotDataRef(); Slot* slotPtr = rwWorkspace->locateSlot (slotDat._rwSlotName); if (slotPtr) { retSlotList.append (slotPtr); } } } return (retSlotList); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static void EditSctSlotListTreeView::selectOnlySerNum (QList& itemList, int serialNum) { const int itemCnt = itemList.count(); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = itemList [inx]; if (slotItem) slotItem->setSelected (slotItem->serNum() == serialNum); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QSet EditSctSlotListTreeView::openRowSerialNums() const { const int itemCnt = _slotItemList.count(); if (itemCnt < 1) return QSet(); // empty QSet openSerNums; openSerNums.reserve (itemCnt); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = _slotItemList [inx]; if (slotItem && slotItem->isExpanded()) openSerNums.insert (slotItem->serNum()); } return openSerNums; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::scrollToSerialNum (int serNum, QAbstractItemView::ScrollHint scrollHint) { const int row = findSerialNumRow (serNum); const int itemCnt = _slotItemList.count(); if ((row >= 0) && (row < itemCnt)) { SlotItem* slotItem = _slotItemList [row]; if (slotItem) scrollToItem (slotItem, scrollHint); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Returns statistics related to slot and divider items vis-a-vis // item selection and tree expanded (open) states // // int& itemCntRet : Num of Items // int& selItemCnt : Num of Selected Items // int& implSelItemCnt : ... incl. all Slots under Closed Selected Divs // int& slotCnt : Num of Slot items // int& selSlotCnt : Num of (actually) Selected Slots // int& implSelSlotCnt : ... incl. all Slots under Closed Selected Divs // int& divCnt : Num of Dividers // int& selDivCnt : Num of Selected Dividers // int& orphSelSlotCnt : Num of Selected Slots NOT under Selected Divs // int& openDivCnt : Num of Open Dividers // int& selOpenDivCnt : Num of Selected Open Dividers // QSet& selGroupRows : Row indices of selected Dividers // void EditSctSlotListTreeView::computeRowStats ( int& itemCntRet, int& selItemCnt, int& implSelItemCnt, int& slotCnt, int& selSlotCnt, int& implSelSlotCnt, int& divCnt, int& selDivCnt, int& orphSelSlotCnt, int& openDivCnt, int& selOpenDivCnt, QSet& selGroupRows) const { // Note: The "impl" (implied) selection counts include all slots // within _closed_ selected groups. const int itemCnt = _slotItemList.count(); itemCntRet = itemCnt; selItemCnt = 0; implSelItemCnt = 0; slotCnt = 0; selSlotCnt = 0; implSelSlotCnt = 0; divCnt = 0; selDivCnt = 0; orphSelSlotCnt = 0; openDivCnt = 0; selOpenDivCnt = 0; selGroupRows.clear(); bool lastDivSelected = false; bool lastDivSelectedAndClosed = false; for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; const bool isSel = slotItem && slotItem->isSelected(); const bool isDiv = slotItem && slotItem->isDivider(); const bool isExp = slotItem && slotItem->isExpanded(); if (isDiv) { lastDivSelected = isSel; lastDivSelectedAndClosed = isSel && !isExp; } if (isSel) { ++selItemCnt; ++implSelItemCnt; if (isDiv) { ++selDivCnt; if (isExp) ++selOpenDivCnt; } else // slot { ++selSlotCnt; ++implSelSlotCnt; if (!lastDivSelected) ++orphSelSlotCnt; } selGroupRows.insert (inx); } else if (lastDivSelectedAndClosed) { ++implSelItemCnt; if (!isDiv) ++implSelSlotCnt; } if (isDiv) { ++divCnt; if (isExp) ++openDivCnt; } else // slot { ++slotCnt; } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QList EditSctSlotListTreeView::slotItemGroupRowsAtRow ( int refRow, bool flatGroups /*=false*/) const { // Note: Ordinarily, if the provided 'refRow' is the row index of a // Tab Divider, then the group consists of all items (including Slot // Dividers) up to the next Tab Divider, to the end of the slot item // list. BUT IF 'flatGroups' is passed in as 'true', groups of BOTH // types terminate at the next divider, of either type. const int cnt = _slotItemList.count(); if ((refRow < 0) || (refRow >= cnt)) return QList(); // empty //---------------->> const bool isTabDiv = isTabDividerRow (refRow); const bool isSlotDiv = isSlotDividerRow (refRow); if (!isTabDiv && !isSlotDiv) return QList(); // empty //---------------->> QList groupRows; const bool fullTabGroup = isTabDiv && !flatGroups; if (fullTabGroup) { groupRows.append (refRow); // Accumulate SlotItems up until the next Tab divider. for (int row = refRow + 1; row < cnt; ++row) { if (isTabDividerRow (row)) break; //------ groupRows.append (row); } } else // (NOT fullTabGroup) { groupRows.append (refRow); // Accumulate SlotItems up until the next Tab OR Slot divider. for (int row = refRow + 1; row < cnt; ++row) { if (isTabDividerRow (row) || isSlotDividerRow (row)) break; //------ groupRows.append (row); } } return groupRows; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::singleSelGroupRow() const { // Return the Slot Group Index of the single Slot Group containing // an item selection. int itemCntRet (0); int selItemCnt (0); int implSelItemCnt (0); int slotCnt (0); int selSlotCnt (0); int implSelSlotCnt (0); int divCnt (0); int selDivCnt (0); int orphSelSlotCnt (0); int openDivCnt (0); int selOpenDivCnt (0); QSet selGroupRows; // Note: The "impl" (implied) selection counts include all slots // within _closed_ selected groups. (But those aren't used in // _this_ method). computeRowStats (itemCntRet, selItemCnt, implSelItemCnt, slotCnt, selSlotCnt, implSelSlotCnt, divCnt, selDivCnt, orphSelSlotCnt, openDivCnt, selOpenDivCnt, selGroupRows); const int selGroupCnt = selGroupRows.count(); if (selGroupCnt != 1) { // The current selection doesn't identify a single group. return (-1); //-------->> } const int selGroupRow = selGroupRows.toList() [0]; return (selGroupRow); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::rowChildrenBaseObjTypeId (int refRow, QString& objNameRet) const { // If the SlotGroup indicated by the given row index has only // Slots on one particular SimObj or Account instance, then return // the "base" SimObj Type ID or Account Type ID of that instance. // // Returned Values: // (-1) the SlotGroup can't be retrieved with the given index. // (0) the SlotGroup doesn't have Slots on a single object // (>0) SimObj or Account Type ID //-- objNameRet.clear(); const int cnt = _slotItemList.count(); if (refRow < 0) return (-1); if (refRow >= cnt) return (-1); //--------------------------->> QString commonContainerName; int commonContainerObjId (0); QList groupRows = slotItemGroupRowsAtRow (refRow); const int groupRowCnt = groupRows.count(); for (int inx = 0; inx < groupRowCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem && !slotItem->isDivider()) { const QString contName = slotItem->containerName(); const int contBaseId = slotItem->baseTypeId(); if (commonContainerName.isEmpty()) { commonContainerName = contName; commonContainerObjId = contBaseId; } else if (commonContainerName != contName) { // Differing Containers Found. Abort. return (0); // group contains slots on multiple objects } } } objNameRet = commonContainerName; return commonContainerObjId; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::firstSelectedRow (bool* isSlotRet /*=NULL*/) const { const int itemCnt = _slotItemList.count(); for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem && slotItem->isSelected()) { if (isSlotRet) { const bool isDiv = slotItem->isDivider(); *isSlotRet = !isDiv; } return (inx); //--------->> } } if (isSlotRet) *isSlotRet = false; return (-1); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QList EditSctSlotListTreeView::selectedRowIndices() const { const int itemCnt = _slotItemList.count(); if (itemCnt < 1) return QList(); // empty QList selRows; selRows.reserve (itemCnt); for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem && slotItem->isSelected()) { selRows.append (inx); } } return selRows; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::applyItemExpandedStates() { //--------------------------------------------------- const bool saveExpInProg = _setExpanded_inProgress; _setExpanded_inProgress = true; //--------------------------------------------------- const int itemCnt = _slotItemList.count(); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = _slotItemList [inx]; if (slotItem && slotItem->isDivider()) { const bool wantExp = slotItem->dataIsExpanded(); const bool isExp = slotItem->isExpanded(); // [QTreeWidget] if (wantExp != isExp) { slotItem->setExpanded (wantExp); } } } //--------------------------------------------------- _setExpanded_inProgress = saveExpInProg; //--------------------------------------------------- } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::resizeAllColumns() { for (int col = 0; col < COL_COUNT; ++col) { resizeColumnToContents (col); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::scrollToSelection (bool padBottom /*=true*/) { const QList selRows = selectedRowIndices(); const int selRowCnt = selRows.count(); if (selRowCnt == 0) return; //----------------------->> const int firstSelRow = selRows [0]; const int lastSelRowActual = selRows [selRowCnt-1]; const int itemCnt = _slotItemList.count(); int lastSelRow = lastSelRowActual; if ((firstSelRow == lastSelRowActual) && (firstSelRow >= 0) && (firstSelRow < itemCnt)) { // If a single selected item is an open divider, then include // the whole group in the scroll operation. const SlotItem* slotItem = _slotItemList [firstSelRow]; if (slotItem && slotItem->isDivider() && slotItem->isExpanded()) lastSelRow = firstSelRow + slotItem->childCount(); } if (padBottom) { // Scroll to show one additional row below the last selection // (unless we are already at the end). if (lastSelRow < itemCnt-1) { ++lastSelRow; } } // ********************************************************** // *** (1) Ensure that the LAST Selected Row is Visible *** // ********************************************************** if ((lastSelRow >= 0) && (lastSelRow < itemCnt)) { SlotItem* lastItem = _slotItemList [lastSelRow]; if (lastItem) scrollToItem (lastItem, QAbstractItemView::EnsureVisible); } // *********************************************************** // *** (2) Ensure that the FIRST Selected Row is Visible *** // *********************************************************** if ((firstSelRow != lastSelRow) && (firstSelRow >= 0) && (firstSelRow < itemCnt)) { SlotItem* firstItem = _slotItemList [firstSelRow]; if (firstItem) scrollToItem (firstItem, QAbstractItemView::EnsureVisible); } } void EditSctSlotListTreeView::expandGroups (bool onlySelectedDivs) { const int itemCnt = _slotItemList.count(); int expandCnt (0); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = _slotItemList [inx]; const bool isDiv = slotItem && slotItem->isDivider(); const bool isExp = slotItem && slotItem->isExpanded(); const bool doExp = slotItem && (!onlySelectedDivs || slotItem->isSelected()); if (slotItem && isDiv && !isExp && doExp) { slotItem->setExpanded (true); ++expandCnt; } } if (expandCnt > 0) { applyItemExpandedStates(); scrollToSelection(); } } void EditSctSlotListTreeView::collapseGroups (bool onlySelectedDivs) { const int itemCnt = _slotItemList.count(); int collapseCnt (0); int deselCnt (0); //--------------------------------------------------- const bool saveExpInProg = _setExpanded_inProgress; _setExpanded_inProgress = true; //--------------------------------------------------- for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = _slotItemList [inx]; if (slotItem == NULL) continue; //----------------------------- const bool isDiv = slotItem->isDivider(); const bool isExp = slotItem->isExpanded(); const bool doCollapse (!onlySelectedDivs || slotItem->isSelected()); if (isDiv && isExp && doCollapse) { slotItem->dataSetExpanded (false); slotItem->setExpanded (false); ++collapseCnt; deselCnt += deselectChildren (inx); } } //--------------------------------------------------- _setExpanded_inProgress = saveExpInProg; //--------------------------------------------------- if (_parentPanel && (deselCnt > 0)) { _parentPanel->notifySlotSelectionChanged(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::deselectChildren (int refRow) { const int itemCnt = _slotItemList.count(); if ((refRow < 0) || (refRow >= itemCnt)) return (0); //------------------------------------------------>> SlotItem* divItem = _slotItemList [refRow]; if (!divItem || !divItem->isDivider()) return (0); //---------------------------------------------->> //--------------------------------------------------- const bool saveSelInProg = _setSelection_inProgress; _setSelection_inProgress = true; //--------------------------------------------------- QList groupRows = slotItemGroupRowsAtRow (refRow); const int groupRowCnt = groupRows.count(); int deselCnt (0); for (int inx = 0; inx < groupRowCnt; ++inx) { const int row = groupRows [inx]; if ((row > refRow) && (row < itemCnt)) { SlotItem* slotItem = _slotItemList [row]; if (slotItem && slotItem->isSelected()) { slotItem->setSelected (false); ++deselCnt; } } } //--------------------------------------------------- _setSelection_inProgress = saveSelInProg; //--------------------------------------------------- return (deselCnt); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ********************************************** // *** Utility: Move QList Items Up or Down *** // ********************************************** // This utility method moves "selected" SlotItems within a QList // UP or DOWN one position -- and has a mode just to test if that operation // is valid given the size of the list and the nature of the "selection". // static bool EditSctSlotListTreeView::moveSelItemsUpOrDown ( QList& slotItems, char upOrDown, // 'U' or 'D' bool checkValidOnly /*=false*/) { static const char* mname ("moveSelItemsUpOrDown"); const int itemCnt = slotItems.count(); if (itemCnt < 2) return (false); //---------------------------->> // Count selected items int selItemCnt (0); for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* pDat = slotItems [inx]; if (pDat && pDat->isSelected()) ++selItemCnt; } // There must be at least one selected item. if (selItemCnt == 0) return (false); //-------------------------------->> if (upOrDown == 'U') { // If moving up, the first item cannot be selected. if (slotItems [0] && slotItems [0]->isSelected()) return (false); //-------------------------------------------->> } else // (upOrDown == 'D') { // If moving down, the last item cannot be selected. if (slotItems [itemCnt-1] && slotItems [itemCnt-1]->isSelected()) return (false); //---------------------------------------------------->> } if (checkValidOnly) { // The Move Up (or Move Down) operation IS available given // the current item selection. return (true); //---------->> } // ***************************************************** // *** Move Selected Items UP or DOWN one position *** // ***************************************************** if (upOrDown == 'U') { // ********************************************* // *** Move Selected Items UP One Position *** // ********************************************* // start at the 2nd item for (int inx = 1; inx < itemCnt; ++inx) { if (slotItems [inx] && slotItems [inx]->isSelected()) { // std::cout << mname << " UP swap " // << inx << ", " << inx-1 << std::endl; // selected: swap with prior item (move up). SlotItem* temp1 = slotItems [inx]; slotItems [inx] = slotItems [inx-1]; slotItems [inx-1] = temp1; } } } else // (upOrDown == 'D') { // *********************************************** // *** Move Selected Items DOWN One Position *** // *********************************************** // start at 2nd to last item, iterate backwards. for (int inx = itemCnt-2; inx >= 0; --inx) { if (slotItems [inx] && slotItems [inx]->isSelected()) { // std::cout << mname << " DOWN swap " // << inx << ", " << inx+1 << std::endl; // selected: swap with subsequent item (move down). SlotItem* temp2 = slotItems [inx]; slotItems [inx] = slotItems [inx+1]; slotItems [inx+1] = temp2; } } } //-- return (true); // success } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool EditSctSlotListTreeView::moveSelSlotItemsUpOrDown (char UorD, bool checkValidOnly) { const int itemCnt = _slotItemList.count(); if (UorD == 'U') { // *********************************************** // *** (1) Special "Move Item Up" Processing *** // *********************************************** // SPECIAL: Because of the special behavior of enforcing the first item // to always be a Divider, we need to "also" disable the Move Item UP // function when the SECOND item is selected and is a Slot Item. // (This is in addition to the normal checks performed by the support // function called below). if (itemCnt >= 2) { const SlotItem* secondItem = _slotItemList [1]; if (secondItem && secondItem->isSelected() && !secondItem->isDivider()) { // "Move Item Up" operation is invalid. // Insure that the first item (a divider) is visible. const SlotItem* firstItem = _slotItemList [0]; if (firstItem) scrollToItem (firstItem, QAbstractItemView::EnsureVisible); return (false); // move up is invalid. } } } // ****************************************************** // *** (2) Normal "Move Item Up or Down" Processing *** // ****************************************************** bool moveOk (false); // tentative if (checkValidOnly) { moveOk = moveSelItemsUpOrDown (_slotItemList, UorD, true); // check only } else // (NOT checkValidOnly) { QList listCopy = _slotItemList; moveOk = moveSelItemsUpOrDown (listCopy, UorD, false); // NOT check only const int listCopyCnt = listCopy.count(); if (moveOk && (rwAssert (listCopyCnt == itemCnt))) { QList newSlotDataList; newSlotDataList.reserve (itemCnt); for (int inx = 0; inx < itemCnt; ++inx) { SlotItem* slotItem = listCopy [inx]; if (slotItem) { newSlotDataList .append (slotItem->slotDataRef()); } } loadSctConfigSlotDataList (newSlotDataList); scrollToSelection(); } } return (moveOk); } bool EditSctSlotListTreeView::moveSelectedSlotItemsUp (bool checkValidOnly) { const bool moveOk = moveSelSlotItemsUpOrDown ('U', checkValidOnly); return (moveOk); } bool EditSctSlotListTreeView::moveSelectedSlotItemsDown (bool checkValidOnly) { const bool moveOk = moveSelSlotItemsUpOrDown ('D', checkValidOnly); return (moveOk); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool EditSctSlotListTreeView::moveSelGroupItemsUpOrDown (char UorD, bool checkValidOnly) { // *************************************************** // *** (1) Characterize Selected Groups (Dividers) *** // *************************************************** const int itemCnt = _slotItemList.count(); QSet rowsFromSelTopLevGroups; QList allDivItems; QList topDivItems; QList selTopDivRows; QList selSubDivRows; for (int row = 0; row < itemCnt; ++row) { SlotItem* slotItem = _slotItemList [row]; if (slotItem && slotItem->isDivider()) { const bool isTopLev (slotItem->parentRow() < 0); const bool isSel = slotItem->isSelected(); if (isTopLev && isSel) { const QList groupRows = slotItemGroupRowsAtRow (row); rowsFromSelTopLevGroups += groupRows.toSet(); } allDivItems << slotItem; if (isTopLev) topDivItems << slotItem; if (isSel) { // Note: We ignore 2nd level dividers which are under a // selected top level divider. if (isTopLev) selTopDivRows << row; else if (!rowsFromSelTopLevGroups.contains (row)) selSubDivRows << row; } } } // ********************************** // *** (2) Assess Selected Groups *** // ********************************** const int selTopDivCnt = selTopDivRows.count(); const int selSubDivCnt = selSubDivRows.count(); // Disable move operation if the selection includes both top-level // dividers AND sub-level dividers (ignoring sub-level dividers // inside top-level groups. // if ((selTopDivCnt > 0) && (selSubDivCnt > 0)) return (false); //-------->> if ((selTopDivCnt + selSubDivCnt) < 1) return (false); //-------->> const bool movingSubGroups = (selSubDivCnt > 0); QList scopedItems = movingSubGroups ? allDivItems : topDivItems; // ********************************************** // *** (3) Reorder the "scoped" SlotItem List *** // ********************************************** const bool moveOk = moveSelItemsUpOrDown (scopedItems, UorD, checkValidOnly); if (checkValidOnly || !moveOk) return (moveOk); //==========>> // ********************************************************************** // *** (4) Build a full Slot Data list from the reordered scoped list *** // ********************************************************************** const bool rebuildWithFlatGroups = movingSubGroups; QList newSlotDataList; newSlotDataList.reserve (itemCnt); const int scopedCnt = scopedItems.count(); for (int scInx = 0; scInx < scopedCnt; ++scInx) { SlotItem* groupDivItem = scopedItems [scInx]; if (groupDivItem == NULL) continue; //--------------------------------- const int groupDivRow = groupDivItem->itemRow(); const QList groupRows = slotItemGroupRowsAtRow (groupDivRow, rebuildWithFlatGroups); const int groupRowCnt = groupRows.count(); for (int grInx = 0; grInx < groupRowCnt; ++grInx) { const int grRow = groupRows [grInx]; if (rwAssert (grRow >= 0) && (rwAssert (grRow < itemCnt))) { const SlotItem* grItem = _slotItemList [grRow]; if (grItem) newSlotDataList.append (grItem->slotDataRef()); } } } // ********************************************************************** // *** (5) Rebuild the QTreeWidget items using the new Slot Data list *** // ********************************************************************** loadSctConfigSlotDataList (newSlotDataList); return (true); // move selected groups up or down, success. } bool EditSctSlotListTreeView::moveSelectedSlotGroupsUp (bool checkValidOnly) { const bool moveOk = moveSelGroupItemsUpOrDown ('U', checkValidOnly); return (moveOk); } bool EditSctSlotListTreeView::moveSelectedSlotGroupsDown (bool checkValidOnly) { const bool moveOk = moveSelGroupItemsUpOrDown ('D', checkValidOnly); return (moveOk); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::copySelItems (bool forCut /*=false*/) { // "Implied" selections -- i.e. slot items in selected closed groups -- // as well as actual selected slot items and dividers -- are copyd. const int itemCnt = _slotItemList.count(); int inclDivs (0); int inclSlots (0); QList slotDataList; slotDataList.reserve (std::max (1, itemCnt)); bool lastDivSelectedAndClosed (false); for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; const bool isSel = slotItem && slotItem->isSelected(); const bool isDiv = slotItem && slotItem->isDivider(); const bool isExp = slotItem && slotItem->isExpanded(); if (isDiv) lastDivSelectedAndClosed = isSel && !isExp; if (isSel || lastDivSelectedAndClosed) { (isDiv ? ++inclDivs : ++inclSlots); if (forCut) { slotDataList.append (slotItem->slotDataRef()); } else { // When copying, it's prudent for the slotData record to have // a new serial number. This may not be technically necessary, // as fresh serial numbers are assigned again also in the // "paste" (insert and append "copied") operations, but it's // a good idea. These serial numbers are free. // SctConfigSlotData itemData = slotItem->slotDataRef(); itemData.assignNewSerNum(); slotDataList.append (itemData); } } } // *************************************************** // *** Prepare Item Selection Description String *** // *************************************************** const int inclItems = inclDivs + inclSlots; QString descStr (tr ("Verb Items")); if (inclDivs == 0) { if (inclSlots == 1) descStr = tr ("Verb Slot"); else if (inclSlots > 1) descStr = tr ("%1 Verb Slots").arg (inclSlots); } else if (inclSlots == 0) { if (inclDivs == 1) descStr = tr ("Verb Divider"); else if (inclDivs > 1) descStr = tr ("%1 Verb Dividers").arg (inclDivs); } else if (inclItems == 1) descStr = tr ("Verb Item"); else if (inclItems > 1) descStr = tr ("%1 Verb Items").arg (inclItems); if (forCut) descStr.replace ("Verb", "Cut"); else descStr.replace ("Verb", "Copied"); // **************************************** // *** Record Selection in Clipboards *** // **************************************** SctManager* mgr = SctManager::inst(); if (mgr) { mgr->recordNewCopySlotSet (slotDataList, descStr, true); // setSlotClipboardToo } return (slotDataList.count()); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::cutSelItems() { (void) copySelItems (true); // for "Cut" const int removeCnt = removeSelItems(); return (removeCnt); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::removeSelItems() { // "Implied" selections -- i.e. slot items in selected closed groups -- // as well as actual selected slot items and dividers -- are removed. const int itemCnt = _slotItemList.count(); if (itemCnt < 1) return (0); QList newSlotDataList; newSlotDataList.reserve (itemCnt); int removeCnt (0); QSet removeChildRows; for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem == NULL) continue; //----------------------------- const bool isSel = slotItem->isSelected(); const bool isDiv = slotItem->isDivider(); const bool isExp = slotItem->isExpanded(); if (isDiv && isSel && !isExp) { const QList groupRows = slotItemGroupRowsAtRow (inx); removeChildRows += groupRows.toSet(); } if (isSel || removeChildRows.contains (inx)) { ++removeCnt; } else { newSlotDataList.append (slotItem->slotDataRef()); } } if (removeCnt > 0) { loadSctConfigSlotDataList (newSlotDataList); } return (removeCnt); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::copySelGroups (bool forCut /*=false*/) { const int itemCnt = _slotItemList.count(); // ************************************************** // *** (1) Accumulate items under selected groups *** // ************************************************** QSet selRowsWithChildren; selRowsWithChildren.reserve (itemCnt + 10); int inclGroups (0); for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem == NULL) continue; //----------------------------- const bool isSel = slotItem->isSelected(); const bool isDiv = slotItem->isDivider(); if (isDiv && isSel) { const QList groupRows = slotItemGroupRowsAtRow (inx); selRowsWithChildren += groupRows.toSet(); ++inclGroups; } } // ******************************************************* // *** (2) Build Slot Data List with accumulated items *** // ******************************************************* QList selSlotDataList; for (int inx = 0; inx < itemCnt; ++inx) { if (!selRowsWithChildren.contains (inx)) continue; //-------- const SlotItem* slotItem = _slotItemList [inx]; if (slotItem) { if (forCut) { selSlotDataList.append (slotItem->slotDataRef()); } else { // When copying, it's prudent for the slotData record to have // a new serial number. This may not be technically necessary, // as fresh serial numbers are assigned again also in the // "paste" (insert and append "copied") operations, but it's // a good idea. These serial numbers are free. // SctConfigSlotData itemData = slotItem->slotDataRef(); itemData.assignNewSerNum(); selSlotDataList.append (itemData); } } } // ****************************************************** // *** (3) Prepare Item Selection Description String *** // ****************************************************** QString descStr; if (forCut) { descStr = (inclGroups == 1) ? QString (tr ("1 Cut Group")) : QString (tr ("%1 Cut Groups")) .arg (inclGroups); } else { descStr = (inclGroups == 1) ? QString (tr ("1 Copied Group")) : QString (tr ("%1 Copied Groups")) .arg (inclGroups); } // ******************************************* // *** (4) Record Selection in Clipboards *** // ******************************************* SctManager* mgr = SctManager::inst(); if (mgr) { mgr->recordNewCopySlotSet (selSlotDataList, descStr, true); // setSlotClipboardToo } return (selSlotDataList.count()); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::cutSelGroups() { (void) copySelGroups (true); // for "Cut" const int removeCnt = removeSelGroups(); return (removeCnt); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::removeSelGroups() { const int itemCnt = _slotItemList.count(); if (itemCnt < 1) return (0); QList newSlotDataList; newSlotDataList.reserve (itemCnt); int removeCnt (0); QSet removeChildRows; for (int inx = 0; inx < itemCnt; ++inx) { const SlotItem* slotItem = _slotItemList [inx]; if (slotItem == NULL) continue; //----------------------------- const bool isSel = slotItem->isSelected(); const bool isDiv = slotItem->isDivider(); if (isDiv && isSel) { const QList groupRows = slotItemGroupRowsAtRow (inx); removeChildRows += groupRows.toSet(); } if (removeChildRows.contains (inx)) { ++removeCnt; } else { newSlotDataList.append (slotItem->slotDataRef()); } } if (removeCnt > 0) { loadSctConfigSlotDataList (newSlotDataList); } return (removeCnt); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::insertSeriesSlots ( const QList& scList, const SctConfig* sctCfg) { static const char* mname ("EditSctSlotListTreeView::insertSeriesSlots"); // std::cout << mname << ": " << scList.count() << std::endl; const int scCnt = scList.count(); bool isSlot (false); const int selRow = firstSelectedRow (&isSlot); if ((selRow < 0) || (scCnt < 1)) { QApplication::beep(); return; //--------->> } const int itemCnt = _slotItemList.count(); int insertIndex = isSlot ? selRow : (selRow+1); if (insertIndex >= itemCnt) { appendSeriesSlots (scList, sctCfg); return; //----------------------->> } SctSumFuncAssignSpec sumFuncAssignSpec; if (sctCfg) sumFuncAssignSpec = sctCfg->sumFuncAssignSpecRef(); // Get current slot data list. QList newSlotDataList = _slotDataList; QSet newSelSerialNums; int insertCnt (0); for (int inx = 0; inx < scCnt; ++inx) { const SlotColRef scRef = scList [inx]; Slot* slotPtr = scRef.slot(); if (slotPtr == NULL) continue; //---------------------------- const bool isSeriesLike = slotPtr->isA (Slot::SeriesSlotBit) || slotPtr->isA (Slot::TableSeriesSlotBit); if (isSeriesLike) { // Create new Slot Item Data SctConfigSlotData newSlotData; newSlotData .setSlot (slotPtr, scRef.col()); newSlotData ._sumFuncSpec = scRef.valid() ? sumFuncAssignSpec.functionForSlot (scRef) : sumFuncAssignSpec.defaultSumFuncSpec(); newSlotDataList.insert (insertIndex++, newSlotData); newSelSerialNums.insert (newSlotData.serNum()); ++insertCnt; } } if (insertCnt < 1) { // Nothing was inserted. Set the selection to the insertion point. clearSelection(); if (_slotItemList [selRow]) _slotItemList [selRow]->setSelected (true); } else { loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); } scrollToSelection(); resizeAllColumns(); } void EditSctSlotListTreeView::appendSeriesSlots ( const QList& scList, const SctConfig* sctCfg) { static const char* mname ("EditSctSlotListTreeView::appendSeriesSlots"); // std::cout << mname << ": " << scList.count() << std::endl; const int scCnt = scList.count(); if (scCnt < 1) { QApplication::beep(); return; //--------->> } SctSumFuncAssignSpec sumFuncAssignSpec; if (sctCfg) sumFuncAssignSpec = sctCfg->sumFuncAssignSpecRef(); // Get current slot data list. QList newSlotDataList = _slotDataList; QSet newSelSerialNums; int appendCnt (0); QList slotList = _slotItemList; selectOnlySerNum (slotList, (-1)); for (int inx = 0; inx < scCnt; ++inx) { const SlotColRef scRef = scList [inx]; Slot* slotPtr = scRef.slot(); if (slotPtr == NULL) continue; //---------------------------- const bool isSeriesLike = slotPtr->isA (Slot::SeriesSlotBit) || slotPtr->isA (Slot::TableSeriesSlotBit); if (isSeriesLike) { // Create new Slot Item Data SctConfigSlotData newSlotData; newSlotData .setSlot (scRef.slot(), scRef.col()); newSlotData ._sumFuncSpec = scRef.valid() ? sumFuncAssignSpec.functionForSlot (scRef) : sumFuncAssignSpec.defaultSumFuncSpec(); newSlotDataList.append (newSlotData); newSelSerialNums.insert (newSlotData.serNum()); ++appendCnt; } } if (appendCnt > 0) { loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); } scrollToSelection(); resizeAllColumns(); } void EditSctSlotListTreeView::reassignSeriesSlot (SlotColRef scRef, const SctConfig* sctCfg) { bool isSlot (false); const int selRow = firstSelectedRow (&isSlot); // Get current slot data list. QList newSlotDataList = _slotDataList; const int itemCnt = newSlotDataList.count(); if ((selRow < 0) || (selRow >= itemCnt)) { QApplication::beep(); return; //--------->> } SctSumFuncAssignSpec sumFuncAssignSpec; if (sctCfg) sumFuncAssignSpec = sctCfg->sumFuncAssignSpecRef(); // Create new Slot Item Data SctConfigSlotData newSlotData; newSlotData .setSlot (scRef.slot(), scRef.col()); newSlotData ._sumFuncSpec = scRef.valid() ? sumFuncAssignSpec.functionForSlot (scRef) : sumFuncAssignSpec.defaultSumFuncSpec(); newSlotDataList [selRow] = newSlotData; QSet newSelSerialNums; newSelSerialNums.insert (newSlotData.serNum()); loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); scrollToSelection(); resizeAllColumns(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::insertDivider (bool forSerTab) { const QList selRows = selectedRowIndices(); if (selRows.isEmpty()) { QApplication::beep(); return; //--------->> } // Insert above first selected row const int rowInx = selRows [0]; // Get current slot data list. QList newSlotDataList = _slotDataList; const int itemCnt = newSlotDataList.count(); if ((rowInx < 0) || (rowInx >= itemCnt)) { QApplication::beep(); return; //--------->> } // Create new Divider Item SctConfigSlotData newDivData; newDivData .setDivider (forSerTab, ""); const int newSerNum = newDivData.serNum(); newSlotDataList.insert (rowInx, newDivData); QSet newSelSerialNums; newSelSerialNums.insert (newDivData.serNum()); loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); scrollToSelection(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::appendDivider (bool forSerTab) { // Get current slot data list. QList newSlotDataList = _slotDataList; const int itemCnt = newSlotDataList.count(); itemCnt; // (avoid compilation warning) // Create new Divider Item SctConfigSlotData newDivData; newDivData .setDivider (forSerTab, ""); const int newSerNum = newDivData.serNum(); newSlotDataList.append (newDivData); QSet newSelSerialNums; newSelSerialNums.insert (newDivData.serNum()); loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); scrollToSelection(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::insertSlotDataList ( const QList& addSlotDataList) { static const char* mname ("EditSctSlotListTreeView::insertSlotDataList"); // std::cout << mname << ": " << addSlotDataList.count() << std::endl; const int sdCnt = addSlotDataList.count(); const bool datStartsWithDiv = (sdCnt > 0) && (addSlotDataList [0] .isDivider()); bool selIsSlot (false); const int selRow = firstSelectedRow (&selIsSlot); if ((selRow < 0) || (sdCnt < 1)) { QApplication::beep(); return; //--------->> } // Insert above currently selected item UNLESS the currently selected // item is a divider AND the new slot data list doesn't start with a // divider. // int insertIndex = selRow; // tentative if (!selIsSlot && !datStartsWithDiv) { insertIndex = selRow+1; } const int itemCnt = _slotItemList.count(); if (insertIndex >= itemCnt) { appendSlotDataList (addSlotDataList); return; //------------------------->> } // Get current slot data list. QList newSlotDataList = _slotDataList; QSet newSelSerialNums; int insertCnt (0); for (int inx = 0; inx < sdCnt; ++inx) { SctConfigSlotData newSlotData = addSlotDataList [inx]; newSlotData.assignNewSerNum(); newSlotDataList.insert (insertIndex++, newSlotData); newSelSerialNums.insert (newSlotData.serNum()); ++insertCnt; } if (insertCnt < 1) { // Nothing was inserted. Set the selection to the insertion point. clearSelection(); if (_slotItemList [selRow]) _slotItemList [selRow]->setSelected (true); } else { loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); } scrollToSelection(); resizeAllColumns(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::appendSlotDataList ( const QList& addSlotDataList) { static const char* mname ("EditSctSlotListTreeView::appendSlotDataList"); // std::cout << mname << ": " << addSlotDataList.count() << std::endl; const int sdCnt = addSlotDataList.count(); if (sdCnt < 1) { QApplication::beep(); return; //--------->> } // Get current slot data list. QList newSlotDataList = _slotDataList; QSet newSelSerialNums; int appendCnt (0); for (int inx = 0; inx < sdCnt; ++inx) { SctConfigSlotData newSlotData = addSlotDataList [inx]; newSlotData.assignNewSerNum(); newSlotDataList.append (newSlotData); newSelSerialNums.insert (newSlotData.serNum()); ++appendCnt; } loadSctConfigSlotDataList (newSlotDataList); selectRowsBySerialNum (newSelSerialNums); scrollToSelection(); resizeAllColumns(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ******************************** // *** Object Type Operations *** // ******************************** // static QString EditSctSlotListTreeView::slotContainerName (const Slot* slotPtr) { if (slotPtr == NULL) return QString(); Account* acct = slotPtr->getAccount(); if (acct) return acct->getCompleteName(); SimObj* obj = slotPtr->getSimObj(); if (obj) return obj->getCompleteName(); return QString(); } // static int EditSctSlotListTreeView::slotContainerTypeId (const Slot* slotPtr, bool baseType) { if (slotPtr == NULL) return (0); //---------------------------->> Account* acct = slotPtr->getAccount(); if (acct) { return acct->typeId(); } SimObj* obj = slotPtr->getSimObj(); if (obj) { if (baseType && obj->isA (RESERVOIR_ID)) { // Treat Reservoirs Polymorphically return (RESERVOIR_ID); } return obj->objTypeId(); } return (0); } // static QString EditSctSlotListTreeView::typeIdStr (int typeId, bool plural /*=false*/) { // Note: New low-level facilities for this need to be developed. At this // time, the results from the existing utilities need to be "munged" // in strange ways. // The following cases were take from these files in June 2011 (Rw 6.1): // Sim/libSimClassIds.hpp // EngrObjs/libEngrObjsClassIds.hpp // Accounting/libAccountingClassIds.hpp // // Note -- See also methods: // QString SimObj::getLongTypeName (bool inclIconTag /*=false*/); // virtual const QString& Account::getType() const = 0; if (plural) { // Handle irregular plurals switch (typeId) { case AGG_REACH_ID: return ("Aggregate Reaches"); case REACH_ID: return ("Reaches"); } } const char* s = ""; switch (typeId) { case SIM_OBJ_ID: s= "Simulation Object"; break; case AGGREGATE_OBJ_ID: s= "Aggregate Object"; break; case DATA_OBJ_ID: s= "Data Object"; break; case SNAP_SHOT_OBJ_ID: s= "Snapshot Object"; break; case SCENARIO_OBJ_ID: s= "Scenario Object"; break; case AGG_DIVERSION_SITE_ID: s= "Aggregate Diversion Site"; break; case AGG_REACH_ID: s= "Aggregate Reach"; break; case CANAL_ID: s= "Canal"; break; case CONFLUENCE_ID: s= "Confluence"; break; case LEVEL_POWER_RESERVOIR_ID: s= "Level Power Reservoir"; break; case POWER_RESERVOIR_ID: s= "Power Reservoir"; break; case PUMPED_STORAGE_ID: s= "Pumped Storage Reservoir"; break; case REACH_ID: s= "Reach"; break; case RESERVOIR_ID: s= "Reservoir"; break; case SLOPE_POWER_RESERVOIR_ID: s= "Slope Power Reservoir"; break; case STORAGE_RESERVOIR_ID: s= "Storage Reservoir"; break; case THERMAL_ID: s= "Thermal Object"; break; case WATER_USER_ID: s= "Water User"; break; case GROUND_WATER_STORAGE_ID: s= "Groundwater Storage Object"; break; case AGG_DISTRIB_CANAL_ID: s= "Aggregate Distribution Canal"; break; case DISTRIBUTION_CANAL_ID: s= "Distribution Canal"; break; case STREAM_GAGE_ID: s= "Stream Gage"; break; case DIVERSION_OBJECT_ID: s= "Diversion"; break; case BIFURCATION_ID: s= "Bifurcation"; break; case INLINE_POWER_ID: s= "Inline Power Plant"; break; case CONTROL_POINT_ID: s= "Control Object"; break; case COMPOBJ_ID: s= "Computational Object"; break; case PIPELINE_ID: s= "Pipeline"; break; case PIPEJUNCTION_ID: s= "Pipe Junction"; break; case INLINEPUMP_ID: s= "Inline Pump"; break; case ACCOUNT_ID: s= "Account"; break; case WATER_ACCOUNT_ID: s= "Water Account"; break; case DIVERSION_ACCOUNT_ID: s= "Diversion Account"; break; case PASSTHROUGH_ACCOUNT_ID: s= "Passthrough Account"; break; case STORAGE_ACCOUNT_ID: s= "Storage Account"; break; case INSTREAMFLOW_ACCOUNT_ID: s= "Instream Flow Account"; break; default: s= "OBJ TYPE ERROR"; break; } if (plural) { // handle regular plurals static const QChar pluralSuffix ('s'); const QString pluralStr = QString (s) + pluralSuffix; return (pluralStr); } const QString singularStr (s); return (singularStr); } // static bool EditSctSlotListTreeView::isAccountTypeId (int typeId) { // See Accounting/libAccountingClassIds.hpp return ( (typeId >= ACCOUNTING_BASE_ID) && (typeId < ACCOUNTING_BASE_ID + ACCOUNTING_NUM_ID) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::createSimilarGroups ( int groupRow, const QList& newObjNameList) { // Create groups similar to the specified group for the given list // of SimObj or Account names. // NEEDS REIMPLEMENTATION -- XXX TODO } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::initConnections() { // ***************************** // *** QTreeWidget Signals *** // ***************************** connect (this, SIGNAL (itemChanged (QTreeWidgetItem*, int)), SLOT (slotItemChanged (QTreeWidgetItem*, int))); connect (this, SIGNAL (itemClicked (QTreeWidgetItem*, int)), SLOT (slotItemClicked (QTreeWidgetItem*, int))); connect (this, SIGNAL (itemCollapsed (QTreeWidgetItem*)), SLOT (slotItemCollapsed (QTreeWidgetItem*))); connect (this, SIGNAL (itemDoubleClicked (QTreeWidgetItem*, int)), SLOT (slotItemDoubleClicked (QTreeWidgetItem*, int))); connect (this, SIGNAL (itemExpanded (QTreeWidgetItem*)), SLOT (slotItemExpanded (QTreeWidgetItem*))); connect (this, SIGNAL (itemPressed (QTreeWidgetItem*, int)), SLOT (slotItemPressed (QTreeWidgetItem*, int))); connect (this, SIGNAL (itemSelectionChanged()), SLOT (slotItemSelectionChanged())); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private slot void EditSctSlotListTreeView::slotItemChanged (QTreeWidgetItem* item, int col) { static const char* mname ("EditSctSlotListTreeView::slotItemChanged"); SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << ")" << std::endl; // Only the item label is editable if (slotItem && (col == COL_ItemLabel)) { const QString newText = item->text (col); const QString oldText = slotItem->itemLabelStr(); if (newText != oldText) { slotItem->setItemLabelStr (newText); const int cnt = _slotDataList.count(); if ((row >= 0) && (row < cnt)) { _slotDataList [row] ._slotLabel = newText; _slotDataList [row] ._slotMultiLine = SctConfig::breakSlotLabel (newText.toLatin1()); } if (_parentPanel) _parentPanel->notifyCellEditEnded(); } } } // private slot void EditSctSlotListTreeView::slotItemClicked (QTreeWidgetItem* item, int col) { static const char* mname ("EditSctSlotListTreeView::slotItemClicked"); SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << "," << col << ")" << std::endl; } // private slot void EditSctSlotListTreeView::slotItemDoubleClicked (QTreeWidgetItem* item, int col) { static const char* mname ("EditSctSlotListTreeView::slotItemDoubleClicked"); SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << "," << col << ")" << std::endl; } // private slot void EditSctSlotListTreeView::slotItemPressed (QTreeWidgetItem* item, int col) { static const char* mname ("EditSctSlotListTreeView::slotItemPressed"); SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << "," << col << ")" << std::endl; const bool ena = cellEditable (row, col); RwQt4Utils::enableItemEditing (item, ena); } // private slot void EditSctSlotListTreeView::slotItemCollapsed (QTreeWidgetItem* item) { static const char* mname ("EditSctSlotListTreeView::slotItemCollapsed"); if (_setExpanded_inProgress) return; //-------------------------------->> SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << ")" << std::endl; if (slotItem) { if (slotItem->dataIsExpanded()) { slotItem->dataSetExpanded (false); const int deselCnt = deselectChildren (row); deselCnt; // (avoid compilation warning) if (_parentPanel) { _parentPanel->notifyGroupExpandedChanged(); } } } } // private slot void EditSctSlotListTreeView::slotItemExpanded (QTreeWidgetItem* item) { static const char* mname ("EditSctSlotListTreeView::slotItemExpanded"); if (_setExpanded_inProgress) return; //-------------------------------->> SlotItem* slotItem = dynamic_cast (item); const int row = slotItem ? slotItem->itemRow() : (-1); // std::cout << mname << " (" << row << ")" << std::endl; if (slotItem) { if (!slotItem->dataIsExpanded()) { slotItem->dataSetExpanded (true); if (_parentPanel) { _parentPanel->notifyGroupExpandedChanged(); } } } } // private slot void EditSctSlotListTreeView::slotItemSelectionChanged() { static const char* mname ( "EditSctSlotListTreeView::slotItemSelectionChanged"); static int callCnt (0); ++callCnt; if (_rebuildTree_inProgress) return; if (_setSelection_inProgress) return; //-------------------------------->> // std::cout << mname << " [#" << callCnt << "]" << std::endl; if (_parentPanel) { _parentPanel->notifySlotSelectionChanged(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // virtual from QWidget void EditSctSlotListTreeView::mousePressEvent (QMouseEvent* evt) { static const char* mname ("EditSctSlotListTreeView::mousePressEvent"); // Call base class method QTreeWidget::mousePressEvent (evt); const QModelIndex posIndex = indexAt (evt->pos()); const int row = posIndex.row(); const int col = posIndex.column(); const int rowCnt = _slotItemList.size(); // std::cout << mname // << " [" << row << "," << col << "]" // << std::endl; if ( (row < 0) || (row >= rowCnt) || (col < 0) || (col >= COL_COUNT) ) { clearSelection(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::mouseReleaseEvent (QMouseEvent* evt) { static const char* mname ("EditSctSlotListTreeView::mouseReleaseEvent"); // Call base class method QTreeWidget::mouseReleaseEvent (evt); // const QModelIndex posIndex = indexAt (evt->pos()); // const int row = posIndex.row(); // const int col = posIndex.column(); // const int rowCnt = _slotItemList.size(); // std::cout << mname // << " [" << row << "," << col << "]" // << std::endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QColor EditSctSlotListTreeView::dividerBgColor (bool forSerTab) const { const SctConfig* cfg = sctConfig(); if (cfg) { if (forSerTab) return cfg->colorTabDivBg(); else return cfg->colorSlotDivBg(); } // Not expected static const QColor defaultColor (Qt::lightGray); return defaultColor; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::cellStr (int row, int col, bool forEdit /*=false*/) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) return QString(); //----------------------------------------------->> const SlotItem* pDat = _slotItemList [row]; if (pDat == NULL) return QString(); //------------------------------>> static const QString SP (" "); QString dispStr; switch (col) { case COL_UnitType: dispStr = pDat->unitTypeStr(); break; case COL_StepSize: dispStr = pDat->stepSizeStr(); break; case COL_SerNum: dispStr = QString::number (pDat->serNum()); break; case COL_InxDebug: dispStr = pDat->indexDebugStr(); break; case COL_SlotName: { dispStr = pDat->slotNameStr(); if (!forEdit) { const int slotCol = pDat->slotDataRef()._rwSlotCol; if (slotCol > 0) { dispStr += QString (" [%1]") .arg (slotCol); } } break; } case COL_ItemLabel: { dispStr = pDat->itemLabelStr(); if (!forEdit) { // SPECIAL CASE 1: If a Divider label is blank and the Divider // Group is Collapsed, then show the text for the subsequent // Slot Item. if (dispStr.trimmed().isEmpty() && pDat->isDivider() && !pDat->isExpanded()) { const int nextRow = row+1; if (nextRow < rowCnt) { const SlotItem* nextItem = _slotItemList [nextRow]; if (nextItem && !nextItem->isDivider()) { dispStr = nextItem->itemLabelStr(); // continue with normal processing } } } // SPECIAL CASE 2: To ensure that all lines have the full text // height, for non-edit contexts, return at least a single space // character. if (dispStr.isEmpty()) { return SP; //------>> } } break; } } if (!forEdit && !dispStr.isEmpty()) { // For display, add leading and trailing spaces dispStr = SP + dispStr + SP; } return dispStr; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::cellTipStr (int row, int col) const { const int rowCnt = _slotItemList.count(); if (row < 0) return QString(); if (row >= rowCnt) return QString(); //-------------------------------->> col; // (avoid compilation waring) const QString slotName = slotNameStr (row).trimmed(); const QString slotDesc = slotDescStr (row); const bool slotLabelDiff = (slotName != itemLabelStr (row).trimmed()); const bool hasDesc = !slotDesc.isEmpty(); if (slotLabelDiff || hasDesc) { QString tipStr = QString (tr ("Slot: ")) + slotName; if (hasDesc) { tipStr += "\n"; tipStr += rwStr::limitLineLength (slotDesc, 90); } return tipStr; } return QString(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QIcon EditSctSlotListTreeView::cellIcon (int row, int col, QSize& retSize) const { // A note about Icon Sizes. QIcons don't convey a 'natural' size. // The natural size needs to be measured from the original QPixmap. retSize = QSize (0,0); // returned size QIcon ri; // returned icon const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) return (ri); //------------------------------------------>> switch (col) { case COL_ItemLabel: ri = slotTypeIcon (row, retSize); break; } return (ri); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool EditSctSlotListTreeView::cellEditable (int row, int col) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) return (false); //--------------------------------------------->> // bool isEditable (false); // tentative // const SlotItem* pDat = _slotItemList [row]; // // switch (col) // { // } const bool isEditable (col == COL_ItemLabel); return (isEditable); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int EditSctSlotListTreeView::findSerialNumRow (int serNum) const { if (serNum <= 0) return (-1); //------------------------->> const int rowCnt = _slotItemList.count(); for (int row = 0; row < rowCnt; ++row) { const SlotItem* pDat = _slotItemList [row]; if (pDat && (pDat->serNum() == serNum)) { return (row); //--------->> } } return (-1); // row not found for the given SerialNum } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool EditSctSlotListTreeView::isSlotDividerRow (int row) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) { return (false); //----->> } const SlotItem* pDat = _slotItemList [row]; const bool isDiv = pDat && pDat->isSlotDivider(); return (isDiv); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool EditSctSlotListTreeView::isTabDividerRow (int row) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) { return (false); //----->> } const SlotItem* pDat = _slotItemList [row]; const bool isDiv = pDat && pDat->isTabDivider(); return (isDiv); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QIcon EditSctSlotListTreeView::slotTypeIcon (int row, QSize& retSize) const { QIcon retIcon; // isNull() const int rowCnt = _slotItemList.count(); if ((row >= 0) && (row < rowCnt)) { const SlotItem* pDat = _slotItemList [row]; if (pDat) { const QPixmap pmap = pDat->slotTypePixmap(); retIcon = QIcon (pmap); retSize = !pmap.isNull() ? pmap.size() : QSize (0,0); } } return retIcon; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::unitTypeStr (int row) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) { return QString(); //----->> } const SlotItem* pDat = _slotItemList [row]; const QString retStr = pDat ? pDat->unitTypeStr() : QString(); return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::stepSizeStr (int row) const { const int rowCnt = _slotItemList.count(); if ((row < 0) || (row >= rowCnt)) { return QString(); //----->> } const SlotItem* pDat = _slotItemList [row]; const QString retStr = pDat ? pDat->stepSizeStr() : QString(); return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::itemLabelStr (int row) const { QString retStr; const int rowCnt = _slotItemList.count(); if ((row >= 0) && (row < rowCnt)) { const SlotItem* pDat = _slotItemList [row]; if (pDat) retStr = pDat->itemLabelStr(); } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::slotNameStr (int row) const { QString retStr; const int rowCnt = _slotItemList.count(); if ((row >= 0) && (row < rowCnt)) { const SlotItem* pDat = _slotItemList [row]; if (pDat) retStr = pDat->slotNameStr(); } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString EditSctSlotListTreeView::slotDescStr (int row) const { QString retStr; const int rowCnt = _slotItemList.count(); if ((row >= 0) && (row < rowCnt)) { const SlotItem* pDat = _slotItemList [row]; if (pDat) retStr = pDat->slotDescStr(); } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void EditSctSlotListTreeView::ensureFirstItemIsDivider ( bool doRebuildTree /*=true*/) { static const char* mname ( "EditSctSlotListTreeView::ensureFirstItemIsDivider"); const int rowCnt = _slotDataList.count(); const bool needInitialDivider = (rowCnt == 0) || !_slotDataList [0].isDivider(); if (needInitialDivider) { SctConfigSlotData newDiv; newDiv.setDivider (true, tr ("Series Slot Sheet")); // forSerTab _slotDataList.insert (0, newDiv); if (doRebuildTree) rebuildTree(); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QSize EditSctSlotListTreeView::maxIconSize() const { const QSize retSize (16,16); return (retSize); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // *************************************************** // *** class EditSctSlotListTreeView :: SlotItem *** // *************************************************** EditSctSlotListTreeView::SlotItem::SlotItem ( EditSctSlotListTreeView* parentTree, const SctConfigSlotData& slotData) : QTreeWidgetItem(), _parentTree (parentTree), _slotData (slotData), _slotTypePixmap(), _unitTypeStr(), _containerName(), // SimObj or Account Name _objTypeId (0), // SimObj or Account Type ID _baseTypeId (0), // .. all Reservoirs: RESERVOIR_ID _slotVisible (false), _itemRow (-1), // row index for this item _parentRow (-1), // row index for this item's tree parent _sibInx (-1) // index of this item among item's parent's children. { Slot* slotPtr (NULL); if (_slotData ._itemType == 'S') { // Note [8-2011; Rw 6.1]: The legacy, default behavior of a support // method used in the SimWorkspace::locateSlot() method REPORTS AN // ERROR (to diagnostics) when the given name matches a SlotProxy // which // is not instantiated. That is unfortunate. A new // parameterized version of that method is used here to avoid the // reporting of that condition as an error. // Note: slotPtr will be NULL if the slot is not found. slotPtr = rwWorkspace->locateSlot ( _slotData._rwSlotName, false, // DON'T allowErrorsToBeReported (see above). true, // look on SimObjs true, // look on exchanges true); // look on supplies // Note: Shows "question mark" icon for "Missing" Slots _slotTypePixmap = RwQtUtils::getQPixmapIconForSlot (slotPtr); _containerName = slotContainerName (slotPtr); _objTypeId = slotContainerTypeId (slotPtr, false); _baseTypeId = slotContainerTypeId (slotPtr, true); // Assess "visibility" of slot. if (slotPtr) { SimObj* simObj = slotPtr->getSimObj(); if (simObj) { // This test is relative to the currently selected controller. const bool slotInUse = simObj->isSlotInUse (slotPtr); _slotVisible = slotInUse && slotPtr->isVisible(); } else { _slotVisible = slotPtr->isVisible(); } } } else // (Not Slot Item; Divider) { // For Dividers, provide a blank icon so that text is indented the // same on those lines (when a column shows both slot label text AND // slot type icons). _slotTypePixmap = RwQPixmap16::blank(); } if (slotPtr) { SlotColRef scRef (slotPtr, _slotData._rwSlotCol); _unitTypeStr = unitMgr->getUnitType (scRef.getPrimUnitType()); } updateCells(); } void EditSctSlotListTreeView::SlotItem::updateCells() { setText (COL_ItemLabel, itemLabelStr()); setText (COL_SlotName, slotNameStr()); setText (COL_UnitType, unitTypeStr()); setText (COL_StepSize, stepSizeStr()); if (COL_SerNum < COL_COUNT) setText (COL_SerNum, QString::number (serNum())); if (COL_InxDebug < COL_COUNT) setText (COL_InxDebug, indexDebugStr()); const QPixmap pmap = slotTypePixmap(); if (pmap.isNull()) setIcon (COL_ItemLabel, QIcon()); else setIcon (COL_ItemLabel, pmap); QBrush bgBrush; if (_parentTree) { if (isTabDivider()) bgBrush = _parentTree->dividerBgColor (true); // forSerTab else if (isSlotDivider()) bgBrush = _parentTree->dividerBgColor (false); // NOT forSerTab } const int colCnt = columnCount(); for (int col = 0; col < colCnt; ++col) { setBackground (col, bgBrush); } } void EditSctSlotListTreeView::SlotItem::setItemLabelStr ( const QString& newVal) { _slotData._slotLabel = newVal; _slotData._slotMultiLine = SctConfig::breakSlotLabel (newVal.toLatin1()); } QString EditSctSlotListTreeView::SlotItem::itemLabelStr() const { return _slotData._slotLabel; } QString EditSctSlotListTreeView::SlotItem::slotNameStr() const { return _slotData._rwSlotName; } QString EditSctSlotListTreeView::SlotItem::indexDebugStr() const { static const QString fmt ("row %1, parRow %2 sibInx-%4 kids-%5"); const QString debugStr = fmt .arg (_itemRow) .arg (_parentRow) .arg (_sibInx) .arg (childCount()); return (debugStr); } QPixmap EditSctSlotListTreeView::SlotItem::slotTypePixmap() const { if (isDivider()) { return QPixmap(); // NULL } return (_slotTypePixmap); } QString EditSctSlotListTreeView::SlotItem::stepSizeStr() const { QString retStr; // Note: slotPtr will be NULL if the slot is not found. Slot* slotPtr = rwWorkspace->locateSlot ( _slotData._rwSlotName, false, // DON'T allowErrorsToBeReported. true, // look on SimObjs true, // look on exchanges true); // look on supplies if (slotPtr) { SlotColRef scRef (slotPtr, _slotData._rwSlotCol); const DeltaTime slotStep (scRef.getStep()); const QString unitsStr (slotStep.singleUnitsAsString()); const int unitMultiple (slotStep.time()); if (unitMultiple > 0) retStr = QString ("%1 %2") .arg (unitMultiple) .arg (unitsStr); } return retStr; } QString EditSctSlotListTreeView::SlotItem::slotDescStr() const { QString retStr; // Note: slotPtr will be NULL if the slot is not found. const Slot* slotPtr = rwWorkspace->locateSlot ( _slotData._rwSlotName, false, // DON'T allowErrorsToBeReported. true, // look on SimObjs true, // look on exchanges true); // look on supplies if (slotPtr) { retStr = slotPtr->getUserDesc().trimmed(); } return retStr; } void EditSctSlotListTreeView::SlotItem::setItemLabel ( const QString& newLabelStr) { _slotData._slotLabel = newLabelStr; _slotData._slotMultiLine = SctConfig::breakSlotLabel (newLabelStr.toLatin1()); } void EditSctSlotListTreeView::SlotItem::setItemTreeData ( int itemRow, // row index for this item int parentRow, // row index for this item's tree parent int sibInx) // index of this item among item's parent's children. { _itemRow = itemRow; _parentRow = parentRow; _sibInx = sibInx; } //--- (end EditSctSlotListTreeView.cpp) ---