/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "TvExDbUserIO.h" #include "DbBaseDatabase.h" #include "TvExDbCommandContext.h" #include "Ge/GeExtents2d.h" #include "Ge/GeMatrix3d.h" #include "Ge/GeLineSeg2d.h" #include "StaticRxObject.h" #include "Gi/GiDrawableImpl.h" #include "Gi/GiWorldDraw.h" #include "Gi/GiViewportDraw.h" #include "Gi/GiUtils.h" #include "OdDToStr.h" #include "Gs/Gs.h" #include "Ed/EdLispEngine.h" #include "ExTrackers.h" #include "ExKWIndex.h" #include #include "RxDictionary.h" #define DBCC_PAGE_EACH_OBJECT 200 ODRX_NO_CONS_DEFINE_MEMBERS(TvExDbUserIO, OdEdBaseUserIO); ODRX_NO_CONS_DEFINE_MEMBERS(TvExDbCommandContextBase, OdEdCommandContext); inline OdString next(OdString& list, const OdChar* delim = (const OdChar*)L",") { OdString res = list.spanExcluding(delim); if(res.getLength() != list.getLength()) list = list.mid(res.getLength()+1); else list.empty(); return res; } OdRxDictionaryPtr TvExDbCommandContext::arbDataDic() const { if(m_pArbDataDic.isNull()) m_pArbDataDic = odrxCreateRxDictionary(); return m_pArbDataDic; } void TvExDbCommandContext::setParam(OdRxObject* pParamObj) { setArbitraryData(OD_T("TvExDbCommandContext_FuncParamObj"), pParamObj); } OdRxObjectPtr TvExDbCommandContext::param() { return arbitraryData(OD_T("TvExDbCommandContext_FuncParamObj")); } void TvExDbCommandContext::setResult(OdRxObject* pResultObj) { setArbitraryData(OD_T("TvExDbCommandContext_FuncResultObj"), pResultObj); } OdRxObjectPtr TvExDbCommandContext::result() { return arbitraryData(OD_T("TvExDbCommandContext_FuncResultObj")); } void TvExDbCommandContext::setArbitraryData(const OdString& szPathName, OdRxObject* pDataObj) { if (pDataObj) arbDataDic()->putAt(szPathName, pDataObj); else arbDataDic()->remove(szPathName); } OdRxObjectPtr TvExDbCommandContext::arbitraryData(const OdString& szPathName) const { return arbDataDic()->getAt(szPathName); } OdUnitsFormatter& TvExDbCommandContext::baseFormatter() { OdDbBaseDatabasePEPtr pDbPE = OdDbBaseDatabasePE::cast(baseDatabase()); //ODA_ASSERT_ONCE(pDbPE.get()); if (!pDbPE.get()) throw OdError(eNoDatabase); return *pDbPE->baseFormatter(baseDatabase()); } inline TvExDbUserIO* TvExDbCommandContext::dbUserIO() { ODA_ASSERT(userIO() && userIO()->isKindOf(TvExDbUserIO::desc())); return static_cast(userIO()); } inline OdDbBaseDatabase* TvExDbCommandContext::database() { OdDbBaseDatabase* pDb = static_cast(baseDatabase()); if (!pDb) throw OdError(eNoDatabase); return pDb; } TvExDbCommandContextBasePtr TvExDbCommandContext::createObject(OdEdBaseIO* pIOStream, OdRxObject* pRxDb) { TvExDbCommandContextBasePtr pRes = OdRxObjectImpl::createObject(); TvExDbCommandContext* pDbCmdCtx = static_cast(pRes.get()); pDbCmdCtx->m_pDb = pRxDb; pDbCmdCtx->m_pIoStream = pIOStream; pDbCmdCtx->m_pOwner = NULL; return pRes; } // Cloud TxHost support void TvExDbCommandContext::reset(OdEdBaseIO* pIOStream, OdRxObject* pRxDb) { m_pIoStream = pIOStream; m_pDb = pRxDb; } OdEdBaseIO* TvExDbCommandContext::baseIO() { return m_pIoStream.get(); } OdEdCommandContextPtr TvExDbCommandContext::cloneObject(OdEdBaseIO* pIOStream, // = NULL OdRxObject* pRxDb) // = NULL { TvExDbCommandContextBasePtr pRes = OdRxObjectImpl::createObject(); TvExDbCommandContext* pDbCmdCtx = static_cast(pRes.get()); pDbCmdCtx->m_pDb = pRxDb ? pRxDb : m_pDb; pDbCmdCtx->m_pIoStream = pIOStream ? pIOStream : m_pIoStream.get(); pDbCmdCtx->m_pOwner = this; return pRes; } OdRxObject* TvExDbCommandContext::baseDatabase() { return m_pDb; } bool TvExDbCommandContext::interactive() { if(m_pIoStream.get()) return m_pIoStream->interactive(); throw OdError(eNotInitializedYet); } OdString TvExDbCommandContext::getStringInternal(const OdString& prompt, int options, OdEdStringTracker* pTracker) { return m_pIoStream->getString(prompt, options, pTracker); } double TvExDbCommandContext::getDist(const OdString& sPrompt, int options, double defVal, const OdString& sKeywords, OdEdRealTracker* pTracker) { OdString prompt( sPrompt ); if(prompt.isEmpty()) prompt = OD_T("Enter a distance:"); return getReal(sPrompt, options, defVal, sKeywords, pTracker); // return getReal(prompt, options, defVal, OdTvResBuf::kDxfXdDist, sKeywords, pTracker); } double TvExDbCommandContext::getAngle(const OdString& sPrompt, int options, double defVal, const OdString& sKeywords, OdEdRealTracker* pTracker) { OdString prompt(sPrompt); if (prompt.isEmpty()) prompt = OD_T("Specify an angle:"); double ANGBASE = 0.0; for (;;) { OdString sInput = getString(prompt, options, OdString::kEmpty, sKeywords); if (sInput.isEmpty()) return defVal; try { double dAngle = baseFormatter().unformatAngle(sInput); dAngle -= ANGBASE; return dAngle; } catch (const OdError& e) { if (e.code() != eInvalidInput) throw; if (GETBIT(options, OdEd::kInpThrowOther)) throw OdEdOtherInput(sInput); putError(sKeywords.find(L' ') < 0 ? L"Requires valid numeric angle." : L"Requires valid numeric angle or optional keyword."); } } } OdEdPointDefTrackerPtr TvExDbCommandContext::createRubberBand(const OdGePoint3d& base, OdGsModel* pModel) const // = NULL { return RubberBand::create(base, pModel); } OdEdPointDefTrackerPtr TvExDbCommandContext::createRectFrame(const OdGePoint3d& base, OdGsModel* pModel) const // = NULL { // { // Create enhanced rect frame if requested // OdRxObjectPtr pArbData = arbitraryData(OD_T("TvExDbCommandContext_EnhRectFrame")); // if (!pArbData.isNull()) // return EnhRectFrame::create(base, pModel); // } return RectFrame::create(base, pModel); } OdGePoint3d TvExDbCommandContext::getLASTPOINT() const { return m_LASTPOINT; } void TvExDbCommandContext::setLASTPOINT(const OdGePoint3d& pt) { m_LASTPOINT = pt; } OdGePoint3d TvExDbCommandContext::getPoint(const OdString& sPrompt, int options, const OdGePoint3d* pDefVal, const OdString& keywords, OdEdPointTracker* pTracker) { OdString prompt(sPrompt); if(prompt.isEmpty()) prompt = OD_T("Enter a point:"); OdEdPointTrackerPtr pPredef; if(!pTracker) { if(GETBIT(options, OdEd::kGptRectFrame)) { pTracker = pPredef = createRectFrame(dbUserIO()->getLASTPOINT()); } else if(GETBIT(options, OdEd::kGptRubberBand)) { pTracker = pPredef = createRubberBand(dbUserIO()->getLASTPOINT()); } } for(;;) { OdGePoint3d res; try { res = m_pIoStream->getPoint( prompt, options, pTracker ); } catch(const OdEdEmptyInput&) { if(GETBIT(options, OdEd::kInpThrowEmpty)) throw; } catch(const OdEdOtherInput& other) { if(!other.string().isEmpty()) { if(!keywords.isEmpty()) KWIndex(keywords).check(other.string()); try { res = OdGePoint3d::kOrigin; OdString sInput(other.string()); int i = 0; if (sInput.find(L',') > 0) // prevent exception via unformatLinear { for (; i < 3 && !sInput.isEmpty(); ++i) { OdString sCoord = ::next(sInput); res[i] = baseFormatter().unformatLinear(sCoord); } } if (i < 2) throw; } catch(const OdError& e) { if(e.code()!=eInvalidInput) throw; if(GETBIT(options, OdEd::kInpThrowOther)) throw other; dbUserIO()->putError(keywords.isEmpty() ? OD_T("Invalid point.") : OD_T("Point or option keyword required.")); continue; } } else if (GETBIT(options, OdEd::kInpThrowEmpty)) { throw OdEdEmptyInput(); } else if(pDefVal) { res = *pDefVal; } else { continue; } } // if(!GETBIT(options, OdEd::kGptNoLimCheck) && database()->getLIMCHECK()) // { // OdGeExtents2d ext(database()->getLIMMIN(), database()->getLIMMAX()); // if(!ext.contains((const OdGePoint2d&)res)) // { // putError(OD_T("**Outside limits")); // continue; // } // } dbUserIO()->setLASTPOINT(res); return res; } } int TvExDbCommandContext::getInt(const OdString& sPrompt, int options, int defVal, const OdString& sKeywords, OdEdIntegerTracker* pTracker) { OdString prompt(sPrompt); if (prompt.isEmpty()) { prompt = OD_T("Enter an integer value:"); } for (;;) { OdString sInput = getString(prompt, options, OdString::kEmpty, sKeywords); if (sInput.isEmpty()) { return defVal; } try { return OdUnitsFormatterTool::toInt(sInput); } catch (const OdError& e) { if (e.code() != eInvalidInput) { throw; } if (GETBIT(options, OdEd::kInpThrowOther)) { throw OdEdOtherInput(sInput); } putError(sKeywords.find(L' ') < 0 ? L"Requires integer value." : L"Requires integer value or optional keyword."); } } } int TvExDbCommandContext::getKeyword(const OdString& sPrompt, const OdString& sKeywords, int defVal, int options, OdEdIntegerTracker* pTracker) { OdString prompt(sPrompt); KWIndex kwIndex(sKeywords); if(prompt.isEmpty()) { prompt = OD_T("Enter one of keywords ["); for(OdUInt32 i=0; i"; if (prompt.find(defValSuf) < 0) //skip if already present prompt += defValSuf; } prompt += OD_T(":"); for(;;) { SETBIT(options, OdEd::kGstNoEmpty, !bDef); OdString sInput; try { // ODE: overriden getString is a key method to support auto-urls by keywords in prompt sInput = getString(prompt, options, bDef ? kwIndex.at(defVal).keyword() : OdString::kEmpty, sKeywords); } catch (OdEdKeyword& key) { return key.keywordIndex(); } if(bDef && sInput.isEmpty()) return defVal; OdUInt32 n = kwIndex.find(sInput); if(n < kwIndex.size()) return n; putString(OD_T("")); putError(OD_T("Invalid option keyword.")); } } double TvExDbCommandContext::getReal(const OdString& sPrompt, int options, double defVal, const OdString& sKeywords, OdEdRealTracker* pTracker) { OdString prompt(sPrompt); if(prompt.isEmpty()) prompt = OD_T("Enter a real value:"); for(;;) { OdString sInput = getString(prompt, options, OdString::kEmpty, sKeywords); if (sInput.isEmpty()) return defVal; try { return baseFormatter().unformatLinear(sInput); } catch(const OdError& e) { if(e.code()!=eInvalidInput) throw; if(GETBIT(options, OdEd::kInpThrowOther)) throw OdEdOtherInput(sInput); putError(sKeywords.find(L' ') < 0 ? L"Requires real value." : L"Requires real value or optional keyword."); } } } OdString TvExDbCommandContext::getString(const OdString& sPrompt, int options, const OdString& pDefVal, const OdString& sKeywords, OdEdStringTracker* pTracker) { OdString res = getStringInternal(sPrompt, options, pTracker); if(res.isEmpty()) { if(GETBIT(options, OdEd::kInpThrowEmpty)) throw OdEdEmptyInput(); if(!pDefVal.isEmpty()) return pDefVal; if(GETBIT(options, OdEd::kGstNoEmpty)) { do { putError(OD_T("Enter non-empty value")); res = getStringInternal(sPrompt, options, pTracker); } while(res.isEmpty()); } else return res; } if(!sKeywords.isEmpty()) KWIndex(sKeywords).check(res); return res; } void TvExDbCommandContext::putString(const OdString& string) { m_pIoStream->putString(string); } OdSharedPtr TvExDbCommandContext::getCmColor(const OdString& sPrompt, int options, const OdCmColorBase* pDefVal, const OdString& sKeywords, OdEdColorTracker* pTracker) { OdString prompt(sPrompt); if(prompt.isEmpty()) prompt = OD_T("Specify a color:"); for(;;) { OdString sInput = getString(prompt, options, pDefVal ? (const OdString&)baseFormatter().formatCmColor(*pDefVal) : OdString::kEmpty, sKeywords); try { return baseFormatter().unformatCmColor(sInput); } catch(const OdError& e) { if(e.code()!=eInvalidInput) throw; if(GETBIT(options, OdEd::kInpThrowOther)) throw OdEdOtherInput(sInput); putError(sKeywords.find(L' ') < 0 ? L"Invalid color value." : L"Requires color value or optional keyword."); } } } #undef DBCC_PAGE_EACH_OBJECT