// $Id: RepGenUtils.cpp,v 1.22 2011/08/02 22:04:23 nwilson Exp $ // RiverWare Model Report Generation -- Utilities. #ifndef RepGenUtilsINCLUDED #include "RepGenUtils.hpp" #endif #ifndef RwModelReportINCLUDED #include "RwModelReport.hpp" #endif #ifndef SimObjINCLUDED #include "SimObj.hpp" #endif #ifndef SlotINCLUDED #include "Slot.hpp" #endif #ifndef cwfstreamINCLUDED #include "cwfstream.hpp" #endif #ifndef RwQPixmap16INCLUDED #include "RwQPixmap16.hpp" #endif #ifndef RwQtIconsINCLUDED #include "RwQtIcons.hpp" #endif #include "rwStr.hpp" #include #include //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- static const QString nbspQstr (" "); // ************************************* // *** Public Configuration Values *** // ************************************* const char* RepGen_SectionAnchor_ObjMethods ("SectionObjMethods"); const char* RepGen_SectionAnchor_ScalarSlotList ("SectionScalarSlots"); const char* RepGen_SectionAnchor_OtherSlotList ("SectionOtherSlots"); const char* RepGen_SectionAnchor_SeriesSlotList ("SectionSeriesSlots"); const char* RepGen_SectionAnchor_SlotDetails ("SectionSlotDetails"); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ******************************************* // *** RiverWare Specific HTML Utilities *** // ******************************************* // Camal Case, removing non-alphanumeric characters QString RepGen::reduceNameString (const QString& rawName) { QString camelName (""); bool nextCharUpper = true; int charsDropped (0); const int rawNameSize (rawName.size()); for (int i = 0; i < rawNameSize; ++i) { const QChar ch (rawName [i]); if (ch.isLetter() || ch.isDigit()) { camelName += nextCharUpper ? ch.toUpper() : ch.toLower(); nextCharUpper = false; } else { nextCharUpper = true; ++charsDropped; } } if (charsDropped == 0) { return (rawName); } return (camelName); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString RepGen::html_link (const QString& valStr, const QString& linkStr) { const QString valStr2 (valStr.isEmpty() ? nbspQstr : valStr); static const QString fmt ("%2"); const QString outStr = fmt .arg (linkStr) .arg (valStr2); return (outStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString RepGen::html_icon (const QString& imgPath, const QSize& imgSize, const int border, const QString& altText, const QString& alignText) // ""=none { static const QString fmt ( ""); QString alignAttr (""); if (!alignText.isEmpty()) alignAttr = QString (" align=\"%1\"") .arg (alignText); const QString outStr = fmt .arg (imgPath) .arg (imgSize.width()) .arg (imgSize.height()) .arg (border) .arg (altText) .arg (alignAttr); return (outStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString RepGen::htmlTableBox (int indentLev, const QString& htmlContent, int margin /*=10*/) { const QString indentStr (indentLev, QChar (' ')); // Indent String const QString indentStr3 (indentLev+3, QChar (' ')); // Indent String QString indentContent (" "); if (!htmlContent.isEmpty()) { indentContent = indentStr3 + htmlContent; indentContent.replace (QString ("\n"), (QString ("\n") + indentStr3)); } static const QString formatTemplate ("INDENT\n" "INDENT \n" "INDENT \n" "INDENT \n" "INDENT
\n%2\n" "INDENT
"); QString formatStr (formatTemplate); formatStr.replace (QString ("INDENT"), indentStr); const QString htmlStr = formatStr .arg (margin) .arg (indentContent); return (htmlStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Note [9-9-2009]: More parameters will be added in the course // of the development for HTML support for GreenBook Reports. QString RepGen::htmlTableRow (char rowTyp, // 'h'-head, 'd'-dat, 's'-summary const QString& firstColCssClass, const QString& otherColCssClass, const QString& noteCssClass, const QString& firstColBgColorStr, const QString& otherColBgColorStr, const QString& noteBgColorStr, const QVector& colDatVec, const QStringList& cellStrings, const QStringList* cellNotes) // may be NULL { QString retStr ("\n"); const bool isHdr = (rowTyp == 'h'); const bool isDat = (rowTyp == 'd'); const bool isSum = (rowTyp == 's'); const int colCnt = colDatVec.size(); for (int col = 0; col < colCnt; ++col) { const int colWidth = colDatVec [col] .width(); const int noteWidth = colDatVec [col] .maxFootnoteDigits(); // const int fullWidth = colWidth + (noteWidth ? noteWidth+1 : 0); const int fullWidth = colWidth + (noteWidth ? noteWidth+1 : 0); if (fullWidth <= 0) continue; //--------------------------- QString cssAttribStr (""); const QString cssClass = ((col == 0) ? firstColCssClass : otherColCssClass); if (!cssClass.isEmpty()) { cssAttribStr = QString (" class=\"%1\"") .arg (cssClass); } QString cssNoteAttribStr (""); if (!noteCssClass.isEmpty()) { cssNoteAttribStr = QString (" class=\"%1\"") .arg (noteCssClass); } QString bgColorAttribStr (""); const QString bgColor = ((col == 0) ? firstColBgColorStr : otherColBgColorStr); if (bgColor.toUpper() != "FFFFFF") // [White] { bgColorAttribStr = QString (" bgcolor=\"#%1\"") .arg (bgColor); } QString bgColorNoteAttribStr (""); if (noteBgColorStr.toUpper() != "FFFFFF") // [White] { bgColorNoteAttribStr = QString (" bgcolor=\"#%1\"") .arg (noteBgColorStr); } QString alignAttribStr (""); const bool alignRight = colDatVec [col] .alignRight(); if (alignRight) { alignAttribStr = " align=\"right\""; } QString cellStr = cellStrings.value (col).trimmed(); if (cellStr.isEmpty()) { cellStr = " "; } QString noteStr (""); QString noteStrHtml (""); if (cellNotes && (cellNotes->size() > col)) { noteStr = (*cellNotes) [col].trimmed(); noteStrHtml = noteStr.trimmed(); } if (noteStrHtml.isEmpty()) noteStrHtml = " "; QString tdElemTempl (""); int colSpan (1); // tentative if (noteWidth == 0) { tdElemTempl += " "; } else if (isHdr && noteStr.isEmpty()) { tdElemTempl += " "; colSpan = 2; } else { tdElemTempl += " "; } retStr += tdElemTempl .arg (alignAttribStr) . arg (bgColorAttribStr) .arg (cssAttribStr); retStr += cellStr; if (noteWidth > 0) { if (colSpan != 2) { QString noteCellTd = QString (" ") .arg (bgColorNoteAttribStr) .arg (cssNoteAttribStr); retStr += "\n"; retStr += noteCellTd; retStr += noteStrHtml; } } retStr += "\n"; } retStr += "\n"; return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ******************************************* // *** RiverWare Specific HTML Utilities *** // ******************************************* QString RepGen::localSimObjUrl (const SimObj* obj, bool quoted /*=true*/) { static const QString fmt1 ("#%1"); static const QString fmt2 ("\"#%1\""); QString objMunge (""); if (obj != NULL) { objMunge = reduceNameString (qPrintable(obj->getCompleteName())); } const QString objUrl = (quoted ? fmt1 : fmt2) .arg (objMunge); return (objUrl); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString RepGen::localSlotUrl (const Slot* slotPtr, bool quoted /*=true*/) { static const QString fmt1 ("#%1%2"); static const QString fmt2 ("\"#%1%2\""); QString objMunge (""); QString slotMunge (""); if (slotPtr != NULL) { SimObj* obj = slotPtr->getSimObj(); if (obj != NULL) { objMunge = reduceNameString (qPrintable(obj->getCompleteName())); } else { objMunge = "NullObj"; } slotMunge = reduceNameString (qPrintable(slotPtr->getName())); } const QString slotUrl = (quoted ? fmt1 : fmt2) .arg (objMunge) .arg (slotMunge); return (slotUrl); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ****************************** // *** IconHandle Utilities *** // ****************************** QString RepGen::imgFileStr (const IconHandle& iconHandle, RwModelReport* rep) { const QString iconTagStr (iconHandle.iconTagStr()); const QString fileName = QString ("reportImages/%1.png") .arg (iconTagStr); if (rep) { // Once per RwModelReport instance, write out this Slot Type Icon rep->createReportIconFile (fileName, iconHandle); } return (fileName); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QSize RepGen::imgSize (const IconHandle& iconHandle) { QPixmap iconPixmap = RwQPixmap16::findIconHandlePixmap (iconHandle); if (iconPixmap.isNull()) iconPixmap = RwQtIcons::findIconHandlePixmap (iconHandle); if (iconPixmap.isNull()) { return (QSize (0,0)); } const QSize retSize (iconPixmap.size()); return (retSize); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ****************************** // *** ASCII TEXT Utilities *** // ****************************** QString RepGen::textBox (const QStringList& contentLineStrs) { // compute maximum length int maxStrLen (0); const int strCnt (contentLineStrs.size()); for (int i = 0; i < strCnt; ++i) { const QString str (contentLineStrs.value (i)); maxStrLen = std::max (maxStrLen, str.length()); } const int boxWidth = maxStrLen + 10; // for: "*** str ***" const QString topBotStr = QString (boxWidth, QChar ('*')) + "\n"; QString retStr = topBotStr; for (int i2 = 0; i2 < strCnt; ++i2) { const QString str (contentLineStrs.value (i2)); const QString lineStr = QString ("*** %1 ***\n") .arg (str, -maxStrLen); // negative: align left retStr += lineStr; } retStr += topBotStr; return (retStr); } QString RepGen::textBox (const QString& contentStr) { QStringList contentLineStrs (contentStr); const QString resultStr = textBox (contentLineStrs); return (resultStr); } QString RepGen::textTableLine (const QVector& colDatVec, char vert, char horz) { // Generate a horizontal table divider string, filling cell characters // with the horizontal fill character, and using the vertical character // for column dividers. QString retStr (""); const int colCnt = colDatVec.size(); for (int col = 0; col < colCnt; ++col) { const int colWidth = colDatVec [col] .width(); const int noteWidth = colDatVec [col] .maxFootnoteDigits(); const int fullWidth = colWidth + (noteWidth ? noteWidth+1 : 0); if (fullWidth > 0) { retStr += QChar (vert); retStr += QString (fullWidth+2, QChar (horz)); } } if (!retStr.isEmpty()) { retStr += QChar (vert); } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString RepGen::textTableLine (const QVector& colDatVec, const QStringList& cellStrings, const QStringList* cellNotes /*=NULL*/) { QString retStr (""); const int colCnt = colDatVec.size(); for (int col = 0; col < colCnt; ++col) { const int colWidth = colDatVec [col] .width(); const int noteWidth = colDatVec [col] .maxFootnoteDigits(); const int fullWidth = colWidth + (noteWidth ? noteWidth+1 : 0); if (fullWidth <= 0) continue; //--------------------------- const bool alignRight = colDatVec [col] .alignRight(); const QString cellStr = cellStrings.value (col); QString noteStr (""); if (cellNotes && (cellNotes->size() > col)) noteStr = (*cellNotes) [col]; // Special QString::arg (const QString& str, int fieldWidth=0) behavior: // The fieldWidth value specifies the minimum amount of space that // str is padded to and filled with the character fillChar. A POSITIVE // value will produce RIGHT-ALIGNED text, whereas a NEGATIVE value will // produce LEFT-ALIGNED text. // const int alignColWidth = (alignRight ? colWidth : (-colWidth)); retStr += QString ("| %1 ") .arg (cellStr, alignColWidth); if (noteWidth > 0) { retStr += QString ("|%1") .arg (noteStr, (-noteWidth)); } } if (!retStr.isEmpty()) { retStr += QChar ('|'); } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // *********************************************** // *** ASCII TEXT Column Configuration Class *** // *********************************************** void RepGen::ColDat::setMinimumWidth (int newMin) // [in characters] { if (_width < newMin) { _width = newMin; } } void RepGen::ColDat::setMinimumWidth (const QString& str) { if (!str.isEmpty()) { const int newMin (str.length()); if (_width < newMin) { _width = newMin; } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RepGen::ColDat::trackMaxFootnoteDigits (const QString& newFootnoteStr) { const int strLength = newFootnoteStr.length(); if (strLength > _maxFootnoteDigs) { _maxFootnoteDigs = strLength; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RepGen::ColDat::clearSummaryValues() { _sumValCntAll = 0; _sumValCntValid = 0; _userSum = 0.0; _userMin = INVALIDVALUE; _userMax = INVALIDVALUE; _userFirst = INVALIDVALUE; _userLast = INVALIDVALUE; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RepGen::ColDat::processValueForSummary (double userVal) { ++_sumValCntAll; if (!isValid (userVal)) return; //--------------------------->> ++_sumValCntValid; _userSum += userVal; _userLast = userVal; if (_sumValCntValid == 1) { _userMin = userVal; _userMax = userVal; _userFirst = userVal; } else { if (userVal < _userMin) _userMin = userVal; if (userVal > _userMax) _userMax = userVal; } } //--- (end RepGenUtils.cpp) ---