#include "variables.h" #include "appEngine.h" #include "perRowValues.h" #include "session.h" #include #include #include #include #include class VariableLiteral : public VariableImpl { public: VariableLiteral(const Glib::ustring & src) : VariableImpl(src) { } virtual const Glib::ustring & value() const { return source; } }; class VariableImplDyn : public VariableImpl { public: VariableImplDyn(const Glib::ustring & src) : VariableImpl(src), cacheValid(false) { } virtual const Glib::ustring & value() const = 0; protected: mutable Glib::ustring cache; mutable bool cacheValid; }; class VariableSession : public VariableImplDyn { public: VariableSession(const Glib::ustring & src) : VariableImplDyn(src) { } const Glib::ustring & value() const { try { cache = ApplicationEngine::getCurrent()->session()->GetValue(name); } catch (Session::VariableNotFound) { if (!defaultValue) { throw; } cache = *defaultValue; } return cache; } }; class VariableParam : public VariableImplDyn { public: VariableParam(const Glib::ustring & src) : VariableImplDyn(src) { } const Glib::ustring & value() const { if (!cacheValid) { try { cache = ApplicationEngine::getCurrent()->env()->getParamQuery(name); } catch (ApplicationEngine::ParamNotFound) { if (!defaultValue) { throw; } cache = *defaultValue; } cacheValid = true; } return cache; } }; class VariableUri : public VariableImplDyn { public: VariableUri(const Glib::ustring & src) : VariableImplDyn(src) { } const Glib::ustring & value() const { if (!cacheValid) { try { cache = ApplicationEngine::getCurrent()->env()->getParamUri(atoi(name.c_str())); } catch (ApplicationEngine::UriElementOutOfRange) { if (!defaultValue) { throw; } cache = *defaultValue; } cacheValid = true; } return cache; } }; class VariableParent : public VariableImplDyn, public RowUser { public: VariableParent(const Glib::ustring & src, const RowUser * d) : VariableImplDyn(Glib::ustring(std::find_if(src.begin(), src.end(), isalpha), src.end())), row(NULL), depth(src.length() - source.length()), dep(d) { } ~VariableParent() { if (row) { row->finish(this); if (dep) { row->finish(dep); } } } const Glib::ustring & value() const { if (!cacheValid) { try { if (!row) { PerRowValues::RowValuesStack::const_reverse_iterator r = PerRowValues::Stack().rbegin(); for (size_t p = depth; --p; r++) ; if (r == PerRowValues::Stack().rend()) { throw PerRowValues::ParentOutOfRange(); } row = *r; row->use(this); if (dep) { row->use(dep); } } cache = row->getCurrentValue(name); } catch (PerRowValues::ParentOutOfRange) { if (!defaultValue) { throw; } cache = *defaultValue; } catch (PerRowValues::FieldDoesNotExist) { if (!defaultValue) { throw; } cache = *defaultValue; } cacheValid = true; } return cache; } void rowChanged() const { cacheValid = false; } protected: mutable const PerRowValues * row; const size_t depth; const RowUser * dep; }; class VariableParse : public VariableImplDyn, public RowUser { public: VariableParse(const Glib::ustring & src) : VariableImplDyn(src) { boost::tokenizer > tokens(source.raw(), boost::char_separator(" ")); BOOST_FOREACH(std::string t, tokens) { vars.push_back(Variable::create(t, this)); } } const Glib::ustring & value() const { if (!cacheValid) { size_t len = 0; BOOST_FOREACH(Variable::VariableImplPtr vip, vars) { len += vip->value().length() + 1; } cache.clear(); cache.reserve(len); BOOST_FOREACH(Variable::VariableImplPtr v, vars) { if (cache.length()) { cache.append(" "); } cache.append(v->value()); } cacheValid = true; } return cache; } void rowChanged() const { cacheValid = false; } private: std::list vars; }; Variable::Variable(const Glib::ustring & s) : var(create(s)) { } Variable::Variable(xmlpp::Attribute * a) : var(create(a->get_value())) { } Variable::Variable(xmlpp::Element * e) : var(create(e->get_child_text()->get_content())) { } Variable::VariableImplPtr Variable::create(const Glib::ustring & s, RowUser * dep) { if (s.empty()) { return VariableImplPtr(new VariableLiteral(s)); } switch (s[0]) { case '$': // param return VariableImplPtr(new VariableParam(s)); case '%': // session return VariableImplPtr(new VariableSession(s)); case '^': // parent return VariableImplPtr(new VariableParent(s, dep)); case '/': // uri return VariableImplPtr(new VariableUri(s)); case '*': // parser return VariableImplPtr(new VariableParse(s.substr(1))); case '=': // literal (explicit) return VariableImplPtr(new VariableLiteral(s.substr(1))); default: return VariableImplPtr(new VariableLiteral(s)); } } VariableImpl::VariableImpl(const Glib::ustring & src) : source(src) { Glib::ustring::const_iterator nameStart = std::find_if(source.begin(), source.end(), Glib::Unicode::isalnum); Glib::ustring::const_iterator nameEnd = std::find(nameStart, source.end(), '|'); name = Glib::ustring(nameStart, nameEnd); Glib::ustring::const_iterator defaultStart = nameEnd; if (defaultStart != source.end()) { defaultStart++; defaultValue = Glib::ustring(defaultStart, source.end()); } } VariableImpl::~VariableImpl() { }