#include "variables.h" #include "exceptions.h" #include "appEngine.h" #include "session.h" #include "rowUser.h" #include #include #include #include #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 (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 (UriElementOutOfRange) { if (!defaultValue) { throw; } cache = *defaultValue; } cacheValid = true; } return cache; } }; template static void assignHelper(Glib::ustring & dest, const T & src) { const Glib::ustring * srcp = boost::get(&src); if (srcp) { dest = *srcp; } else { dest = boost::lexical_cast(src); } } template <> void assignHelper(Glib::ustring & dest, const Glib::ustring & src) { dest = src; } class VariableParent : public VariableImplDyn, public RowUser { public: VariableParent(const Glib::ustring & src, const RowUser * d) : VariableImplDyn(src), row(NULL), depth(src.find_first_not_of('^')), attr(src[depth] == '!'), dep(d) { } VariableParent(const Glib::ustring & name, unsigned int d) : VariableImplDyn(name), row(NULL), depth(d), attr(name[0] == '!'), dep(NULL) { } ~VariableParent() { if (row) { row->finish(this); if (dep) { row->finish(dep); } } } const Glib::ustring & value() const { if (!cacheValid) { try { if (!row) { RowSet::RowValuesStack::const_reverse_iterator r = RowSet::Stack().rbegin(); for (size_t p = depth; p--; r++) ; if (r == RowSet::Stack().rend()) { throw RowSet::ParentOutOfRange(); } row = *r; row->use(this); if (dep) { row->use(dep); } bind(); } getValue(cache, row); } catch (RowSet::ParentOutOfRange) { if (!defaultValue) { throw; } cache = *defaultValue; } catch (RowSet::FieldDoesNotExist) { if (!defaultValue) { throw; } cache = *defaultValue; } cacheValid = true; } return cache; } void rowChanged() const { cacheValid = false; } protected: void bind() const { if (attr) { getValue = boost::bind(&assignHelper, _1, boost::bind(row->resolveAttr(name))); } else { typedef const Glib::ustring & (RowSet::*gCV)(const Glib::ustring &) const; getValue = boost::bind(&assignHelper, _1, boost::bind((gCV)&RowSet::getCurrentValue, _2, name)); } } mutable const RowSet * row; const size_t depth; const bool attr; const RowUser * dep; mutable boost::function2 getValue; }; 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(const xmlpp::Attribute * a) : var(create(a->get_value())) { } Variable::Variable(const xmlpp::Element * e) : var(create(e->get_child_text()->get_content())) { } Variable::Variable(VariableImpl * v) : var(v) { } 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)); } } Variable Variable::makeParent(const Glib::ustring & n, unsigned int d) { return Variable(new VariableParent(n, d)); } 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() { }