diff options
Diffstat (limited to '')
-rw-r--r-- | src/spreadsheet/flat_dumper.cpp | 208 |
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: */ |