summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-04-11 20:22:39 +0000
committerrandomdan <randomdan@localhost>2014-04-11 20:22:39 +0000
commit969fc74b5933e116ad9615355c5fc4eeed87ca09 (patch)
tree57622893750e29305fe81d188f95ddfca9d2ca71
parentMove lots of components from common in basics (diff)
downloadproject2-969fc74b5933e116ad9615355c5fc4eeed87ca09.tar.bz2
project2-969fc74b5933e116ad9615355c5fc4eeed87ca09.tar.xz
project2-969fc74b5933e116ad9615355c5fc4eeed87ca09.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.cpp154
-rw-r--r--project2/basics/views/autotree.h66
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
+