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 +  | 
