// $Id: RepGenSlotText.cpp,v 1.12 2010/11/11 01:47:57 philw Exp $ // // class RepGenSlotText : public RepGenSlot // //-- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- static const int MAX_SLOT_DATA_ROWS (300); #ifndef RepGenSlotTextINCLUDED #include "RepGenSlotText.hpp" #endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #ifndef RwModelReportINCLUDED #include "RwModelReport.hpp" #endif #ifndef RepGenUtilsINCLUDED #include "RepGenUtils.hpp" #endif #ifndef cwfstreamINCLUDED #include "cwfstream.hpp" #endif #ifndef SlotINCLUDED #include "Slot.hpp" #endif #ifndef SeriesSlotINCLUDED #include "SeriesSlot.hpp" #endif #ifndef ListSlotINCLUDED #include "ListSlot.hpp" #endif #ifndef SlotColRefINCLUDED #include "SlotColRef.hpp" #endif #ifndef SimObjINCLUDED #include "SimObj.hpp" #endif #ifndef SlotGUIUtilsINCLUDED #include "SlotGUIUtils.hpp" #endif #include "rwStr.hpp" #include <QStringList> #include <QString> //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- static const QString nbspQstr (" "); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // constructor 1 of 1 RepGenSlotText::RepGenSlotText (RwModelReport* rep, const Slot* slotPtr) : RepGenSlot (rep, slotPtr) { } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- RepGenSlotText::~RepGenSlotText() { } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RepGenSlotText::writeSlotListHeader (bool measureOnly, QVector<RepGen::ColDat>& colDatVec, SlotListType slotListType, const QString& listTitle, cwofstream& os) const { static const char (*mname) ("RepGenSlotText::writeSlotListHeader"); QStringList columnLabelStrList; if (!measureOnly && !listTitle.isEmpty()) { const QString titleBox = RepGen::textBox (listTitle); os << qPrintable (titleBox) << endl; } switch (slotListType) { case SlotList_Scalar: columnLabelStrList << "Type" // [0] << "Slot Name" // [1] << "Value" // [2] << "Units"; // [3] break; case SlotList_Series: columnLabelStrList << "Type" // [0] << "Slot Name" // [1] << "Units" // [2] << "Rows" // [3] << "Cols" // [4] << "Step" // [5] << "Start" // [6] << "End"; // [7] break; case SlotList_Other: columnLabelStrList << "Type" // [0] << "Slot Name" // [1] << "Rows" // [3] << "Cols" // [4] << "Column Labels"; // [5] break; } // Record minimum sizes in QVector<RepGen::ColDat>& colDatVec const int colCnt = columnLabelStrList.size(); colDatVec.resize (colCnt); for (int col = 0; col < colCnt; ++col) { const QString colLab (columnLabelStrList .value (col)); const bool alignRgt = ( (colLab == "Value") || (colLab == "Rows") || (colLab == "Cols") ); colDatVec [col] .setMinimumWidth (colLab); colDatVec [col] .setAlignRight (alignRgt); } if (measureOnly) return; //====================>> // *************************** // *** Write List Header *** // *************************** const QString line1 (RepGen::textTableLine (colDatVec, '+', '-')); const QString line2 (RepGen::textTableLine (colDatVec, columnLabelStrList)); const QString line3 (RepGen::textTableLine (colDatVec, '|', '=')); os << qPrintable (line1) << "\n" << qPrintable (line2) << "\n" << qPrintable (line3) << endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RepGenSlotText::writeSlotListRow (bool measureOnly, QVector<RepGen::ColDat>& colDatVec, SlotListType slotListType, cwofstream& os) const { static const char (*mname) ("RepGenSlotText::writeScalarSlotListRow"); if (_slot == NULL) return; //---------------------->> QStringList rowCellStrList; switch (slotListType) { case SlotList_Scalar: rowCellStrList << slotTypStrTerse() // [0] << slotNameStr() // [1] << slotValStr() // [2] << slotUnitsStr (false); // [3], no brackets break; case SlotList_Series: rowCellStrList << slotTypStrTerse() // [0] << slotNameStr() // [1] << slotUnitsStr (false) // [2], no brackets << slotRowsStr() // [3] << slotColsStr() // [4] << seriesStepStr() // [5] << seriesStartStr() // [6] << seriesEndStr(); // [7] break; case SlotList_Other: rowCellStrList << slotTypStrTerse() // [0] << slotNameStr() // [1] << slotRowsStr() // [3] << slotColsStr() // [4] << slotLabelsStr(); // [5] break; } // Record minimum sizes in QVector<RepGen::ColDat>& colDatVec const int colCnt = rowCellStrList.size(); colDatVec.resize (colCnt); if (measureOnly) { for (int col = 0; col < colCnt; ++col) { const QString colLab (rowCellStrList .value (col)); colDatVec [col] .setMinimumWidth (colLab); } return; // measure only //====>> } // ************************ // *** Write Slot Row *** // ************************ const QString line1 (RepGen::textTableLine (colDatVec, rowCellStrList)); os << qPrintable (line1) << endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RepGenSlotText::writeSlotDetailTitleSection (cwofstream& os) { if (_slot == NULL) return; //---------------------->> SimObj* obj (_slot->getSimObj()); // may be NULL // *************************** // *** Slot Detail Title *** // *************************** const QString objName (obj ? obj->getCompleteName() : "Object?"); const QString objTyp (obj ? obj->getLongTypeName(true) : "Type?"); const QString slotName (slotNameStr()); const QString slotTyp (slotTypStr (true)); // verbose const int maxNameLen = std::max (objName.length(), slotName.length()); static const QString objFmt ("Object: %1 / %2"); static const QString slotFmt (" Slot: %1 / %2"); const QString oLine = objFmt .arg (objName, -maxNameLen) .arg (objTyp); const QString sLine = slotFmt .arg (slotName, -maxNameLen) .arg (slotTyp); const QStringList titleLines = (QStringList() << oLine << sLine); const QString titleBox = RepGen::textBox (titleLines); os << qPrintable (titleBox) << endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RepGenSlotText::writeSlotDataTable (cwofstream& os) { if (_slot == NULL) return; //---------------------->> // ****************************** // *** Row Count Assessment *** // ****************************** const int dataRowCnt = SlotGUIUtils::getNumSlotRows (_slot); const bool truncateRows = (dataRowCnt > MAX_SLOT_DATA_ROWS); if (truncateRows) { static const QString truncMsgFmt ( "The number of rows in this slot (%1) exceeds the maximum \n" "number of slot rows for this report (%2). Only the first \n" "and last several rows are shown." ); const QString truncMsg = truncMsgFmt .arg (dataRowCnt) .arg (MAX_SLOT_DATA_ROWS); os << qPrintable (truncMsg) << endl; } // *************************************************** // *** (1) Measure Slot Data Table Column Widths *** // *************************************************** static const int EXCERPT_ROW_CNT (4); QVector<RepGen::ColDat> colDatVec; // Measure column headers writeSlotDetailHeader (true, colDatVec, os); // MEASURE ONLY // Measure data rows for (int rowInx = 0; rowInx < dataRowCnt; ++rowInx) { writeSlotDetailRow (true, colDatVec, rowInx, os); // MEASURE ONLY if (truncateRows) { if (rowInx == EXCERPT_ROW_CNT) { // Measure ellipsis (truncation gap) row writeSlotDetailRow (true, colDatVec, (-1), os); // MEASURE ONLY // Skip ahead rowInx = std::max (EXCERPT_ROW_CNT, dataRowCnt-EXCERPT_ROW_CNT-1); } } } // ******************************************** // *** (2) Write Pre-Table Notes (if any) *** // ******************************************** QString colMapEntityName (""); const bool colMapEntityDef = SlotGUIUtils::getColMapEntityName (_slot, colMapEntityName); if (colMapEntityDef && !colMapEntityName.isEmpty()) { // Write Column Map Entity description static const QString colMapEntFmt ( "Numeric column header value entity: %1\n"); QString colMapEntStr = colMapEntFmt .arg (colMapEntityName); os << qPrintable (colMapEntStr) << endl; } // *********************************** // *** (3) Write Slot Data Table *** // *********************************** // Write column headers writeSlotDetailHeader (false, colDatVec, os); // Not "measure only" for (int rowInx = 0; rowInx < dataRowCnt; ++rowInx) { writeSlotDetailRow (false, colDatVec, rowInx, os); // Not "measure only" if (truncateRows) { if (rowInx == EXCERPT_ROW_CNT) { // Write ellipsis (truncation gap) row writeSlotDetailRow (false, colDatVec, (-1), os); // Not "measure" // Skip ahead rowInx = std::max (EXCERPT_ROW_CNT, dataRowCnt-EXCERPT_ROW_CNT-1); } } } const QString botLine (RepGen::textTableLine (colDatVec, '+', '-')); os << qPrintable (botLine) << "\n" << endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RepGenSlotText::writeSlotDetailHeader (bool measureOnly, QVector<RepGen::ColDat>& colDatVec, cwofstream& os) const { if (_slot == NULL) return; //---------------------->> if (!measureOnly) { // Write Detail Table Top Horizontal Line const QString topLine (RepGen::textTableLine (colDatVec, '+', '-')); os << qPrintable (topLine) << endl; } // Process the Slot's Column Map (Numeric Dimension), if it has one. writeSlotDetailColMap (measureOnly, colDatVec, os); // ListSlots don't need a slot data table header if (_slot->isA (Slot::ListSlotBit)) return; //--------------------------------------->> const int dataColCnt = SlotGUIUtils::getNumCols (_slot); colDatVec.resize (dataColCnt+1); // (extra initial column for row headers) QStringList headerColNames; QStringList headerColUnits; int nonEmptyColLabCnt (0); // First column header is blank. That's for the row indicies or datetime. headerColNames << " "; headerColUnits << " "; for (int datCol = 0; datCol < dataColCnt; ++datCol) { const int tabCol = datCol+1; const QString colLab = SlotGUIUtils::getColLabel (_slot, datCol).toLocal8Bit().constData(); const ScaledUnitPtr scUnit = SlotGUIUtils::getScaledUnitPtr (_slot, datCol); const QString colUnits = QString ("[%1]") .arg (SlotGUIUtils::scaledUnitDisplayStr (scUnit)); if (measureOnly) { const int labelLen = std::max (colLab.length(), colUnits.length()); colDatVec [tabCol] .setMinimumWidth (labelLen); colDatVec [tabCol] .setAlignRight (true); } else { headerColNames << colLab; headerColUnits << colUnits; } if (!colLab.isEmpty()) { ++nonEmptyColLabCnt; } } if (!measureOnly) { const QString line1 (RepGen::textTableLine (colDatVec, headerColNames)); const QString line2 (RepGen::textTableLine (colDatVec, headerColUnits)); const QString line3 (RepGen::textTableLine (colDatVec, '|', '=')); if (nonEmptyColLabCnt > 0) { os << qPrintable (line1) << "\n"; } os << qPrintable (line2) << "\n" << qPrintable (line3) << endl; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RepGenSlotText::writeSlotDetailColMap (bool measureOnly, QVector<RepGen::ColDat>& colDatVec, cwofstream& os) const { if (_slot == NULL) return; //---------------------->> // Only TableSlots (incl. subclasses) support Column Maps (NumericDimension) if (!_slot->isA (Slot::TableSlotBit)) return; //----------------------------------------->> QStringList colMapUsrValStrs; QString colMapUnitsStr (""); const bool colMapDataFound = SlotGUIUtils::getColMapUsrValues (_slot, colMapUsrValStrs, colMapUnitsStr); if (!colMapDataFound) return; //------------------------->> if (!colMapUnitsStr.startsWith (QChar ('['))) colMapUnitsStr = QString ("[%1]") .arg (colMapUnitsStr); const int colMapValCnt = colMapUsrValStrs.size(); if (colDatVec.size() <= colMapValCnt) { colDatVec.resize (colMapValCnt+1); } QStringList colMapValStrs; QStringList colMapUnitStrs; const int colMapUnitsStrLen (colMapUnitsStr.length()); // First column header is blank. That's for the row indicies or datetime. colMapValStrs << " "; colMapUnitStrs << " "; for (int colMapCol = 0; colMapCol < colMapValCnt; ++colMapCol) { const int tabCol = colMapCol+1; const QString colLab = colMapUsrValStrs .value (colMapCol); if (measureOnly) { const int labelLen = std::max (colLab.length(), colMapUnitsStrLen); colDatVec [tabCol] .setMinimumWidth (labelLen); colDatVec [tabCol] .setAlignRight (true); } else { colMapValStrs << colLab; colMapUnitStrs << colMapUnitsStr; } } if (!measureOnly) { const QString line1 (RepGen::textTableLine (colDatVec, colMapValStrs)); const QString line2 (RepGen::textTableLine (colDatVec, colMapUnitStrs)); const QString line3 (RepGen::textTableLine (colDatVec, '|', '-')); os << qPrintable (line1) << "\n" << qPrintable (line2) << "\n" << qPrintable (line3) << endl; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RepGenSlotText::writeSlotDetailRow (bool measureOnly, QVector<RepGen::ColDat>& colDatVec, int rowInx, cwofstream& os) const { static const QString ellipsis ("..."); //-------------------------------------------------------- // NOTE: if (row < 0), show a divider row (with ellipsis). //-------------------------------------------------------- if (_slot == NULL) return; //---------------------->> const bool isListSlot (_slot->isA (Slot::ListSlotBit)); QStringList rowCellStrList; // *********************************** // *** Row Header (First Column) *** // *********************************** const bool supportsTextRowLabel (_slot->isA (Slot::TableSlotBit) || _slot->isA (Slot::SeriesSlotBit) ); QString rowLab (" "); // tentative bool alignRight (!isListSlot || (rowInx == 0)); // tentative if (rowInx < 0) { rowLab = ellipsis; } else // (rowInx >= 0) { rowLab = QString::number (rowInx); // tentative if (supportsTextRowLabel) { const QString rowLabStr = SlotGUIUtils::getRowLabel (_slot, rowInx); if (!rowLabStr.isEmpty()) { rowLab = rowLabStr; alignRight = false; } } } rowCellStrList << rowLab; if (measureOnly && (rowInx == 0)) { if (colDatVec.size() == 0) { colDatVec.resize (1); } colDatVec [0] .setAlignRight (alignRight); } // ************************************************ // *** Special Column for ListSlots: Item Icon *** // ************************************************ if (isListSlot) { QString lslotItemTypStr (ellipsis); // tentative if (rowInx >= 0) { const ListSlotBase* lslot = dynamic_cast<const ListSlotBase*> (_slot); if (lslot) { IconHandle lsIcon ((SimObj*) NULL, false); const bool iconOk = lslot->getItemIcon (rowInx, lsIcon); if (iconOk) { QString descStr (lsIcon.iconDescStr()); // Remove "Object" from long-winded object type descriptions, // but not from "Data Object". if ((descStr.length() > 12) && (descStr.contains ("Object"))) { descStr.remove ("Object"); } lslotItemTypStr = descStr.simplified(); } } } rowCellStrList << lslotItemTypStr; } // *************************** // *** Slot Data Columns *** // *************************** const int dataColCnt = SlotGUIUtils::getNumCols (_slot); for (int colInx = 0; colInx < dataColCnt; ++colInx) { QString valStr (ellipsis); // tentative if (rowInx >= 0) { valStr = SlotGUIUtils::getValueUsrStr (_slot, rowInx, colInx, false, //-- for edit false); //-- alt units } rowCellStrList << valStr; } // ******************************** // *** Process rowCellStrList *** // ******************************** if (measureOnly) { // Record minimum sizes in QVector<RepGen::ColDat>& colDatVec const int colCnt = rowCellStrList.size(); if (colDatVec.size() < colCnt) { colDatVec.resize (colCnt); } for (int col = 0; col < colCnt; ++col) { colDatVec [col] .setMinimumWidth (rowCellStrList .value (col)); } } else // (not measureOnly) { // ***************************** // *** Write Slot Data Row *** // ***************************** const QString line1 (RepGen::textTableLine (colDatVec, rowCellStrList)); os << qPrintable (line1) << endl; } } //--- (end RepGenSlotText.cpp) ---