// $Id: DefaultSupplyNameSpec.cpp,v 1.7 2010/10/12 18:57:28 philw Exp $ // // Data definition of a Default Supply Name Specification. This consists // primarily of a sequence of "Parts" representing names or properties of // the Upstream and Downstream Accounts. // // This class contains: // (1) Data and methods to configure the Default Supply Name Specification // (2) Serialization and "User Settings"-based Persitence. // (3) A method to generate a Default Supply Name for a given Supply: // -- QString computeDefaultNameForSupply (const Supply*) const; // // class DefaultSupplyNameSpec // struct DefaultSupplyNameSpec::Part // //-- #ifndef DefaultSupplyNameSpecINCLUDED #include "DefaultSupplyNameSpec.hpp" #endif #ifndef SupplyINCLUDED #include "Supply.hpp" #endif #ifndef AccountINCLUDED #include "Account.hpp" #endif #ifndef SimObjINCLUDED #include "SimObj.hpp" #endif #ifndef SupplyDemandTypeINCLUDED #include "SupplyDemandType.hpp" #endif #ifndef RwQtSettingsINCLUDED #include "RwQtSettings.hpp" #endif #include #include // static fields QString DefaultSupplyNameSpec::_lastSampSupplyActualName (""); static const QString SpaceStr (" "); static const QString SpaceTagStr (""); static const QString InOutTag ("#InOut"); static const QString DivRetTag ("#DivRet"); static const QString TranTag ("#Tran"); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static QString DefaultSupplyNameSpec::partTypeUserString ( DefaultSupplyNameSpec::PartType typ) { // ******************************************* // *** Part Type Strings: User Interface *** // ******************************************* switch (typ) { case PartType_UND: return (""); case PartType_String: return ("Entered Text ..."); case PartType_UpObjName: return ("Upstream Object Name"); case PartType_UpAcctName: return ("Upstream Account Name"); case PartType_DownObjName: return ("Downstream Object Name"); case PartType_DownAcctName: return ("Downstream Account Name"); case PartType_UpWaterType: return ("Upstream Water Type"); case PartType_UpWaterOwner: return ("Upstream Water Owner"); case PartType_DownWaterType: return ("Downstream Water Type"); case PartType_DownWaterOwner: return ("Downstream Water Owner"); case PartType_SplyTypeCode: return ("Supply Type"); case PartType_COUNT: return (""); } return (""); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static QString DefaultSupplyNameSpec::partTypeTerseString ( DefaultSupplyNameSpec::PartType typ) { // *********************************************************** // *** Part Type Strings: Terse (e.g. for Serialization) *** // *********************************************************** switch (typ) { case PartType_UND: return ("UND"); case PartType_String: return ("StringRec"); case PartType_UpObjName: return ("UpObjName"); case PartType_UpAcctName: return ("UpAcctName"); case PartType_DownObjName: return ("DownObjName"); case PartType_DownAcctName: return ("DownAcctName"); case PartType_UpWaterType: return ("UpWaterType"); case PartType_UpWaterOwner: return ("UpWaterOwner"); case PartType_DownWaterType: return ("DownWaterType"); case PartType_DownWaterOwner: return ("DownWaterOwner"); case PartType_SplyTypeCode: return ("SplyTypeCode"); } static const QString errStr ("PartType-%1"); return (errStr .arg ((int) typ)); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static DefaultSupplyNameSpec::PartType DefaultSupplyNameSpec::partTypeFromUserString (const QString& rawStr) { const QString str = rawStr.trimmed(); for (int inx = 0; inx < (int) PartType_COUNT; ++inx) { const PartType typ = (PartType) inx; if (str == partTypeUserString (typ)) return (typ); } return PartType_UND; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static bool DefaultSupplyNameSpec::getPartTypeFromTerseString ( const QString& rawStr, PartType& retPartType) { const QString str = rawStr.trimmed(); for (int inx = 0; inx < (int) PartType_COUNT; ++inx) { const PartType typ = (PartType) inx; if (str == partTypeTerseString (typ)) { retPartType = typ; return (true); // terse part type string found } } retPartType = PartType_UND; return (false); // terse part type string NOT found } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool DefaultSupplyNameSpec::Part::operator== (const DefaultSupplyNameSpec::Part& rhs) const { return ( (_partType == rhs._partType) && (_stringVal == rhs._stringVal) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QString DefaultSupplyNameSpec::Part::str (const Supply* sply, bool removeSpaces, bool camelCaseToo) const { if (_partType == PartType_String) { // Special Handling for String Parts: // (1) Does not depend on the given Supply // (2) Never Camel Cased // Encode Internal Spaces QString stringValRet = _stringVal.simplified(); stringValRet.replace (SpaceStr, SpaceTagStr); // " " --> "" // Prepend '#' to prevent CamelCasing of first character, when // spaces are being removed from the overall default name. static const QChar NoCamelCaseChar ('#'); stringValRet.prepend (NoCamelCaseChar); return (stringValRet); //------------------>> } if (sply == NULL) return (""); //-------------------------->> QString str1 (""); const Account* upAcct = sply->getSupplyAccount(); const SimObj* upObj = sply->getSupplyObj(); const Account* dnAcct = sply->getDemandAccount(); const SimObj* dnObj = sply->getDemandObj(); const SupplyDemandType_t typ = sply->getType(); switch (_partType) { case PartType_UpObjName: if (upObj) str1 = upObj->getName(); break; case PartType_UpAcctName: if (upAcct) str1 = upAcct->getName(); break; case PartType_DownObjName: if (dnObj) str1 = dnObj->getName(); break; case PartType_DownAcctName: if (dnAcct) str1 = dnAcct->getName(); break; case PartType_UpWaterType: if (upAcct) str1 = upAcct->getWaterType(); break; case PartType_UpWaterOwner: if (upAcct) str1 = upAcct->getWaterOwner(); break; case PartType_DownWaterType: if (dnAcct) str1 = dnAcct->getWaterType(); break; case PartType_DownWaterOwner: if (dnAcct) str1 = dnAcct->getWaterOwner(); break; case PartType_SplyTypeCode: { // Don't CamelCase; Return Special Code. // (Note: Can't use a switch because of CRAZY sofware // technology of the SupplyDemandType_t class). if (typ == SupplyDemandType_t::ST_InOut) return (InOutTag); if (typ == SupplyDemandType_t::DT_InOut) return (InOutTag); if (typ == SupplyDemandType_t::ST_DivRet) return (DivRetTag); if (typ == SupplyDemandType_t::DT_DivRet) return (DivRetTag); if (typ == SupplyDemandType_t::ST_Transfers) return (TranTag); if (typ == SupplyDemandType_t::DT_Transfers) return (TranTag); break; } } QString retStr = str1; // tentative if (removeSpaces) { if (camelCaseToo) { retStr = camelCase (str1); } else { static const QChar SP (' '); retStr.remove (SP); } } return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- DefaultSupplyNameSpec::DefaultSupplyNameSpec() : _partList(), _supplyTypeStr_InpOut (""), _supplyTypeStr_DivRet (""), _supplyTypeStr_Tran (""), _removeSpacesEna (false), _remSpacesInPartsOnly (false), _remSpacesCamelCase (false), _omitRepeatObjNames (false), _sampSupplyActualName (_lastSampSupplyActualName), _temporaryChangeCnt (0) { } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static const DefaultSupplyNameSpec& DefaultSupplyNameSpec::factoryValueRef() { // Returns a const reference to a static DefaultSupplyNameSpec // instance having the "Factory" default settings. static DefaultSupplyNameSpec factVal; static bool staticInstanceDefined (false); if (!staticInstanceDefined) { staticInstanceDefined = true; const QString SpacedToText = SpaceTagStr + " to " + SpaceTagStr; QList partList; partList << Part (PartType_UpObjName) << Part (PartType_UpAcctName) << Part (PartType_String, SpacedToText) << Part (PartType_DownObjName) << Part (PartType_DownAcctName) << Part (PartType_SplyTypeCode); factVal.setPartList (partList); factVal.setSupplyTypeStr_InpOut (""); factVal.setSupplyTypeStr_DivRet ("Div"); factVal.setSupplyTypeStr_Tran ("Tran"); factVal.setRemoveSpacesEna (false); factVal.setRemSpacesInPartsOnly (false); factVal.setRemSpacesCamelCase (false); factVal.setOmitRepeatObjNames (true); } // Non-Specification Field: This field doesn't effect the computation // of a Supply's default name. Return the recent value of this field // with the factory value. // factVal.setSampSupplyActualName (_lastSampSupplyActualName); factVal.clearTemporaryChangeCnt(); return (factVal); } void DefaultSupplyNameSpec::setFactoryValue() { _partList.clear(); *this = factoryValueRef(); } bool DefaultSupplyNameSpec::isFactoryValue() const { const DefaultSupplyNameSpec& factoryVal = factoryValueRef(); const bool isFactoryVal = equals (factoryVal, true); // ignoreNonSpecFields return (isFactoryVal); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void DefaultSupplyNameSpec::setPartList ( const QList& newPartList) { if (_partList != newPartList) { _partList.clear(); _partList = newPartList; ++_temporaryChangeCnt; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void DefaultSupplyNameSpec::setSupplyTypeStr_InpOut (const QString& str) { const QString newStr = str.trimmed(); if (newStr != _supplyTypeStr_InpOut) { _supplyTypeStr_InpOut = newStr; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setSupplyTypeStr_DivRet (const QString& str) { const QString newStr = str.trimmed(); if (newStr != _supplyTypeStr_DivRet) { _supplyTypeStr_DivRet = newStr; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setSupplyTypeStr_Tran (const QString& str) { const QString newStr = str.trimmed(); if (newStr != _supplyTypeStr_Tran) { _supplyTypeStr_Tran = newStr; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setRemoveSpacesEna (bool newOn) { if (newOn != _removeSpacesEna) { _removeSpacesEna = newOn; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setRemSpacesInPartsOnly (bool newOn) { if (newOn != _remSpacesInPartsOnly) { _remSpacesInPartsOnly = newOn; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setRemSpacesCamelCase (bool newOn) { if (newOn != _remSpacesCamelCase) { _remSpacesCamelCase = newOn; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setOmitRepeatObjNames (bool newOn) { if (newOn != _omitRepeatObjNames) { _omitRepeatObjNames = newOn; ++_temporaryChangeCnt; } } void DefaultSupplyNameSpec::setSampSupplyActualName (const QString& str) { const QString newStr = str.trimmed(); if (newStr != _sampSupplyActualName) { _sampSupplyActualName = newStr; ++_temporaryChangeCnt; } _lastSampSupplyActualName = newStr; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool DefaultSupplyNameSpec::equals (const DefaultSupplyNameSpec& rhs, bool ignoreNonSpecFields /*=false*/) const { // If comparison is of an instance with ITSELF, return true. if (this == &rhs) return (true); //---------------------------->> if (_partList.count() != rhs._partList.count()) return (false); if (_partList != rhs._partList) return (false); if (_supplyTypeStr_InpOut != rhs._supplyTypeStr_InpOut) return (false); if (_supplyTypeStr_DivRet != rhs._supplyTypeStr_DivRet) return (false); if (_supplyTypeStr_Tran != rhs._supplyTypeStr_Tran) return (false); if (_removeSpacesEna != rhs._removeSpacesEna) return (false); if (_remSpacesInPartsOnly != rhs._remSpacesInPartsOnly) return (false); if (_remSpacesCamelCase != rhs._remSpacesCamelCase) return (false); if (_omitRepeatObjNames != rhs._omitRepeatObjNames) return (false); //--------------------------------------------------------------------->> if (!ignoreNonSpecFields) { // Non-Specification Fields: These fields don't effect // the computation of a Supply's default name. if (_sampSupplyActualName != rhs._sampSupplyActualName) return (false); //------------------------------------------------------------------->> } //-- Fields ALWAYS ignored for purposes of equality comparison: //-- int _temporaryChangeCnt; return (true); // no differences found; equal. } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool DefaultSupplyNameSpec::operator== (const DefaultSupplyNameSpec& rhs) const { const bool equal = equals (rhs, false); // DON'T ignore Non Spec Fields return (equal); } bool DefaultSupplyNameSpec::operator!= (const DefaultSupplyNameSpec& rhs) const { const bool equal = equals (rhs, false); // DON'T ignore Non Spec Fields return (!equal); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static QString DefaultSupplyNameSpec::camelCase (const QString& inStr) { QString camelStr (""); bool nextCharUpper = true; int charsDropped (0); const int inStrSize (inStr.size()); for (int i = 0; i < inStrSize; ++i) { const QChar ch (inStr [i]); if (ch.isSpace()) { ++charsDropped; nextCharUpper = true; } else if (ch.isLetter()) { camelStr += nextCharUpper ? ch.toUpper() : ch; nextCharUpper = false; } else { camelStr += ch; nextCharUpper = false; } } return (camelStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // *********************** // *** Serialization *** // *********************** static const QString SERIAL_SEP ("##"); // Serial record seperator // Serialization Token Keys -- Must not contain any spaces. // static const QString STS_InpOut ("STS_InpOut"); // _supplyTypeStr_InpOut static const QString STS_DivRet ("STS_DivRet"); // _supplyTypeStr_DivRet static const QString STS_Tran ("STS_Tran"); // _supplyTypeStr_Tran static const QString RSP_Ena ("RSP_Ena"); // _removeSpacesEna static const QString RSP_POnly ("RSP_POnly"); // _remSpacesInPartsOnly static const QString RSP_Camel ("RSP_Camel"); // _remSpacesCamelCase static const QString OMT_RepObj ("OMT_RepObj"); // _omitRepeatObjNames static const QString SMP_SName ("SMP_SName"); // _sampSupplyActualName //-- SERIALIZATION EXAMPLE of the "factory" setting, all one line, //-- without quotes. Note that "##" is the record delimitor. //-- 192 characters: //-- //-- "UpObjName##UpAcctName##StringRec to ##DownObjName## //-- DownAcctName##SplyTypeCode##STS_InpOut##STS_DivRet Div## //-- STS_Tran Tran##RSP_Ena 0##RSP_POnly 0##RSP_Camel 0## //-- OMT_RepObj 1##SMP_SName" QString DefaultSupplyNameSpec::serialize() const { QStringList recordList; static const QChar SP (' '); const int partCnt = _partList.count(); for (int partInx = 0; partInx < partCnt; ++partInx) { const Part part = _partList [partInx]; QString recStr = partTypeTerseString (part._partType); const bool usesString = (part._partType == PartType_String); if (usesString && !part._stringVal.isEmpty()) { recStr += SP; recStr += part._stringVal; } recordList << recStr; } recordList << (STS_InpOut + SP + _supplyTypeStr_InpOut) .trimmed(); recordList << (STS_DivRet + SP + _supplyTypeStr_DivRet) .trimmed(); recordList << (STS_Tran + SP + _supplyTypeStr_Tran) .trimmed(); recordList << (RSP_Ena + SP + QString::number (_removeSpacesEna)); recordList << (RSP_POnly + SP + QString::number (_remSpacesInPartsOnly)); recordList << (RSP_Camel + SP + QString::number (_remSpacesCamelCase)); recordList << (OMT_RepObj + SP + QString::number (_omitRepeatObjNames)); recordList << (SMP_SName + SP + _sampSupplyActualName) .trimmed(); const QString retStr = recordList .join (SERIAL_SEP); return (retStr); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- okstat DefaultSupplyNameSpec::loadSerial (const QString& serialStr) { static const char* mname ("DefaultSupplyNameSpec::loadSerial"); const QStringList recordList = serialStr .split (SERIAL_SEP); const int recordCnt = recordList.count(); QStringList errorList; QList partList; static const QChar SP (' '); for (int recInx = 0; recInx < recordCnt; ++recInx) { QString recKey (""); QString recVal (""); const QString recStr = recordList [recInx] .trimmed(); const int firstSpInx = recStr.indexOf (SP); if (firstSpInx < 0) { // No space found. The record key is the full record. recKey = recStr; } else { // Space found. First word is the record key. The rest is the value. recKey = recStr.left (firstSpInx); recVal = recStr.mid (firstSpInx + 1, -1); // (to end) } if (recKey.isEmpty()) continue; //----------------------------- const int recInt = recVal.toInt(); // 0 if conversion fails const bool recBool (recInt != 0); PartType partType = PartType_UND; const bool isNamePart = getPartTypeFromTerseString (recKey, partType); // set if (isNamePart) { partList << Part (partType, recVal); } else if (recKey == STS_InpOut) _supplyTypeStr_InpOut = recVal; else if (recKey == STS_DivRet) _supplyTypeStr_DivRet = recVal; else if (recKey == STS_Tran) _supplyTypeStr_Tran = recVal; else if (recKey == RSP_Ena) _removeSpacesEna = recBool; else if (recKey == RSP_POnly) _remSpacesInPartsOnly = recBool; else if (recKey == RSP_Camel) _remSpacesCamelCase = recBool; else if (recKey == OMT_RepObj) _omitRepeatObjNames = recBool; else if (recKey == SMP_SName) _sampSupplyActualName = recVal; else // ERROR: record key not recognized. { errorList << QString ("Record [%1] Not Recognized: '%2'") .arg (recInx) .arg (recStr); } } setPartList (partList); const int errorCnt = errorList.count(); if (errorCnt > 0) { return okstat (errorList.join ("\n")); } return okstat (true); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ****************************************** // *** Persistence via Qt User Settings *** // ****************************************** // QSettings Keys static const char* DFLT_SPLY_NAME_SPEC ("/DefaultSupplyNameSpec"); static const char* SPLY_NAME_REC ("/Rec"); void DefaultSupplyNameSpec::saveToUserSettings() const { static const char* mname ("DefaultSupplyNameSpec::saveToUserSettings"); const QString specSerial = serialize(); // std::cout << mname // << " '" << qPrintable (specSerial) << "'" // << std::endl; // ******************************************* // *** Write specSerial to User Settings *** // ******************************************* QSettings sett; RwQtSettings::initSettings (sett); sett.beginGroup (DFLT_SPLY_NAME_SPEC); sett .setValue (SPLY_NAME_REC, specSerial); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- okstat DefaultSupplyNameSpec::loadFromUserSettings() { static const char* mname ("DefaultSupplyNameSpec::loadFromUserSettings"); DefaultSupplyNameSpec spec; okstat loadOk (true); // tentative // ******************************************** // *** Read specSerial from User Settings *** // ******************************************** QSettings sett; RwQtSettings::initSettings (sett); sett.beginGroup (DFLT_SPLY_NAME_SPEC); const QString specSerial = sett.value (SPLY_NAME_REC) .toString() .trimmed(); // std::cout << mname // << " '" << qPrintable (specSerial) << "'" // << std::endl; if (specSerial.isEmpty()) { loadOk = okstat ("Spec record Empty or Not Found."); } else { loadOk = spec.loadSerial (specSerial); } // Load the spec without regard to any detected error. // The user may choose to take a look at it, and fix it. *this = spec; return loadOk; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ************************************************** // *** Generate Default Name for a given Supply *** // ************************************************** QString DefaultSupplyNameSpec::computeDefaultNameForSupply ( const Supply* sply) const { static const char* mname ("DefaultSupplyNameSpec::computeDefaultNameForSupply"); // Note: Space removal and CamelCasing does not effect user-entered // text parts -- either actual PartType_String parts or user-entered // text for the various Supply Types (PartType_SplyTypeCode). So all // space removal and CamelCasing -- both within each part or to the // overall generated name -- occurs BEFORE symbol substitution for // non-removal space tags and device type text tags. QStringList partStringList; QSet objPartStrings; const int partCnt = _partList.count(); for (int partInx = 0; partInx < partCnt; ++partInx) { // *********************************************************** // *** Get Part String, with respect to the given Supply *** // *********************************************************** const Part part = _partList [partInx]; QString partStr = part.str (sply, _removeSpacesEna, _remSpacesCamelCase); if (partStr.isEmpty()) continue; //------------------------------ // ********************************************************** // *** "Omit repeated Object Name in Transfer Supplies" *** // ********************************************************** const bool partIsObj = (part._partType == PartType_UpObjName) || (part._partType == PartType_DownObjName) ; const bool thisObjPartStrAlreadyUsed = partIsObj && objPartStrings.contains (partStr); if (partIsObj) { objPartStrings .insert (partStr); } if (_omitRepeatObjNames && thisObjPartStrAlreadyUsed) { // Skip this redundant Object Name Part (e.g. for Transfer Supply) continue; //-------------- } partStringList .append (partStr); } // ********************************** // *** Join Computed Name Parts *** // ********************************** QString fullStr = partStringList .join (SpaceStr); // " " if (_removeSpacesEna && !_remSpacesInPartsOnly) { if (_remSpacesCamelCase) { fullStr = camelCase (fullStr); } else { static const QChar SP (' '); fullStr.remove (SP); } } // ***************************************** // *** Translate User Supply Type Text *** // ***************************************** fullStr.replace (InOutTag, _supplyTypeStr_InpOut, Qt::CaseInsensitive); fullStr.replace (DivRetTag, _supplyTypeStr_DivRet, Qt::CaseInsensitive); fullStr.replace (TranTag, _supplyTypeStr_Tran, Qt::CaseInsensitive); // Remove Remaining "#" Characters static const QChar CmdTagEsc ('#'); fullStr.remove (CmdTagEsc); // *********************************** // *** Translate Hard Space Tags *** // *********************************** fullStr.replace (SpaceTagStr, SpaceStr, Qt::CaseInsensitive); // Remove Remaining "<>" Characters fullStr.remove (QChar ('<')); fullStr.remove (QChar ('>')); // Remove leading and trailing spaces, and condense internal multiple // continguous spaces into a single space. QString retStr = fullStr.simplified(); if (retStr.isEmpty()) { // If the generated default supply name is empty, return just "Supply". return ("Supply"); } return (retStr); } //--- (end DefaultSupplyNameSpec.cpp) ---