summaryrefslogtreecommitdiffstats
path: root/src/spreadsheet/flat_dumper.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/spreadsheet/flat_dumper.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/spreadsheet/flat_dumper.cpp b/src/spreadsheet/flat_dumper.cpp
new file mode 100644
index 0000000..9be4245
--- /dev/null
+++ b/src/spreadsheet/flat_dumper.cpp
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "flat_dumper.hpp"
+#include "number_format.hpp"
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/stream.hpp>
+
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/model_iterator.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+using std::cout;
+using std::endl;
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+flat_dumper::flat_dumper(const document& doc) : m_doc(doc) {}
+
+void flat_dumper::dump(std::ostream& os, ixion::sheet_t sheet_id) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_range_t range = cxt.get_data_range(sheet_id);
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ size_t row_count = range.last.row + 1;
+ size_t col_count = range.last.column + 1;
+ os << "rows: " << row_count << " cols: " << col_count << endl;
+
+ // Always start at the top-left corner.
+ range.first.row = 0;
+ range.first.column = 0;
+ ixion::model_iterator iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::vertical, range);
+
+ std::vector<std::string> mx(row_count*col_count);
+
+ auto to_pos = [col_count](size_t row, size_t col) -> size_t
+ {
+ return col_count * row + col;
+ };
+
+ // Calculate column widths as we iterate.
+ std::vector<size_t> col_widths(col_count, 0);
+ auto it_colwidth = col_widths.begin();
+ col_t current_col = 0;
+
+ for (; iter.has(); iter.next())
+ {
+ const ixion::model_iterator::cell& c = iter.get();
+ if (c.col > current_col)
+ {
+ ++current_col;
+ ++it_colwidth;
+ assert(current_col == c.col);
+ }
+
+ size_t cell_str_width = 0;
+
+ switch (c.type)
+ {
+ case ixion::celltype_t::string:
+ {
+ ixion::string_id_t sindex = std::get<ixion::string_id_t>(c.value);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ cell_str_width = calc_logical_string_length(*p);
+ mx[to_pos(c.row, c.col)] = std::move(*p);
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ std::ostringstream os2;
+ format_to_file_output(os2, std::get<double>(c.value));
+ os2 << " [v]";
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ break;
+ }
+ case ixion::celltype_t::boolean:
+ {
+ std::ostringstream os2;
+ os2 << (std::get<bool>(c.value) ? "true" : "false") << " [b]";
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = std::get<const ixion::formula_cell*>(c.value);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+
+ std::ostringstream os2;
+ std::string formula;
+ if (resolver)
+ {
+ ixion::abs_address_t pos(sheet_id, c.row, c.col);
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ cxt, pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os2 << '{' << formula << '}';
+ else
+ os2 << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os2 << " (" << res.str(cxt) << ")";
+ }
+ catch (const std::exception&)
+ {
+ os2 << "(#RES!)";
+ }
+
+ std::string s = os2.str();
+ cell_str_width = calc_logical_string_length(s);
+ mx[to_pos(c.row, c.col)] = std::move(s);
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+ if (*it_colwidth < cell_str_width)
+ *it_colwidth = cell_str_width;
+ }
+
+ // Create a row separator string;
+ std::ostringstream os2;
+ os2 << '+';
+ for (size_t i = 0; i < col_widths.size(); ++i)
+ {
+ os2 << '-';
+ size_t cw = col_widths[i];
+ for (size_t j = 0; j < cw; ++j)
+ os2 << '-';
+ os2 << "-+";
+ }
+
+ std::string sep = os2.str();
+
+ // Now print to stdout.
+ os << sep << endl;
+ for (size_t r = 0; r < row_count; ++r)
+ {
+ os << "|";
+ for (size_t c = 0; c < col_count; ++c)
+ {
+ size_t cw = col_widths[c]; // column width
+ const std::string& s = mx[to_pos(r, c)];
+ if (s.empty())
+ {
+ for (size_t i = 0; i < cw; ++i)
+ os << ' ';
+ os << " |";
+ }
+ else
+ {
+ os << ' ' << s;
+ cw -= calc_logical_string_length(s);
+ for (size_t i = 0; i < cw; ++i)
+ os << ' ';
+ os << " |";
+ }
+ }
+ os << endl;
+ os << sep << endl;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */