diff options
author | randomdan <randomdan@localhost> | 2014-04-11 20:22:39 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2014-04-11 20:22:39 +0000 |
commit | cb9afbc62cedd74c019ac8dc28ad696dd8e3f82f (patch) | |
tree | 57622893750e29305fe81d188f95ddfca9d2ca71 | |
parent | Move lots of components from common in basics (diff) | |
download | project2-cb9afbc62cedd74c019ac8dc28ad696dd8e3f82f.tar.bz2 project2-cb9afbc62cedd74c019ac8dc28ad696dd8e3f82f.tar.xz project2-cb9afbc62cedd74c019ac8dc28ad696dd8e3f82f.zip |
Add component for build a tree view from a flat row set based on sequential identical values
-rw-r--r-- | project2/basics/views/autotree.cpp | 154 | ||||
-rw-r--r-- | project2/basics/views/autotree.h | 66 |
2 files changed, 220 insertions, 0 deletions
diff --git a/project2/basics/views/autotree.cpp b/project2/basics/views/autotree.cpp new file mode 100644 index 0000000..d957040 --- /dev/null +++ b/project2/basics/views/autotree.cpp @@ -0,0 +1,154 @@ +#include <pch.hpp> +#include "autotree.h" +#include "presenter.h" +#include "scopeObject.h" +#include "scriptLoader.h" +#include "scopeObject.h" +#include <boost/foreach.hpp> +#include <boost/bind.hpp> + +DECLARE_LOADER("autotree", AutoTree); + +AutoTree::AutoTree(ScriptNodePtr p) : + SourceObject(p), + View(p), + RowProcessor(p), + root(new AutoTreeNode(p->child("tree"), 0, 0)) +{ + auto node = root; + while (node) { + depth += 1; + node = node->child(); + } +} + +AutoTree::~AutoTree() +{ +} + +void +AutoTree::loadComplete(const CommonObjects * co) +{ + RowProcessor::loadComplete(co); +} + +void +AutoTree::execute(const MultiRowSetPresenter * p, ExecContext * ec) const +{ + AutoTreeState state; + for (unsigned int d = 0; d < depth; ++d) { + state.opened.push_back(AutoTreeState::Opened(false, false)); + } + root->openArray(p, ec, state); + RowProcessor::execute(ec, boost::bind(&AutoTreeNode::rowReady, root, _1, p, ec, boost::ref(state))); + root->closeArray(p, ec, state); +} + +AutoTreeNode::AutoTreeNode(ScriptNodePtr sn, unsigned int p, unsigned int d) : + rootName(sn, "rootname", Null()), + objectName(sn, "objectname", Null()), + pos(p), + depth(d) +{ + BOOST_FOREACH (const auto & n, sn->children("key")) { + keys.insert({n->value("name", NULL).as<Glib::ustring>(), Variable::fromScriptNode(n)} ); + } + BOOST_FOREACH (const auto & n, sn->children("include")) { + includes.insert({n->value("name", NULL).as<Glib::ustring>(), Variable::fromScriptNode(n)} ); + } + if (sn->valueExists("tree")) { + tree = new AutoTreeNode(sn->child("tree"), pos + keys.size(), depth + 1); + } +} + +void +AutoTreeNode::rowReady(const RowState * rs, const MultiRowSetPresenter * p, ExecContext * ec, AutoTreeState & state) const +{ + std::vector<VariableType> values; + values.reserve(keys.size()); + BOOST_FOREACH (const auto & v, keys) { + values.push_back(v.second(ec)); + } + bool isNew = false; + if (state.values.size() < keys.size() + pos) { + isNew = true; + } + else { + for (unsigned int k = 0; k < keys.size(); ++k) { + if (state.values[pos + k] != values[k]) { + isNew = true; + break; + } + } + } + if (isNew) { + closeObject(p, ec, state); + state.values.resize(pos); + openObject(p, ec, state); + unsigned int k = 0; + BOOST_FOREACH (const auto & v, keys) { + state.values.push_back(values[k]); + p->addNamedValue(v.first, values[k++]); + } + BOOST_FOREACH (const auto & v, includes) { + p->addNamedValue(v.first, v.second(ec)); + } + if (tree) { + tree->openArray(p, ec, state); + } + } + + if (tree) { + tree->rowReady(rs, p, ec, state); + } +} + +#define arrayOpened opened[depth].get<0>() +#define objectOpened opened[depth].get<1>() + +void +AutoTreeNode::openArray(const MultiRowSetPresenter * p, ExecContext * ec, AutoTreeState & state) const +{ + if (!state.arrayOpened && !rootName(ec).isNull()) { + p->addNewRowSet(rootName(ec)); + state.arrayOpened = true; + } +} + +void +AutoTreeNode::openObject(const MultiRowSetPresenter * p, ExecContext * ec, AutoTreeState & state) const +{ + if (!state.objectOpened && !objectName(ec).isNull()) { + p->addNewRowSet(objectName(ec)); + state.objectOpened = true; + } +} + +void +AutoTreeNode::closeArray(const MultiRowSetPresenter * p, ExecContext * ec, AutoTreeState & state) const +{ + closeObject(p, ec, state); + if (state.arrayOpened && !rootName(ec).isNull()) { + p->finishRowSet(); + state.arrayOpened = false; + } +} + +void +AutoTreeNode::closeObject(const MultiRowSetPresenter * p, ExecContext * ec, AutoTreeState & state) const +{ + if (tree) { + tree->closeArray(p, ec, state); + } + if (state.objectOpened && !objectName(ec).isNull()) { + p->finishRow(); + state.objectOpened = false; + } +} + +AutoTreeNodePtr +AutoTreeNode::child() const +{ + return tree; +} + diff --git a/project2/basics/views/autotree.h b/project2/basics/views/autotree.h new file mode 100644 index 0000000..48f46be --- /dev/null +++ b/project2/basics/views/autotree.h @@ -0,0 +1,66 @@ +#ifndef AUTOTREE_H +#define AUTOTREE_H + +#include <boost/intrusive_ptr.hpp> +#include "rowProcessor.h" +#include "view.h" +#include "aggregate.h" + +class AutoTreeNode; +typedef boost::intrusive_ptr<const AutoTreeNode> AutoTreeNodePtr; + +class AutoTreeState { + public: + typedef boost::tuple<bool, bool> Opened; + + std::vector<Opened> opened; + std::vector<VariableType> values; +}; + +class AutoTreeNode : public IntrusivePtrBase { + public: + typedef std::map<Glib::ustring, Variable> Values; + + AutoTreeNode(ScriptNodePtr, unsigned int pos, unsigned int depth); + + void rowReady(const RowState *, const MultiRowSetPresenter *, ExecContext *, AutoTreeState & state) const; + void openArray(const MultiRowSetPresenter * p, ExecContext *, AutoTreeState & state) const; + void openObject(const MultiRowSetPresenter * p, ExecContext *, AutoTreeState & state) const; + void closeArray(const MultiRowSetPresenter * p, ExecContext *, AutoTreeState & state) const; + void closeObject(const MultiRowSetPresenter * p, ExecContext *, AutoTreeState & state) const; + AutoTreeNodePtr child() const; + + protected: + + private: + Values keys; + Values includes; + AutoTreeNodePtr tree; + Variable rootName; + Variable objectName; + + const unsigned int pos; + const unsigned int depth; +}; + +/// Project2 component to create tree output based on a records in a row set +class AutoTree : public View, public RowProcessor { + public: + AutoTree(ScriptNodePtr); + virtual ~AutoTree(); + + void loadComplete(const CommonObjects *); + void execute(const MultiRowSetPresenter *, ExecContext *) const; + + protected: + typedef std::map<Glib::ustring, Variable> Columns; + Columns viewColumns; + + void executeChildren(const MultiRowSetPresenter * presenter, ExecContext *) const; + + AutoTreeNodePtr root; + unsigned int depth; +}; + +#endif + |