summaryrefslogtreecommitdiffstats
path: root/src/spreadsheet
diff options
context:
space:
mode:
Diffstat (limited to 'src/spreadsheet')
-rw-r--r--src/spreadsheet/Makefile.am90
-rw-r--r--src/spreadsheet/Makefile.in1134
-rw-r--r--src/spreadsheet/auto_filter.cpp116
-rw-r--r--src/spreadsheet/check_dumper.cpp209
-rw-r--r--src/spreadsheet/check_dumper.hpp38
-rw-r--r--src/spreadsheet/config.cpp28
-rw-r--r--src/spreadsheet/csv_dumper.cpp95
-rw-r--r--src/spreadsheet/csv_dumper.hpp38
-rw-r--r--src/spreadsheet/debug_state_dumper.cpp460
-rw-r--r--src/spreadsheet/debug_state_dumper.hpp61
-rw-r--r--src/spreadsheet/document.cpp526
-rw-r--r--src/spreadsheet/document_impl.cpp232
-rw-r--r--src/spreadsheet/document_impl.hpp104
-rw-r--r--src/spreadsheet/document_types.cpp77
-rw-r--r--src/spreadsheet/dumper_global.cpp87
-rw-r--r--src/spreadsheet/dumper_global.hpp31
-rw-r--r--src/spreadsheet/factory.cpp410
-rw-r--r--src/spreadsheet/factory_pivot.cpp303
-rw-r--r--src/spreadsheet/factory_pivot.hpp120
-rw-r--r--src/spreadsheet/factory_shared_strings.cpp118
-rw-r--r--src/spreadsheet/factory_shared_strings.hpp64
-rw-r--r--src/spreadsheet/factory_sheet.cpp640
-rw-r--r--src/spreadsheet/factory_sheet.hpp275
-rw-r--r--src/spreadsheet/factory_styles.cpp870
-rw-r--r--src/spreadsheet/factory_table.cpp213
-rw-r--r--src/spreadsheet/factory_table.hpp60
-rw-r--r--src/spreadsheet/flat_dumper.cpp208
-rw-r--r--src/spreadsheet/flat_dumper.hpp36
-rw-r--r--src/spreadsheet/formula_global.cpp56
-rw-r--r--src/spreadsheet/formula_global.hpp48
-rw-r--r--src/spreadsheet/global_settings.cpp50
-rw-r--r--src/spreadsheet/global_settings.hpp41
-rw-r--r--src/spreadsheet/html_dumper.cpp695
-rw-r--r--src/spreadsheet/html_dumper.hpp49
-rw-r--r--src/spreadsheet/impl_types.hpp40
-rw-r--r--src/spreadsheet/json_dumper.cpp95
-rw-r--r--src/spreadsheet/json_dumper.hpp36
-rw-r--r--src/spreadsheet/number_format.cpp25
-rw-r--r--src/spreadsheet/number_format.hpp28
-rw-r--r--src/spreadsheet/pivot.cpp371
-rw-r--r--src/spreadsheet/shared_formula.cpp32
-rw-r--r--src/spreadsheet/shared_formula.hpp36
-rw-r--r--src/spreadsheet/shared_strings.cpp61
-rw-r--r--src/spreadsheet/sheet.cpp555
-rw-r--r--src/spreadsheet/sheet_impl.cpp53
-rw-r--r--src/spreadsheet/sheet_impl.hpp72
-rw-r--r--src/spreadsheet/styles.cpp485
-rw-r--r--src/spreadsheet/view.cpp201
48 files changed, 9672 insertions, 0 deletions
diff --git a/src/spreadsheet/Makefile.am b/src/spreadsheet/Makefile.am
new file mode 100644
index 0000000..8f1e0fb
--- /dev/null
+++ b/src/spreadsheet/Makefile.am
@@ -0,0 +1,90 @@
+if BUILD_SPREADSHEET_MODEL
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -D__ORCUS_SPM_BUILDING_DLL
+
+AM_CPPFLAGS += $(BOOST_CPPFLAGS) $(LIBIXION_CFLAGS)
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+COMMON_CPPFLAGS = $(AM_CPPFLAGS)
+
+if HAVE_STATIC_LIB
+AM_CPPFLAGS += -D__ORCUS_STATIC_LIB=1
+endif
+
+lib_LTLIBRARIES = liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES = \
+ auto_filter.cpp \
+ check_dumper.hpp \
+ check_dumper.cpp \
+ config.cpp \
+ debug_state_dumper.hpp \
+ debug_state_dumper.cpp \
+ document.cpp \
+ document_impl.hpp \
+ document_impl.cpp \
+ document_types.cpp \
+ dumper_global.hpp \
+ dumper_global.cpp \
+ factory.cpp \
+ factory_pivot.hpp \
+ factory_pivot.cpp \
+ factory_shared_strings.hpp \
+ factory_shared_strings.cpp \
+ factory_sheet.hpp \
+ factory_sheet.cpp \
+ factory_styles.cpp \
+ factory_table.hpp \
+ factory_table.cpp \
+ flat_dumper.hpp \
+ flat_dumper.cpp \
+ formula_global.hpp \
+ formula_global.cpp \
+ html_dumper.hpp \
+ html_dumper.cpp \
+ impl_types.hpp \
+ csv_dumper.hpp \
+ csv_dumper.cpp \
+ json_dumper.hpp \
+ json_dumper.cpp \
+ number_format.hpp \
+ number_format.cpp \
+ pivot.cpp \
+ shared_formula.hpp \
+ shared_formula.cpp \
+ shared_strings.cpp \
+ sheet.cpp \
+ sheet_impl.hpp \
+ sheet_impl.cpp \
+ styles.cpp \
+ view.cpp \
+ global_settings.hpp \
+ global_settings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBIXION_CFLAGS)
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD = \
+ $(LIBIXION_LIBS) \
+ $(BOOST_DATE_TIME_LIBS) \
+ $(BOOST_SYSTEM_LIBS) \
+ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../liborcus/liborcus-@ORCUS_API_VERSION@.la
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD += -lstdc++fs
+else
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+endif
diff --git a/src/spreadsheet/Makefile.in b/src/spreadsheet/Makefile.in
new file mode 100644
index 0000000..f1fabb8
--- /dev/null
+++ b/src/spreadsheet/Makefile.in
@@ -0,0 +1,1134 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_FILESYSTEM_TRUE@am__append_1 = "-DHAVE_FILESYSTEM=1"
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_2 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_STATIC_LIB_TRUE@am__append_3 = -D__ORCUS_STATIC_LIB=1
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_4 = -lstdc++fs
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_5 = $(BOOST_FILESYSTEM_LIBS)
+subdir = src/spreadsheet
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@BUILD_SPREADSHEET_MODEL_TRUE@@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__DEPENDENCIES_2)
+am__liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES_DIST = \
+ auto_filter.cpp check_dumper.hpp check_dumper.cpp config.cpp \
+ debug_state_dumper.hpp debug_state_dumper.cpp document.cpp \
+ document_impl.hpp document_impl.cpp document_types.cpp \
+ dumper_global.hpp dumper_global.cpp factory.cpp \
+ factory_pivot.hpp factory_pivot.cpp factory_shared_strings.hpp \
+ factory_shared_strings.cpp factory_sheet.hpp factory_sheet.cpp \
+ factory_styles.cpp factory_table.hpp factory_table.cpp \
+ flat_dumper.hpp flat_dumper.cpp formula_global.hpp \
+ formula_global.cpp html_dumper.hpp html_dumper.cpp \
+ impl_types.hpp csv_dumper.hpp csv_dumper.cpp json_dumper.hpp \
+ json_dumper.cpp number_format.hpp number_format.cpp pivot.cpp \
+ shared_formula.hpp shared_formula.cpp shared_strings.cpp \
+ sheet.cpp sheet_impl.hpp sheet_impl.cpp styles.cpp view.cpp \
+ global_settings.hpp global_settings.cpp
+@BUILD_SPREADSHEET_MODEL_TRUE@am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS = liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo \
+@BUILD_SPREADSHEET_MODEL_TRUE@ liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS = $(am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) \
+ $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_SPREADSHEET_MODEL_TRUE@am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_rpath = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -rpath $(libdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo \
+ ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = \
+ $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES)
+DIST_SOURCES = $(am__liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+@BUILD_SPREADSHEET_MODEL_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/include \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -I$(top_srcdir)/src/include \
+@BUILD_SPREADSHEET_MODEL_TRUE@ -D__ORCUS_SPM_BUILDING_DLL \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_CPPFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(LIBIXION_CFLAGS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_1) $(am__append_2) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_3)
+@BUILD_SPREADSHEET_MODEL_TRUE@COMMON_CPPFLAGS = $(AM_CPPFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@lib_LTLIBRARIES = liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_SOURCES = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ auto_filter.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ check_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ check_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ config.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ debug_state_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ debug_state_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_impl.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_impl.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ document_types.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ dumper_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ dumper_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_pivot.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_pivot.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_shared_strings.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_shared_strings.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_sheet.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_sheet.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_styles.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_table.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ factory_table.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ flat_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ flat_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ formula_global.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ formula_global.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ html_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ html_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ impl_types.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ csv_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ csv_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ json_dumper.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ json_dumper.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ number_format.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ number_format.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ pivot.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_formula.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_formula.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ shared_strings.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_impl.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ sheet_impl.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ styles.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ view.cpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ global_settings.hpp \
+@BUILD_SPREADSHEET_MODEL_TRUE@ global_settings.cpp
+
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBIXION_CFLAGS)
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined
+@BUILD_SPREADSHEET_MODEL_TRUE@liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD = \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(LIBIXION_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_DATE_TIME_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(BOOST_SYSTEM_LIBS) \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../parser/liborcus-parser-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ ../liborcus/liborcus-@ORCUS_API_VERSION@.la \
+@BUILD_SPREADSHEET_MODEL_TRUE@ $(am__append_4) $(am__append_5)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/spreadsheet/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/spreadsheet/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-spreadsheet-model-@ORCUS_API_VERSION@.la: $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LINK) $(am_liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_rpath) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo: auto_filter.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo `test -f 'auto_filter.cpp' || echo '$(srcdir)/'`auto_filter.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='auto_filter.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.lo `test -f 'auto_filter.cpp' || echo '$(srcdir)/'`auto_filter.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo: check_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo `test -f 'check_dumper.cpp' || echo '$(srcdir)/'`check_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='check_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.lo `test -f 'check_dumper.cpp' || echo '$(srcdir)/'`check_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo: config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.lo `test -f 'config.cpp' || echo '$(srcdir)/'`config.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo: debug_state_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo `test -f 'debug_state_dumper.cpp' || echo '$(srcdir)/'`debug_state_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='debug_state_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.lo `test -f 'debug_state_dumper.cpp' || echo '$(srcdir)/'`debug_state_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo: document.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo `test -f 'document.cpp' || echo '$(srcdir)/'`document.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.lo `test -f 'document.cpp' || echo '$(srcdir)/'`document.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo: document_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo `test -f 'document_impl.cpp' || echo '$(srcdir)/'`document_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document_impl.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.lo `test -f 'document_impl.cpp' || echo '$(srcdir)/'`document_impl.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo: document_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo `test -f 'document_types.cpp' || echo '$(srcdir)/'`document_types.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='document_types.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.lo `test -f 'document_types.cpp' || echo '$(srcdir)/'`document_types.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo: dumper_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo `test -f 'dumper_global.cpp' || echo '$(srcdir)/'`dumper_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dumper_global.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.lo `test -f 'dumper_global.cpp' || echo '$(srcdir)/'`dumper_global.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo: factory.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo `test -f 'factory.cpp' || echo '$(srcdir)/'`factory.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.lo `test -f 'factory.cpp' || echo '$(srcdir)/'`factory.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo: factory_pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo `test -f 'factory_pivot.cpp' || echo '$(srcdir)/'`factory_pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_pivot.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.lo `test -f 'factory_pivot.cpp' || echo '$(srcdir)/'`factory_pivot.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo: factory_shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo `test -f 'factory_shared_strings.cpp' || echo '$(srcdir)/'`factory_shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_shared_strings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.lo `test -f 'factory_shared_strings.cpp' || echo '$(srcdir)/'`factory_shared_strings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo: factory_sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo `test -f 'factory_sheet.cpp' || echo '$(srcdir)/'`factory_sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_sheet.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.lo `test -f 'factory_sheet.cpp' || echo '$(srcdir)/'`factory_sheet.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo: factory_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo `test -f 'factory_styles.cpp' || echo '$(srcdir)/'`factory_styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_styles.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.lo `test -f 'factory_styles.cpp' || echo '$(srcdir)/'`factory_styles.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo: factory_table.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo `test -f 'factory_table.cpp' || echo '$(srcdir)/'`factory_table.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='factory_table.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.lo `test -f 'factory_table.cpp' || echo '$(srcdir)/'`factory_table.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo: flat_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo `test -f 'flat_dumper.cpp' || echo '$(srcdir)/'`flat_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='flat_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.lo `test -f 'flat_dumper.cpp' || echo '$(srcdir)/'`flat_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo: formula_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo `test -f 'formula_global.cpp' || echo '$(srcdir)/'`formula_global.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='formula_global.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.lo `test -f 'formula_global.cpp' || echo '$(srcdir)/'`formula_global.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo: html_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo `test -f 'html_dumper.cpp' || echo '$(srcdir)/'`html_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='html_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.lo `test -f 'html_dumper.cpp' || echo '$(srcdir)/'`html_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo: csv_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo `test -f 'csv_dumper.cpp' || echo '$(srcdir)/'`csv_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.lo `test -f 'csv_dumper.cpp' || echo '$(srcdir)/'`csv_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo: json_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo `test -f 'json_dumper.cpp' || echo '$(srcdir)/'`json_dumper.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_dumper.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.lo `test -f 'json_dumper.cpp' || echo '$(srcdir)/'`json_dumper.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo: number_format.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo `test -f 'number_format.cpp' || echo '$(srcdir)/'`number_format.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='number_format.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.lo `test -f 'number_format.cpp' || echo '$(srcdir)/'`number_format.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo: pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo `test -f 'pivot.cpp' || echo '$(srcdir)/'`pivot.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pivot.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.lo `test -f 'pivot.cpp' || echo '$(srcdir)/'`pivot.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo: shared_formula.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo `test -f 'shared_formula.cpp' || echo '$(srcdir)/'`shared_formula.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='shared_formula.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.lo `test -f 'shared_formula.cpp' || echo '$(srcdir)/'`shared_formula.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo: shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo `test -f 'shared_strings.cpp' || echo '$(srcdir)/'`shared_strings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='shared_strings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.lo `test -f 'shared_strings.cpp' || echo '$(srcdir)/'`shared_strings.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo: sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo `test -f 'sheet.cpp' || echo '$(srcdir)/'`sheet.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sheet.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.lo `test -f 'sheet.cpp' || echo '$(srcdir)/'`sheet.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo: sheet_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo `test -f 'sheet_impl.cpp' || echo '$(srcdir)/'`sheet_impl.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sheet_impl.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.lo `test -f 'sheet_impl.cpp' || echo '$(srcdir)/'`sheet_impl.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo: styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo `test -f 'styles.cpp' || echo '$(srcdir)/'`styles.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='styles.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.lo `test -f 'styles.cpp' || echo '$(srcdir)/'`styles.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo: view.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo `test -f 'view.cpp' || echo '$(srcdir)/'`view.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='view.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.lo `test -f 'view.cpp' || echo '$(srcdir)/'`view.cpp
+
+liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo: global_settings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo -MD -MP -MF $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Tpo -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo `test -f 'global_settings.cpp' || echo '$(srcdir)/'`global_settings.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Tpo $(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='global_settings.cpp' object='liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.lo `test -f 'global_settings.cpp' || echo '$(srcdir)/'`global_settings.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-auto_filter.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-check_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-config.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-csv_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-debug_state_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-document_types.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-dumper_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-factory_table.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-flat_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-formula_global.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-global_settings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-html_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-json_dumper.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-number_format.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-pivot.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_formula.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-shared_strings.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-sheet_impl.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-styles.Plo
+ -rm -f ./$(DEPDIR)/liborcus_spreadsheet_model_@ORCUS_API_VERSION@_la-view.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am am--depfiles check check-am check-valgrind-am \
+ check-valgrind-drd-am check-valgrind-drd-local \
+ check-valgrind-helgrind-am check-valgrind-helgrind-local \
+ check-valgrind-local check-valgrind-memcheck-am \
+ check-valgrind-memcheck-local check-valgrind-sgcheck-am \
+ check-valgrind-sgcheck-local clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/spreadsheet/auto_filter.cpp b/src/spreadsheet/auto_filter.cpp
new file mode 100644
index 0000000..3262305
--- /dev/null
+++ b/src/spreadsheet/auto_filter.cpp
@@ -0,0 +1,116 @@
+/* -*- 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 "orcus/spreadsheet/auto_filter.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+auto_filter_column_t::auto_filter_column_t() = default;
+auto_filter_column_t::auto_filter_column_t(const auto_filter_column_t& other) = default;
+auto_filter_column_t::auto_filter_column_t(auto_filter_column_t&& other) = default;
+auto_filter_column_t::~auto_filter_column_t() = default;
+
+auto_filter_column_t& auto_filter_column_t::operator=(const auto_filter_column_t& other) = default;
+auto_filter_column_t& auto_filter_column_t::operator=(auto_filter_column_t&& other) = default;
+
+void auto_filter_column_t::reset()
+{
+ match_values.clear();
+}
+
+void auto_filter_column_t::swap(auto_filter_column_t& r)
+{
+ match_values.swap(r.match_values);
+}
+
+auto_filter_t::auto_filter_t() : range(ixion::abs_range_t::invalid) {}
+auto_filter_t::auto_filter_t(const auto_filter_t& other) = default;
+auto_filter_t::auto_filter_t(auto_filter_t&& other) = default;
+auto_filter_t::~auto_filter_t() = default;
+
+auto_filter_t& auto_filter_t::operator=(const auto_filter_t& other) = default;
+auto_filter_t& auto_filter_t::operator=(auto_filter_t&& other) = default;
+
+void auto_filter_t::reset()
+{
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ columns.clear();
+}
+
+void auto_filter_t::swap(auto_filter_t& r)
+{
+ std::swap(range, r.range);
+ columns.swap(r.columns);
+}
+
+void auto_filter_t::commit_column(col_t col, auto_filter_column_t data)
+{
+ if (col < 0)
+ // Invalid column index. Nothing happens.
+ return;
+
+ columns.insert_or_assign(col, std::move(data));
+}
+
+table_column_t::table_column_t() : identifier(0), totals_row_function(totals_row_function_t::none) {}
+
+table_column_t::table_column_t(const table_column_t& other) = default;
+table_column_t::~table_column_t() = default;
+
+table_column_t& table_column_t::operator=(const table_column_t& other) = default;
+
+void table_column_t::reset()
+{
+ identifier = 0;
+ name = std::string_view{};
+ totals_row_label = std::string_view{};
+ totals_row_function = totals_row_function_t::none;
+}
+
+table_style_t::table_style_t() :
+ show_first_column(false),
+ show_last_column(false),
+ show_row_stripes(false),
+ show_column_stripes(false) {}
+
+table_style_t::table_style_t(const table_style_t& other) = default;
+table_style_t::~table_style_t() = default;
+
+table_style_t& table_style_t::operator=(const table_style_t& other) = default;
+
+void table_style_t::reset()
+{
+ name = std::string_view{};
+ show_first_column = false;
+ show_last_column = false;
+ show_row_stripes = false;
+ show_column_stripes = false;
+}
+
+table_t::table_t() : identifier(0), range(ixion::abs_range_t::invalid), totals_row_count(0) {}
+table_t::table_t(const table_t& other) = default;
+table_t::table_t(table_t&& other) = default;
+table_t::~table_t() = default;
+
+table_t& table_t::operator=(const table_t& other) = default;
+table_t& table_t::operator=(table_t&& other) = default;
+
+void table_t::reset()
+{
+ identifier = 0;
+ name = std::string_view{};
+ display_name = std::string_view{};
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ totals_row_count = 0;
+ filter.reset();
+ columns.clear();
+ style.reset();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/check_dumper.cpp b/src/spreadsheet/check_dumper.cpp
new file mode 100644
index 0000000..191b5a0
--- /dev/null
+++ b/src/spreadsheet/check_dumper.cpp
@@ -0,0 +1,209 @@
+/* -*- 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 "check_dumper.hpp"
+#include "sheet_impl.hpp"
+#include "number_format.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/cell.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+
+#include <string>
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void write_cell_position(std::ostream& os, std::string_view sheet_name, row_t row, col_t col)
+{
+ os << sheet_name << '/' << row << '/' << col << ':';
+}
+
+std::string escape_chars(const std::string& str)
+{
+ if (str.empty())
+ return str;
+
+ std::string ret;
+ const char* p = &str[0];
+ const char* p_end = p + str.size();
+ for (; p != p_end; ++p)
+ {
+ if (*p == '"')
+ ret.push_back('\\');
+ ret.push_back(*p);
+ }
+ return ret;
+}
+
+}
+
+check_dumper::check_dumper(const detail::sheet_impl& sheet, std::string_view sheet_name) :
+ m_sheet(sheet), m_sheet_name(sheet_name)
+{
+}
+
+void check_dumper::dump(std::ostream& os) const
+{
+ dump_cell_values(os);
+ dump_merged_cell_info(os);
+}
+
+void check_dumper::dump_cell_values(std::ostream& os) const
+{
+ ixion::abs_range_t range = m_sheet.get_data_range();
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::model_context& cxt = m_sheet.doc.get_model_context();
+ const ixion::formula_name_resolver* resolver =
+ m_sheet.doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+
+ size_t row_count = range.last.row + 1;
+ size_t col_count = range.last.column + 1;
+
+ for (size_t row = 0; row < row_count; ++row)
+ {
+ for (size_t col = 0; col < col_count; ++col)
+ {
+ ixion::abs_address_t pos(m_sheet.sheet_id, row, col);
+ switch (cxt.get_celltype(pos))
+ {
+ case ixion::celltype_t::string:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ size_t sindex = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ os << "string:\"" << escape_chars(*p) << '"' << std::endl;
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "numeric:";
+ detail::format_to_file_output(os, cxt.get_numeric_value(pos));
+ os << std::endl;
+ break;
+ }
+ case ixion::celltype_t::boolean:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "boolean:" << (cxt.get_boolean_value(pos) ? "true" : "false") << std::endl;
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ write_cell_position(os, m_sheet_name, row, col);
+ os << "formula";
+
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = cxt.get_formula_cell(pos);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+ std::string formula;
+ if (resolver)
+ {
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ m_sheet.doc.get_model_context(), pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ os << ':';
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os << '{' << formula << '}';
+ else
+ os << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os << ':' << res.str(m_sheet.doc.get_model_context());
+ }
+ catch (const std::exception&)
+ {
+ os << ":#RES!";
+ }
+ }
+
+ os << std::endl;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+}
+
+void check_dumper::dump_merged_cell_info(std::ostream& os) const
+{
+ // Sort by rows first then by columns.
+
+ struct _entry
+ {
+ row_t row;
+ col_t col;
+ const merge_size* ms;
+
+ _entry(row_t _row, col_t _col, const merge_size* _ms) :
+ row(_row), col(_col), ms(_ms) {}
+ };
+
+ std::vector<_entry> entries;
+
+ for (const auto& col_entry : m_sheet.merge_ranges)
+ {
+ col_t col = col_entry.first;
+
+ for (const auto& row_entry : *col_entry.second)
+ {
+ row_t row = row_entry.first;
+ const merge_size& ms = row_entry.second;
+
+ entries.emplace_back(row, col, &ms);
+ }
+ }
+
+ std::sort(entries.begin(), entries.end(),
+ [](const _entry& left, const _entry& right) -> bool
+ {
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ if (left.col != right.col)
+ return left.col < right.col;
+
+ return left.ms < right.ms;
+ }
+ );
+
+ for (const _entry e : entries)
+ {
+ os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-width:" << e.ms->width << std::endl;
+ os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-height:" << e.ms->height << std::endl;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/check_dumper.hpp b/src/spreadsheet/check_dumper.hpp
new file mode 100644
index 0000000..3a55a2c
--- /dev/null
+++ b/src/spreadsheet/check_dumper.hpp
@@ -0,0 +1,38 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_CHECK_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_CHECK_DUMPER_HPP
+
+#include <ostream>
+#include <string_view>
+
+namespace orcus { namespace spreadsheet {
+
+namespace detail {
+
+struct sheet_impl;
+
+class check_dumper
+{
+ const sheet_impl& m_sheet;
+ std::string_view m_sheet_name;
+
+public:
+ check_dumper(const sheet_impl& sheet, std::string_view sheet_name);
+ void dump(std::ostream& os) const;
+
+private:
+ void dump_cell_values(std::ostream& os) const;
+ void dump_merged_cell_info(std::ostream& os) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/config.cpp b/src/spreadsheet/config.cpp
new file mode 100644
index 0000000..45a7934
--- /dev/null
+++ b/src/spreadsheet/config.cpp
@@ -0,0 +1,28 @@
+/* -*- 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 "orcus/spreadsheet/config.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+document_config::document_config() :
+ output_precision(-1) {}
+
+document_config::document_config(const document_config& r) :
+ output_precision(r.output_precision) {}
+
+document_config::~document_config() {}
+
+document_config& document_config::operator= (const document_config& r)
+{
+ output_precision = r.output_precision;
+ return *this;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/csv_dumper.cpp b/src/spreadsheet/csv_dumper.cpp
new file mode 100644
index 0000000..5aa5a4e
--- /dev/null
+++ b/src/spreadsheet/csv_dumper.cpp
@@ -0,0 +1,95 @@
+/* -*- 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 "csv_dumper.hpp"
+#include "dumper_global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <mdds/multi_type_vector/collection.hpp>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void dump_string(std::ostream& os, const std::string& s)
+{
+ // Scan for any special characters that necessitate quoting.
+ bool outer_quotes = s.find_first_of(",\"") != std::string::npos;
+
+ if (outer_quotes)
+ os << '"';
+
+ for (const char c : s)
+ {
+ switch (c)
+ {
+ case '"':
+ {
+ os << c << c;
+ break;
+ }
+ default:
+ os << c;
+ }
+ }
+
+ if (outer_quotes)
+ os << '"';
+}
+
+void dump_empty(std::ostream& /*os*/)
+{
+ // Do nothing.
+}
+
+}
+
+csv_dumper::csv_dumper(const document& doc) :
+ m_doc(doc), m_sep(','), m_quote('"')
+{
+}
+
+void csv_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 data_range = cxt.get_data_range(sheet_id);
+ if (!data_range.valid())
+ return;
+
+ ixion::abs_rc_range_t iter_range;
+ iter_range.first.column = 0;
+ iter_range.first.row = 0;
+ iter_range.last.column = data_range.last.column;
+ iter_range.last.row = data_range.last.row;
+
+ auto iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::horizontal, iter_range);
+
+ for (; iter.has(); iter.next())
+ {
+ const auto& cell = iter.get();
+
+ if (cell.col == 0 && cell.row > 0)
+ os << std::endl;
+
+ if (cell.col > 0)
+ os << m_sep;
+
+ dump_cell_value(os, cxt, cell, dump_string, dump_empty);
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/csv_dumper.hpp b/src/spreadsheet/csv_dumper.hpp
new file mode 100644
index 0000000..a03bbe9
--- /dev/null
+++ b/src/spreadsheet/csv_dumper.hpp
@@ -0,0 +1,38 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_CSV_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_CSV_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class csv_dumper
+{
+ const document& m_doc;
+ const char m_sep;
+ const char m_quote;
+
+public:
+ csv_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/debug_state_dumper.cpp b/src/spreadsheet/debug_state_dumper.cpp
new file mode 100644
index 0000000..c748924
--- /dev/null
+++ b/src/spreadsheet/debug_state_dumper.cpp
@@ -0,0 +1,460 @@
+/* -*- 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 "debug_state_dumper.hpp"
+#include "check_dumper.hpp"
+#include "document_impl.hpp"
+#include "sheet_impl.hpp"
+#include "ostream_utils.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/named_expressions_iterator.hpp>
+
+#include <fstream>
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void print_named_expressions(const ixion::model_context& cxt, ixion::named_expressions_iterator iter, std::ostream& os)
+{
+ auto resolver = ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &cxt);
+
+ if (!resolver)
+ return;
+
+ const ixion::abs_address_t origin{0, 0, 0};
+ ixion::print_config config;
+ config.display_sheet = ixion::display_sheet_t::always;
+
+ for (; iter.has(); iter.next())
+ {
+ auto name = iter.get();
+
+ std::string exp = ixion::print_formula_tokens(
+ config, cxt, origin, *resolver, name.expression->tokens);
+
+ os << "- name: " << *name.name << std::endl;
+ os << " origin: " << resolver->get_name(name.expression->origin, origin, true) << std::endl;
+ os << " expression: " << exp << std::endl;
+ }
+}
+
+} // anonymous namespace
+
+doc_debug_state_dumper::doc_debug_state_dumper(const document_impl& doc) : m_doc(doc)
+{
+}
+
+void doc_debug_state_dumper::dump(const fs::path& outdir) const
+{
+ dump_properties(outdir);
+ dump_styles(outdir);
+ dump_named_expressions(outdir);
+}
+
+void doc_debug_state_dumper::dump_properties(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "properties.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ of << "formula-grammar: " << m_doc.grammar << std::endl;
+ of << "origin-date: " << m_doc.origin_date << std::endl;
+ of << "output-precision: " << short(m_doc.doc_config.output_precision) << std::endl;
+}
+
+void doc_debug_state_dumper::dump_styles(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "styles.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ of << std::boolalpha;
+
+ auto to_string = [](std::optional<bool> v) -> std::string
+ {
+ if (!v)
+ return "(unset)";
+
+ return *v ? "true" : "false";
+ };
+
+ auto dump_xf = [&of,to_string](std::size_t i, const cell_format_t& xf)
+ {
+ of << " - id: " << i << std::endl
+ << " font: " << xf.font << std::endl
+ << " fill: " << xf.fill << std::endl
+ << " border: " << xf.border << std::endl
+ << " protection: " << xf.protection << std::endl
+ << " number-format: " << xf.number_format << std::endl
+ << " style-xf: " << xf.style_xf << std::endl
+ << " horizontal-alignment: " << xf.hor_align << std::endl
+ << " vertical-alignment: " << xf.ver_align << std::endl
+ << " apply-number-format: " << xf.apply_num_format << std::endl
+ << " apply-font: " << xf.apply_font << std::endl
+ << " apply-fill: " << xf.apply_fill << std::endl
+ << " apply-border: " << xf.apply_border << std::endl
+ << " apply-alignment: " << xf.apply_alignment << std::endl
+ << " apply-protection: " << xf.apply_protection << std::endl
+ << " wrap-text: " << to_string(xf.wrap_text) << std::endl
+ << " shrink-to-fit: " << to_string(xf.shrink_to_fit) << std::endl;
+ };
+
+ auto optional_value = [&of](std::string_view name, const auto& v, int level=2)
+ {
+ // v is of type std::optional<T>.
+
+ constexpr char q = '"';
+ constexpr const char* indent_unit_s = " ";
+
+ std::string indent = indent_unit_s;
+ for (int i = 0; i < level - 1; ++i)
+ indent += indent_unit_s;
+
+ of << indent << name << ": ";
+
+ if (v)
+ {
+ std::ostringstream os;
+ os << *v;
+ std::string s = os.str();
+ bool quote = s.find_first_of("#:-") != s.npos;
+ if (quote)
+ of << q << s << q;
+ else
+ of << s;
+ }
+ else
+ of << "(unset)";
+
+ of << std::endl;
+ };
+
+ auto dump_border = [&optional_value](const border_attrs_t& _attrs)
+ {
+ optional_value("style", _attrs.style, 3);
+ optional_value("color", _attrs.border_color, 3);
+ optional_value("width", _attrs.border_width, 3);
+ };
+
+ of << "cell-styles:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_styles_count(); ++i)
+ {
+ const cell_style_t* cs = m_doc.styles_store.get_cell_style(i);
+ assert(cs);
+
+ of << " - id: " << i << std::endl
+ << " name: " << cs->name << std::endl
+ << " display-name: " << cs->display_name << std::endl
+ << " parent: " << cs->parent_name << std::endl
+ << " xf: " << cs->xf << std::endl
+ << " builtin: " << cs->builtin << std::endl;
+ }
+
+ of << "cell-style-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_style_formats_count(); ++i)
+ {
+ const cell_format_t* xf = m_doc.styles_store.get_cell_style_format(i);
+ assert(xf);
+ dump_xf(i, *xf);
+ }
+
+ of << "cell-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_cell_formats_count(); ++i)
+ {
+ const cell_format_t* xf = m_doc.styles_store.get_cell_format(i);
+ assert(xf);
+ dump_xf(i, *xf);
+ }
+
+ of << "fonts:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_font_count(); ++i)
+ {
+ const font_t* font = m_doc.styles_store.get_font(i);
+ assert(font);
+
+ of << " - id: " << i << std::endl;
+ optional_value("name", font->name, 2);
+ optional_value("name-asian", font->name_asian, 2);
+ optional_value("name-complex", font->name_complex, 2);
+ optional_value("size", font->size, 2);
+ optional_value("size-asian", font->size_asian, 2);
+ optional_value("size-complex", font->size_complex, 2);
+ optional_value("bold", font->bold, 2);
+ optional_value("bold-asian", font->bold_asian, 2);
+ optional_value("bold-complex", font->bold_complex, 2);
+ optional_value("italic", font->italic, 2);
+ optional_value("italic-asian", font->italic_asian, 2);
+ optional_value("italic-complex", font->italic_complex, 2);
+ optional_value("underline-style", font->underline_style, 2);
+ optional_value("underline-width", font->underline_width, 2);
+ optional_value("underline-mode", font->underline_mode, 2);
+ optional_value("underline-type", font->underline_type, 2);
+ optional_value("underline-color", font->underline_color, 2);
+ optional_value("color", font->color, 2);
+ optional_value("strikethrough-style", font->strikethrough_style, 2);
+ optional_value("strikethrough-width", font->strikethrough_width, 2);
+ optional_value("strikethrough-type", font->strikethrough_type, 2);
+ optional_value("strikethrough-text", font->strikethrough_text, 2);
+ }
+
+ of << "fills:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_fill_count(); ++i)
+ {
+ const fill_t* fill = m_doc.styles_store.get_fill(i);
+ assert(fill);
+
+ of << " - id: " << i << std::endl;
+ optional_value("pattern", fill->pattern_type, 2);
+ optional_value("fg-color", fill->fg_color, 2);
+ optional_value("bg-color", fill->bg_color, 2);
+ }
+
+ of << "borders:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_border_count(); ++i)
+ {
+ const border_t* border = m_doc.styles_store.get_border(i);
+ assert(border);
+
+ of << " - id: " << i << std::endl;
+
+ of << " top:" << std::endl;
+ dump_border(border->top);
+ of << " bottom:" << std::endl;
+ dump_border(border->bottom);
+ of << " left:" << std::endl;
+ dump_border(border->left);
+ of << " right:" << std::endl;
+ dump_border(border->right);
+ of << " diagonal:" << std::endl;
+ dump_border(border->diagonal);
+ of << " diagonal-bl-tr:" << std::endl;
+ dump_border(border->diagonal_bl_tr);
+ of << " diagonal-tl-br:" << std::endl;
+ dump_border(border->diagonal_tl_br);
+ }
+
+ of << "protections:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_protection_count(); ++i)
+ {
+ const protection_t* prot = m_doc.styles_store.get_protection(i);
+ assert(prot);
+
+ of << " - id: " << i << std::endl;
+ optional_value("locked", prot->locked, 2);
+ optional_value("hidden", prot->hidden, 2);
+ optional_value("print-content", prot->print_content, 2);
+ optional_value("formula-hidden", prot->formula_hidden, 2);
+ }
+
+ of << "number-formats:" << std::endl;
+
+ for (std::size_t i = 0; i < m_doc.styles_store.get_number_format_count(); ++i)
+ {
+ const number_format_t* numfmt = m_doc.styles_store.get_number_format(i);
+ assert(numfmt);
+
+ of << " - id: " << i << std::endl;
+ optional_value("identifier", numfmt->identifier, 2);
+ optional_value("format-string", numfmt->format_string, 2);
+ }
+}
+
+void doc_debug_state_dumper::dump_named_expressions(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "named-expressions.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ print_named_expressions(m_doc.context, m_doc.context.get_named_expressions_iterator(), of);
+}
+
+sheet_debug_state_dumper::sheet_debug_state_dumper(const sheet_impl& sheet, std::string_view sheet_name) :
+ m_sheet(sheet), m_sheet_name(sheet_name) {}
+
+void sheet_debug_state_dumper::dump(const fs::path& outdir) const
+{
+ dump_cell_values(outdir);
+ dump_cell_formats(outdir);
+ dump_column_formats(outdir);
+ dump_row_formats(outdir);
+ dump_column_widths(outdir);
+ dump_row_heights(outdir);
+ dump_auto_filter(outdir);
+ dump_named_expressions(outdir);
+}
+
+void sheet_debug_state_dumper::dump_cell_values(const fs::path& outdir) const
+{
+ check_dumper dumper{m_sheet, m_sheet_name};
+ fs::path outpath = outdir / "cell-values.txt";
+ std::ofstream of{outpath.native()};
+ if (of)
+ dumper.dump(of);
+}
+
+void sheet_debug_state_dumper::dump_cell_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "cell-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ std::vector<col_t> columns;
+ for (const auto& node : m_sheet.cell_formats)
+ columns.push_back(node.first);
+
+ std::sort(columns.begin(), columns.end());
+
+ for (const col_t col : columns)
+ {
+ of << "column: " << col << std::endl;
+
+ auto it = m_sheet.cell_formats.find(col);
+ assert(it != m_sheet.cell_formats.end());
+ const segment_row_index_type& rows = *it->second;
+
+ for (const auto& seg : rows.segment_range())
+ {
+ // NB: end position is not inclusive.
+ of << " - rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+ }
+}
+
+void sheet_debug_state_dumper::dump_column_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "column-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.column_formats.segment_range())
+ {
+ of << "- columns: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_row_formats(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "row-formats.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.row_formats.segment_range())
+ {
+ of << "- rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " xf: " << seg.value << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_column_widths(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "column-widths.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.col_widths.segment_range())
+ {
+ of << "- columns: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " width: ";
+
+ if (seg.value == get_default_column_width())
+ of << "(default)";
+ else
+ of << seg.value;
+
+ of << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_row_heights(const fs::path& outdir) const
+{
+ fs::path outpath = outdir / "row-heights.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ for (const auto& seg : m_sheet.row_heights.segment_range())
+ {
+ of << "- rows: " << seg.start << '-' << (seg.end - 1) << std::endl;
+ of << " height: ";
+
+ if (seg.value == get_default_row_height())
+ of << "(default)";
+ else
+ of << seg.value;
+
+ of << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_auto_filter(const fs::path& outdir) const
+{
+ if (!m_sheet.auto_filter_data)
+ return;
+
+ fs::path outpath = outdir / "auto-filter.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ const auto_filter_t& data = *m_sheet.auto_filter_data;
+
+ auto resolver = ixion::formula_name_resolver::get(
+ ixion::formula_name_resolver_t::excel_a1, nullptr);
+
+ if (!resolver)
+ return;
+
+ ixion::abs_address_t origin;
+ ixion::range_t name{data.range};
+ name.set_absolute(false);
+
+ of << "range: " << resolver->get_name(name, origin, false) << "\n";
+ of << "columns:\n";
+
+ for (const auto& [col, cdata] : data.columns)
+ {
+ of << "- column: " << col << "\n";
+ of << " match-values:\n";
+
+ for (const auto& v : cdata.match_values)
+ of << " - " << v << std::endl;
+ }
+}
+
+void sheet_debug_state_dumper::dump_named_expressions(const fs::path& outdir) const
+{
+ const fs::path outpath = outdir / "named-expressions.yaml";
+ std::ofstream of{outpath.native()};
+ if (!of)
+ return;
+
+ const ixion::model_context& cxt = m_sheet.doc.get_model_context();
+ print_named_expressions(cxt, cxt.get_named_expressions_iterator(m_sheet.sheet_id), of);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/debug_state_dumper.hpp b/src/spreadsheet/debug_state_dumper.hpp
new file mode 100644
index 0000000..7e895ca
--- /dev/null
+++ b/src/spreadsheet/debug_state_dumper.hpp
@@ -0,0 +1,61 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include "filesystem_env.hpp"
+
+#include <string_view>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+struct document_impl;
+struct sheet_impl;
+
+class doc_debug_state_dumper
+{
+ const document_impl& m_doc;
+
+public:
+ doc_debug_state_dumper(const document_impl& doc);
+
+ void dump(const fs::path& outdir) const;
+
+private:
+ void dump_properties(const fs::path& outdir) const;
+ void dump_styles(const fs::path& outdir) const;
+ void dump_named_expressions(const fs::path& outdir) const;
+};
+
+class sheet_debug_state_dumper
+{
+ const sheet_impl& m_sheet;
+ std::string_view m_sheet_name;
+
+public:
+ sheet_debug_state_dumper(const sheet_impl& sheet, std::string_view sheet_name);
+
+ void dump(const fs::path& outdir) const;
+
+private:
+ void dump_cell_values(const fs::path& outdir) const;
+ void dump_cell_formats(const fs::path& outdir) const;
+ void dump_column_formats(const fs::path& outdir) const;
+ void dump_row_formats(const fs::path& outdir) const;
+ void dump_column_widths(const fs::path& outdir) const;
+ void dump_row_heights(const fs::path& outdir) const;
+ void dump_auto_filter(const fs::path& outdir) const;
+ void dump_named_expressions(const fs::path& outdir) const;
+};
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document.cpp b/src/spreadsheet/document.cpp
new file mode 100644
index 0000000..dc8daec
--- /dev/null
+++ b/src/spreadsheet/document.cpp
@@ -0,0 +1,526 @@
+/* -*- 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 "document_impl.hpp"
+#include "debug_state_dumper.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <map>
+#include <algorithm>
+
+using namespace std;
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class find_sheet_by_name
+{
+ std::string_view m_name;
+public:
+ find_sheet_by_name(std::string_view name) : m_name(name) {}
+ bool operator() (const std::unique_ptr<detail::sheet_item>& v) const
+ {
+ return v->name == m_name;
+ }
+};
+
+}
+
+document::document(const range_size_t& sheet_size) : mp_impl(std::make_unique<detail::document_impl>(*this, sheet_size)) {}
+
+document::~document() {}
+
+shared_strings& document::get_shared_strings()
+{
+ return mp_impl->ss_store;
+}
+
+const shared_strings& document::get_shared_strings() const
+{
+ return mp_impl->ss_store;
+}
+
+styles& document::get_styles()
+{
+ return mp_impl->styles_store;
+}
+
+const styles& document::get_styles() const
+{
+ return mp_impl->styles_store;
+}
+
+pivot_collection& document::get_pivot_collection()
+{
+ return mp_impl->pivots;
+}
+
+const pivot_collection& document::get_pivot_collection() const
+{
+ return mp_impl->pivots;
+}
+
+ixion::model_context& document::get_model_context()
+{
+ return mp_impl->context;
+}
+
+const ixion::model_context& document::get_model_context() const
+{
+ return mp_impl->context;
+}
+
+const document_config& document::get_config() const
+{
+ return mp_impl->doc_config;
+}
+
+void document::set_config(const document_config& cfg)
+{
+ mp_impl->doc_config = cfg;
+ ixion::config ixion_cfg = mp_impl->context.get_config();
+ ixion_cfg.output_precision = cfg.output_precision;
+ mp_impl->context.set_config(ixion_cfg);
+}
+
+string_pool& document::get_string_pool()
+{
+ return mp_impl->string_pool_store;
+}
+
+const string_pool& document::get_string_pool() const
+{
+ return mp_impl->string_pool_store;
+}
+
+void document::insert_table(table_t* p)
+{
+ if (!p)
+ return;
+
+ std::string_view name = p->name;
+ mp_impl->tables.emplace(name, std::unique_ptr<table_t>(p));
+}
+
+const table_t* document::get_table(std::string_view name) const
+{
+ auto it = mp_impl->tables.find(name);
+ return it == mp_impl->tables.end() ? nullptr : it->second.get();
+}
+
+void document::finalize_import()
+{
+ std::for_each(mp_impl->sheets.begin(), mp_impl->sheets.end(),
+ [](std::unique_ptr<detail::sheet_item>& sh)
+ {
+ sh->data.finalize_import();
+ }
+ );
+
+ mp_impl->styles_store.finalize_import();
+}
+
+sheet* document::append_sheet(std::string_view sheet_name)
+{
+ std::string_view sheet_name_safe = mp_impl->string_pool_store.intern(sheet_name).first;
+ sheet_t sheet_index = static_cast<sheet_t>(mp_impl->sheets.size());
+
+ mp_impl->sheets.push_back(
+ std::make_unique<detail::sheet_item>(*this, sheet_name_safe, sheet_index));
+
+ mp_impl->context.append_sheet(std::string{sheet_name_safe});
+
+ return &mp_impl->sheets.back()->data;
+}
+
+sheet* document::get_sheet(std::string_view sheet_name)
+{
+ const sheet* sh = const_cast<const document*>(this)->get_sheet(sheet_name);
+ return const_cast<sheet*>(sh);
+}
+
+const sheet* document::get_sheet(std::string_view sheet_name) const
+{
+ auto it = std::find_if(
+ mp_impl->sheets.begin(), mp_impl->sheets.end(), find_sheet_by_name(sheet_name));
+
+ if (it == mp_impl->sheets.end())
+ return nullptr;
+
+ return &(*it)->data;
+}
+
+sheet* document::get_sheet(sheet_t sheet_pos)
+{
+ const sheet* sh = const_cast<const document*>(this)->get_sheet(sheet_pos);
+ return const_cast<sheet*>(sh);
+}
+
+const sheet* document::get_sheet(sheet_t sheet_pos) const
+{
+ if (static_cast<size_t>(sheet_pos) >= mp_impl->sheets.size())
+ return nullptr;
+
+ return &mp_impl->sheets[sheet_pos]->data;
+}
+
+void document::recalc_formula_cells()
+{
+ ixion::abs_range_set_t empty;
+
+ ixion::model_context& cxt = get_model_context();
+ std::vector<ixion::abs_range_t> sorted = ixion::query_and_sort_dirty_cells(
+ cxt, empty, &mp_impl->dirty_cells);
+ ixion::calculate_sorted_cells(cxt, sorted, 0);
+}
+
+void document::clear()
+{
+ mp_impl = std::make_unique<detail::document_impl>(*this, get_sheet_size());
+}
+
+void document::dump(dump_format_t format, const std::string& output) const
+{
+ if (format == dump_format_t::none)
+ return;
+
+ if (format == dump_format_t::check)
+ {
+ // For this output, we write to a single file.
+ std::ostream* ostrm = &std::cout;
+ std::unique_ptr<std::ofstream> fs;
+
+ if (!output.empty())
+ {
+ if (fs::is_directory(output))
+ {
+ std::ostringstream os;
+ os << "Output file path points to an existing directory.";
+ throw std::invalid_argument(os.str());
+ }
+
+ // Output to stdout when output path is not given.
+ fs = std::make_unique<std::ofstream>(output.data());
+ ostrm = fs.get();
+ }
+
+ dump_check(*ostrm);
+ return;
+ }
+
+ if (output.empty())
+ throw std::invalid_argument("No output directory.");
+
+ if (fs::exists(output))
+ {
+ if (!fs::is_directory(output))
+ {
+ std::ostringstream os;
+ os << "A file named '" << output << "' already exists, and is not a directory.";
+ throw std::invalid_argument(os.str());
+ }
+ }
+ else
+ fs::create_directory(output);
+
+ switch (format)
+ {
+ case dump_format_t::csv:
+ dump_csv(output);
+ break;
+ case dump_format_t::flat:
+ dump_flat(output);
+ break;
+ case dump_format_t::html:
+ dump_html(output);
+ break;
+ case dump_format_t::json:
+ dump_json(output);
+ break;
+ case dump_format_t::debug_state:
+ dump_debug_state(output);
+ break;
+ // coverity[dead_error_line] - following conditions exist to avoid compiler warning
+ case dump_format_t::none:
+ case dump_format_t::unknown:
+ break;
+ default:
+ ;
+ }
+}
+
+void document::dump_check(ostream& os) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ sheet->data.dump_check(os, sheet->name);
+}
+
+void document::dump_flat(const string& outdir) const
+{
+ cout << "----------------------------------------------------------------------" << endl;
+ cout << " Document content summary" << endl;
+ cout << "----------------------------------------------------------------------" << endl;
+ mp_impl->ss_store.dump(cout);
+
+ cout << "number of sheets: " << mp_impl->sheets.size() << endl;
+
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".txt");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ file << "---" << endl;
+ file << "Sheet name: " << sheet->name << endl;
+ sheet->data.dump_flat(file);
+ }
+}
+
+void document::dump_html(const string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".html");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_html(file);
+ }
+}
+
+void document::dump_json(const string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".json");
+
+ std::ofstream file(outpath.native());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_json(file);
+ }
+}
+
+void document::dump_csv(const std::string& outdir) const
+{
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath{outdir};
+ outpath /= std::string{sheet->name};
+ outpath.replace_extension(".csv");
+
+ ofstream file(outpath.c_str());
+ if (!file)
+ {
+ cerr << "failed to create file: " << outpath << endl;
+ return;
+ }
+
+ sheet->data.dump_csv(file);
+ }
+}
+
+void document::dump_debug_state(const std::string& outdir) const
+{
+ detail::doc_debug_state_dumper dumper{*mp_impl};
+ fs::path output_dir{outdir};
+ dumper.dump(output_dir);
+
+ for (const std::unique_ptr<detail::sheet_item>& sheet : mp_impl->sheets)
+ {
+ fs::path outpath = output_dir;
+ outpath /= std::string{sheet->name};
+ fs::create_directories(outpath);
+ sheet->data.dump_debug_state(outpath.string(), sheet->name);
+ }
+}
+
+sheet_t document::get_sheet_index(std::string_view name) const
+{
+ auto it = std::find_if(
+ mp_impl->sheets.begin(), mp_impl->sheets.end(), find_sheet_by_name(name));
+
+ if (it == mp_impl->sheets.end())
+ return ixion::invalid_sheet;
+
+ auto it_beg = mp_impl->sheets.begin();
+ size_t pos = std::distance(it_beg, it);
+ return static_cast<sheet_t>(pos);
+}
+
+std::string_view document::get_sheet_name(sheet_t sheet_pos) const
+{
+ if (sheet_pos < 0)
+ return std::string_view{};
+
+ size_t pos = static_cast<size_t>(sheet_pos);
+ if (pos >= mp_impl->sheets.size())
+ return std::string_view{};
+
+ return mp_impl->sheets[pos]->name;
+}
+
+void document::set_sheet_name(sheet_t sheet_pos, std::string name)
+{
+ assert(mp_impl->sheets.size() == mp_impl->context.get_sheet_count());
+
+ std::string_view name_interned = mp_impl->string_pool_store.intern(name).first;
+ mp_impl->context.set_sheet_name(sheet_pos, std::move(name)); // will throw on invalid name or position
+ mp_impl->sheets[sheet_pos]->name = name_interned;
+}
+
+range_size_t document::get_sheet_size() const
+{
+ ixion::rc_size_t ss = mp_impl->context.get_sheet_size();
+ range_size_t ret;
+ ret.rows = ss.row;
+ ret.columns = ss.column;
+ return ret;
+}
+
+void document::set_sheet_size(const range_size_t& sheet_size)
+{
+ mp_impl->context.set_sheet_size({sheet_size.rows, sheet_size.columns});
+}
+
+size_t document::get_sheet_count() const
+{
+ return mp_impl->sheets.size();
+}
+
+void document::set_origin_date(int year, int month, int day)
+{
+ mp_impl->origin_date.year = year;
+ mp_impl->origin_date.month = month;
+ mp_impl->origin_date.day = day;
+}
+
+date_time_t document::get_origin_date() const
+{
+ return mp_impl->origin_date;
+}
+
+void document::set_formula_grammar(formula_grammar_t grammar)
+{
+ if (mp_impl->grammar == grammar)
+ return;
+
+ mp_impl->grammar = grammar;
+
+ ixion::formula_name_resolver_t resolver_type_global = ixion::formula_name_resolver_t::unknown;
+ ixion::formula_name_resolver_t resolver_type_named_exp_base = ixion::formula_name_resolver_t::unknown;
+ ixion::formula_name_resolver_t resolver_type_named_range = ixion::formula_name_resolver_t::unknown;
+ char arg_sep = 0;
+
+ switch (mp_impl->grammar)
+ {
+ case formula_grammar_t::xls_xml:
+ resolver_type_global = ixion::formula_name_resolver_t::excel_r1c1;
+ arg_sep = ',';
+ break;
+ case formula_grammar_t::xlsx:
+ resolver_type_global = ixion::formula_name_resolver_t::excel_a1;
+ arg_sep = ',';
+ break;
+ case formula_grammar_t::ods:
+ resolver_type_global = ixion::formula_name_resolver_t::odff;
+ resolver_type_named_exp_base = ixion::formula_name_resolver_t::calc_a1;
+ resolver_type_named_range = ixion::formula_name_resolver_t::odf_cra;
+ arg_sep = ';';
+ break;
+ case formula_grammar_t::gnumeric:
+ // TODO : Use Excel A1 name resolver for now.
+ resolver_type_global = ixion::formula_name_resolver_t::excel_a1;
+ arg_sep = ',';
+ break;
+ default:
+ ;
+ }
+
+ mp_impl->name_resolver_global.reset();
+ mp_impl->name_resolver_named_exp_base.reset();
+
+ if (resolver_type_global != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_global =
+ ixion::formula_name_resolver::get(resolver_type_global, &mp_impl->context);
+
+ if (resolver_type_named_exp_base != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_named_exp_base =
+ ixion::formula_name_resolver::get(resolver_type_named_exp_base, &mp_impl->context);
+ }
+
+ if (resolver_type_named_range != ixion::formula_name_resolver_t::unknown)
+ {
+ mp_impl->name_resolver_named_range =
+ ixion::formula_name_resolver::get(resolver_type_named_range, &mp_impl->context);
+ }
+
+ ixion::config cfg = mp_impl->context.get_config();
+ cfg.sep_function_arg = arg_sep;
+ cfg.output_precision = mp_impl->doc_config.output_precision;
+ mp_impl->context.set_config(cfg);
+ }
+}
+
+formula_grammar_t document::get_formula_grammar() const
+{
+ return mp_impl->grammar;
+}
+
+const ixion::formula_name_resolver* document::get_formula_name_resolver(formula_ref_context_t cxt) const
+{
+ switch (cxt)
+ {
+ case formula_ref_context_t::global:
+ return mp_impl->name_resolver_global.get();
+ case formula_ref_context_t::named_expression_base:
+ if (mp_impl->name_resolver_named_exp_base)
+ return mp_impl->name_resolver_named_exp_base.get();
+ break;
+ case formula_ref_context_t::named_range:
+ if (mp_impl->name_resolver_named_range)
+ return mp_impl->name_resolver_named_range.get();
+ break;
+ default:
+ ;
+ }
+
+ return mp_impl->name_resolver_global.get();
+}
+
+void document::insert_dirty_cell(const ixion::abs_address_t& pos)
+{
+ mp_impl->dirty_cells.insert(pos);
+}
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_impl.cpp b/src/spreadsheet/document_impl.cpp
new file mode 100644
index 0000000..db6050a
--- /dev/null
+++ b/src/spreadsheet/document_impl.cpp
@@ -0,0 +1,232 @@
+/* -*- 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 "document_impl.hpp"
+
+#include <algorithm>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+class find_column_by_name
+{
+ std::string_view m_name;
+public:
+ find_column_by_name(std::string_view name) : m_name(name) {}
+
+ bool operator() (const table_column_t& col) const
+ {
+ return col.name == m_name;
+ }
+};
+
+void adjust_row_range(ixion::abs_range_t& range, const table_t& tab, ixion::table_areas_t areas)
+{
+ bool headers = (areas & ixion::table_area_headers);
+ bool data = (areas & ixion::table_area_data);
+ bool totals = (areas & ixion::table_area_totals);
+
+ if (headers)
+ {
+ if (data)
+ {
+ if (totals)
+ {
+ // All areas.
+ return;
+ }
+
+ // Headers + data
+ range.last.row -= tab.totals_row_count;
+ return;
+ }
+
+ if (totals)
+ {
+ // Header + total is invalid.
+ range = ixion::abs_range_t(ixion::abs_range_t::invalid);
+ return;
+ }
+
+ // Headers only.
+ range.last.row = range.first.row;
+ return;
+ }
+
+ if (data)
+ {
+ ++range.first.row;
+
+ if (totals)
+ {
+ // Data + total
+ return;
+ }
+
+ // Data only
+ range.last.row -= tab.totals_row_count;
+ return;
+ }
+
+ if (totals)
+ {
+ // Total only
+ if (!tab.totals_row_count)
+ {
+ // This table has not total rows. Return empty range.
+ range = ixion::abs_range_t();
+ return;
+ }
+
+ range.first.row = range.last.row - tab.totals_row_count - 1;
+ return;
+ }
+
+ // Empty range.
+ range = ixion::abs_range_t();
+}
+
+}
+
+sheet_item::sheet_item(document& doc, std::string_view _name, sheet_t sheet_index) :
+ name(_name), data(doc, sheet_index) {}
+
+
+const table_t* ixion_table_handler::find_table(const ixion::abs_address_t& pos) const
+{
+ auto it = m_tables.begin(), it_end = m_tables.end();
+ for (; it != it_end; ++it)
+ {
+ const table_t* p = it->second.get();
+ if (p->range.contains(pos))
+ return p;
+ }
+
+ return nullptr;
+}
+
+std::string_view ixion_table_handler::get_string(ixion::string_id_t sid) const
+{
+ if (sid == ixion::empty_string_id)
+ return std::string_view{};
+
+ const std::string* p = m_context.get_string(sid);
+ if (!p || p->empty())
+ return std::string_view{};
+
+ return std::string_view(p->data(), p->size());
+}
+
+col_t ixion_table_handler::find_column(const table_t& tab, std::string_view name, size_t offset) const
+{
+ if (offset >= tab.columns.size())
+ return -1;
+
+ table_t::columns_type::const_iterator it_beg = tab.columns.begin();
+ table_t::columns_type::const_iterator it_end = tab.columns.end();
+
+ std::advance(it_beg, offset);
+ table_t::columns_type::const_iterator it =
+ std::find_if(it_beg, it_end, find_column_by_name(name));
+
+ if (it == it_end)
+ // not found.
+ return -1;
+
+ size_t dist = std::distance(tab.columns.begin(), it);
+ return tab.range.first.column + dist;
+}
+
+ixion::abs_range_t ixion_table_handler::get_range_from_table(
+ const table_t& tab, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ if (column_first != ixion::empty_string_id)
+ {
+ std::string_view col1_name = get_string(column_first);
+ if (col1_name.empty())
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ col_t col1_index = find_column(tab, col1_name, 0);
+ if (col1_index < 0)
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ if (column_last != ixion::empty_string_id)
+ {
+ std::string_view col2_name = get_string(column_last);
+ if (!col2_name.empty())
+ {
+ // column range table reference.
+ col_t col2_index = find_column(tab, col2_name, col1_index);
+ ixion::abs_range_t range = tab.range;
+ range.first.column = col1_index;
+ range.last.column = col2_index;
+ adjust_row_range(range, tab, areas);
+ return range;
+ }
+ }
+
+ // single column table reference.
+ ixion::abs_range_t range = tab.range;
+ range.first.column = range.last.column = col1_index;
+ adjust_row_range(range, tab, areas);
+ return range;
+ }
+
+ return ixion::abs_range_t();
+}
+
+ixion_table_handler::ixion_table_handler(const ixion::model_context& cxt, const table_store_type& tables) :
+ m_context(cxt), m_tables(tables) {}
+
+ixion::abs_range_t ixion_table_handler::get_range(
+ const ixion::abs_address_t& pos, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ const table_t* tab = find_table(pos);
+ if (!tab)
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ return get_range_from_table(*tab, column_first, column_last, areas);
+
+}
+
+ixion::abs_range_t ixion_table_handler::get_range(
+ ixion::string_id_t table, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const
+{
+ std::string_view tab_name = get_string(table);
+ if (tab_name.empty())
+ // no table name given.
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ auto it = m_tables.find(tab_name);
+ if (it == m_tables.end())
+ // no table by this name found.
+ return ixion::abs_range_t(ixion::abs_range_t::invalid);
+
+ const table_t* tab = it->second.get();
+ return get_range_from_table(*tab, column_first, column_last, areas);
+}
+
+document_impl::document_impl(document& _doc, const range_size_t& sheet_size) :
+ doc(_doc),
+ context({sheet_size.rows, sheet_size.columns}),
+ styles_store(),
+ ss_store(context),
+ pivots(doc),
+ name_resolver_global(ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &context)),
+ grammar(formula_grammar_t::xlsx),
+ table_handler(context, tables)
+{
+ context.set_table_handler(&table_handler);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_impl.hpp b/src/spreadsheet/document_impl.hpp
new file mode 100644
index 0000000..44ee91f
--- /dev/null
+++ b/src/spreadsheet/document_impl.hpp
@@ -0,0 +1,104 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/auto_filter.hpp>
+#include <orcus/spreadsheet/config.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/pivot.hpp>
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/string_pool.hpp>
+#include <orcus/types.hpp>
+
+#include <ixion/config.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/interface/table_handler.hpp>
+#include <ixion/matrix.hpp>
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+/**
+ * Single sheet entry which consists of a sheet name and a sheet data.
+ */
+struct sheet_item
+{
+ sheet_item(const sheet_item&) = delete;
+ sheet_item& operator=(const sheet_item&) = delete;
+
+ std::string_view name;
+ sheet data;
+ sheet_item(document& doc, std::string_view _name, sheet_t sheet_index);
+};
+
+typedef std::map<std::string_view, std::unique_ptr<table_t>> table_store_type;
+typedef std::vector<std::unique_ptr<sheet_item>> sheet_items_type;
+
+class ixion_table_handler : public ixion::iface::table_handler
+{
+ const ixion::model_context& m_context;
+ const table_store_type& m_tables;
+
+ const table_t* find_table(const ixion::abs_address_t& pos) const;
+
+ std::string_view get_string(ixion::string_id_t sid) const;
+
+ col_t find_column(const table_t& tab, std::string_view name, size_t offset) const;
+
+ ixion::abs_range_t get_range_from_table(
+ const table_t& tab, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const;
+
+public:
+ ixion_table_handler(const ixion::model_context& cxt, const table_store_type& tables);
+
+ virtual ixion::abs_range_t get_range(
+ const ixion::abs_address_t& pos, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const override;
+
+ virtual ixion::abs_range_t get_range(
+ ixion::string_id_t table, ixion::string_id_t column_first, ixion::string_id_t column_last,
+ ixion::table_areas_t areas) const override;
+};
+
+struct document_impl
+{
+ document_impl(const document_impl&) = delete;
+ document_impl& operator=(const document_impl&) = delete;
+
+ document& doc;
+
+ document_config doc_config;
+ string_pool string_pool_store;
+ ixion::model_context context;
+ date_time_t origin_date;
+ sheet_items_type sheets;
+ styles styles_store;
+ shared_strings ss_store;
+ ixion::abs_range_set_t dirty_cells;
+
+ pivot_collection pivots;
+
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_global;
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_named_exp_base;
+ std::unique_ptr<ixion::formula_name_resolver> name_resolver_named_range;
+ formula_grammar_t grammar;
+
+ table_store_type tables;
+ ixion_table_handler table_handler;
+
+ document_impl(document& _doc, const range_size_t& sheet_size);
+};
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/document_types.cpp b/src/spreadsheet/document_types.cpp
new file mode 100644
index 0000000..88e0724
--- /dev/null
+++ b/src/spreadsheet/document_types.cpp
@@ -0,0 +1,77 @@
+/* -*- 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 <orcus/spreadsheet/document_types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+color_t::color_t() :
+ alpha(0), red(0), green(0), blue(0)
+{
+}
+
+color_t::color_t(color_elem_t _red, color_elem_t _green, color_elem_t _blue) :
+ alpha(255), red(_red), green(_green), blue(_blue)
+{
+}
+
+color_t::color_t(color_elem_t _alpha, color_elem_t _red, color_elem_t _green, color_elem_t _blue) :
+ alpha(_alpha), red(_red), green(_green), blue(_blue)
+{
+}
+
+void color_t::reset()
+{
+ *this = color_t();
+}
+
+bool color_t::operator==(const color_t& other) const
+{
+ return alpha == other.alpha && red == other.red && green == other.green && blue == other.blue;
+}
+
+bool color_t::operator!=(const color_t& other) const
+{
+ return !operator==(other);
+}
+
+format_run::format_run() :
+ pos(0), size(0),
+ font_size(0),
+ bold(false), italic(false) {}
+
+void format_run::reset()
+{
+ pos = 0;
+ size = 0;
+ font = std::string_view{};
+ font_size = 0;
+ bold = false;
+ italic = false;
+ color = color_t();
+}
+
+bool format_run::formatted() const
+{
+ if (bold || italic)
+ return true;
+
+ if (font_size)
+ return true;
+
+ if (!font.empty())
+ return true;
+
+ if (color.alpha || color.red || color.green || color.blue)
+ return true;
+
+ return false;
+}
+
+}} // namespace orcus::spreadsheet
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/dumper_global.cpp b/src/spreadsheet/dumper_global.cpp
new file mode 100644
index 0000000..f500f3c
--- /dev/null
+++ b/src/spreadsheet/dumper_global.cpp
@@ -0,0 +1,87 @@
+/* -*- 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 "dumper_global.hpp"
+#include "number_format.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+void dump_cell_value(
+ std::ostream& os, const ixion::model_context& cxt, const ixion::model_iterator::cell& cell,
+ func_str_handler str_handler,
+ func_empty_handler empty_handler)
+{
+ switch (cell.type)
+ {
+ case ixion::celltype_t::empty:
+ empty_handler(os);
+ break;
+ case ixion::celltype_t::boolean:
+ {
+ os << (std::get<bool>(cell.value) ? "true" : "false");
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ {
+ format_to_file_output(os, std::get<double>(cell.value));
+ break;
+ }
+ case ixion::celltype_t::string:
+ {
+ const std::string* p = cxt.get_string(std::get<ixion::string_id_t>(cell.value));
+ assert(p);
+ str_handler(os, *p);
+ break;
+ }
+ case ixion::celltype_t::formula:
+ {
+ const ixion::formula_cell* fc = std::get<const ixion::formula_cell*>(cell.value);
+ assert(fc);
+ ixion::formula_result res;
+
+ try
+ {
+ res = fc->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ }
+ catch (const std::exception&)
+ {
+ os << "\"#RES!\"";
+ break;
+ }
+
+ switch (res.get_type())
+ {
+ case ixion::formula_result::result_type::value:
+ format_to_file_output(os, res.get_value());
+ break;
+ case ixion::formula_result::result_type::string:
+ {
+ const std::string& s = res.get_string();
+ str_handler(os, s);
+ }
+ break;
+ case ixion::formula_result::result_type::error:
+ os << "\"#ERR!\"";
+ break;
+ default:
+ ;
+ }
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/dumper_global.hpp b/src/spreadsheet/dumper_global.hpp
new file mode 100644
index 0000000..96c5afc
--- /dev/null
+++ b/src/spreadsheet/dumper_global.hpp
@@ -0,0 +1,31 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_DUMPER_GLOBAL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_DUMPER_GLOBAL_HPP
+
+#include <ixion/model_context.hpp>
+#include <ixion/model_iterator.hpp>
+
+#include <ostream>
+#include <functional>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+using func_str_handler = std::function<void(std::ostream&, const std::string&)>;
+using func_empty_handler = std::function<void(std::ostream&)>;
+
+void dump_cell_value(
+ std::ostream& os, const ixion::model_context& cxt, const ixion::model_iterator::cell& cell,
+ func_str_handler str_handler,
+ func_empty_handler empty_handler);
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory.cpp b/src/spreadsheet/factory.cpp
new file mode 100644
index 0000000..9cd7884
--- /dev/null
+++ b/src/spreadsheet/factory.cpp
@@ -0,0 +1,410 @@
+/* -*- 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 "orcus/spreadsheet/factory.hpp"
+
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/spreadsheet/sheet.hpp>
+#include <orcus/spreadsheet/document.hpp>
+#include <orcus/spreadsheet/view.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/string_pool.hpp>
+
+#include "factory_pivot.hpp"
+#include "factory_shared_strings.hpp"
+#include "factory_sheet.hpp"
+#include "global_settings.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_tokens.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+#include <sstream>
+#include <iostream>
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class import_ref_resolver : public iface::import_reference_resolver
+{
+ document& m_doc;
+ const ixion::formula_name_resolver* m_resolver;
+
+public:
+ import_ref_resolver(document& doc) : m_doc(doc), m_resolver(nullptr) {}
+
+ void set_formula_ref_context(formula_ref_context_t cxt)
+ {
+ m_resolver = m_doc.get_formula_name_resolver(cxt);
+ }
+
+ virtual src_address_t resolve_address(std::string_view address) override
+ {
+ if (!m_resolver)
+ throw std::runtime_error("import_ref_resolver::resolve_address: formula resolver is null!");
+
+ ixion::formula_name_t name = m_resolver->resolve(address, ixion::abs_address_t());
+
+ if (name.type != ixion::formula_name_t::cell_reference)
+ {
+ std::ostringstream os;
+ os << address << " is not a valid cell address.";
+ throw orcus::invalid_arg_error(os.str());
+ }
+
+ auto addr = std::get<ixion::address_t>(name.value);
+ src_address_t ret;
+ ret.sheet = addr.sheet;
+ ret.column = addr.column;
+ ret.row = addr.row;
+ return ret;
+ }
+
+ virtual src_range_t resolve_range(std::string_view range) override
+ {
+ if (!m_resolver)
+ throw std::runtime_error("import_ref_resolver::resolve_range: formula resolver is null!");
+
+ ixion::formula_name_t name = m_resolver->resolve(range, ixion::abs_address_t());
+
+ switch (name.type)
+ {
+ case ixion::formula_name_t::range_reference:
+ {
+ auto v = std::get<ixion::range_t>(name.value);
+ src_range_t ret;
+ ret.first.sheet = v.first.sheet;
+ ret.first.column = v.first.column;
+ ret.first.row = v.first.row;
+ ret.last.sheet = v.last.sheet;
+ ret.last.column = v.last.column;
+ ret.last.row = v.last.row;
+ return ret;
+ }
+ case ixion::formula_name_t::cell_reference:
+ {
+ // Single cell address is still considered a valid "range".
+ auto addr = std::get<ixion::address_t>(name.value);
+ src_address_t cell;
+ cell.sheet = addr.sheet;
+ cell.column = addr.column;
+ cell.row = addr.row;
+
+ src_range_t ret;
+ ret.first = cell;
+ ret.last = cell;
+ return ret;
+ }
+ default:
+ ;
+ }
+
+ std::ostringstream os;
+ os << "'" << range << "' is not a valid range address.";
+ throw orcus::invalid_arg_error(os.str());
+ }
+};
+
+class import_global_named_exp : public iface::import_named_expression
+{
+ document& m_doc;
+ std::string_view m_name;
+ ixion::abs_address_t m_base;
+ ixion::formula_tokens_t m_tokens;
+
+ void define(std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt)
+ {
+ string_pool& sp = m_doc.get_string_pool();
+ m_name = sp.intern(name).first;
+
+ const ixion::formula_name_resolver* resolver = m_doc.get_formula_name_resolver(ref_cxt);
+ assert(resolver);
+
+ ixion::model_context& cxt = m_doc.get_model_context();
+ m_tokens = ixion::parse_formula_string(cxt, m_base, *resolver, expression);
+ }
+public:
+ import_global_named_exp(document& doc) : m_doc(doc), m_base(0, 0, 0) {}
+ virtual ~import_global_named_exp() override {}
+
+ virtual void set_base_position(const src_address_t& pos) override
+ {
+ m_base.sheet = pos.sheet;
+ m_base.row = pos.row;
+ m_base.column = pos.column;
+ }
+
+ virtual void set_named_expression(std::string_view name, std::string_view expression) override
+ {
+ define(name, expression, formula_ref_context_t::global);
+ }
+
+ virtual void set_named_range(std::string_view name, std::string_view range) override
+ {
+ define(name, range, formula_ref_context_t::named_range);
+ }
+
+ virtual void commit() override
+ {
+ ixion::model_context& cxt = m_doc.get_model_context();
+ cxt.set_named_expression(std::string{m_name}, m_base, std::move(m_tokens));
+
+ m_name = std::string_view{};
+ m_base.sheet = 0;
+ m_base.row = 0;
+ m_base.column = 0;
+ }
+};
+
+using sheet_ifaces_type = std::vector<std::unique_ptr<import_sheet>>;
+
+} // anonymous namespace
+
+import_factory_config::import_factory_config() = default;
+import_factory_config::import_factory_config(const import_factory_config& other) = default;
+import_factory_config::~import_factory_config() = default;
+
+import_factory_config& import_factory_config::operator=(const import_factory_config& other) = default;
+
+struct import_factory::impl
+{
+ std::shared_ptr<import_factory_config> m_config;
+ import_factory& m_envelope;
+ document& m_doc;
+ view* m_view;
+ character_set_t m_charset;
+
+ import_global_settings m_global_settings;
+ import_pivot_cache_def m_pc_def;
+ import_pivot_cache_records m_pc_records;
+ import_ref_resolver m_ref_resolver;
+ import_global_named_exp m_global_named_exp;
+ import_styles m_styles;
+ detail::import_shared_strings shared_strings;
+
+ sheet_ifaces_type m_sheets;
+
+ bool m_recalc_formula_cells;
+ formula_error_policy_t m_error_policy;
+
+ impl(import_factory& envelope, document& doc) :
+ m_config(std::make_shared<import_factory_config>()),
+ m_envelope(envelope),
+ m_doc(doc),
+ m_view(nullptr),
+ m_charset(character_set_t::unspecified),
+ m_global_settings(envelope, doc),
+ m_pc_def(doc),
+ m_pc_records(doc),
+ m_ref_resolver(doc),
+ m_global_named_exp(doc),
+ m_styles(m_config, doc.get_styles(), doc.get_string_pool()),
+ shared_strings(doc.get_string_pool(), doc.get_model_context(), doc.get_styles(), doc.get_shared_strings()),
+ m_recalc_formula_cells(false),
+ m_error_policy(formula_error_policy_t::fail)
+ {
+ }
+};
+
+import_factory::import_factory(document& doc) :
+ mp_impl(std::make_unique<impl>(*this, doc)) {}
+
+import_factory::import_factory(document& doc, view& view_store) :
+ mp_impl(std::make_unique<impl>(*this, doc))
+{
+ // Store the optional view store.
+ mp_impl->m_view = &view_store;
+}
+
+import_factory::~import_factory() {}
+
+iface::import_global_settings* import_factory::get_global_settings()
+{
+ return &mp_impl->m_global_settings;
+}
+
+iface::import_shared_strings* import_factory::get_shared_strings()
+{
+ return &mp_impl->shared_strings;
+}
+
+iface::import_styles* import_factory::get_styles()
+{
+ return &mp_impl->m_styles;
+}
+
+iface::import_named_expression* import_factory::get_named_expression()
+{
+ return &mp_impl->m_global_named_exp;
+}
+
+iface::import_reference_resolver* import_factory::get_reference_resolver(formula_ref_context_t cxt)
+{
+ mp_impl->m_ref_resolver.set_formula_ref_context(cxt);
+ return &mp_impl->m_ref_resolver;
+}
+
+iface::import_pivot_cache_definition* import_factory::create_pivot_cache_definition(
+ pivot_cache_id_t cache_id)
+{
+ mp_impl->m_pc_def.create_cache(cache_id);
+ return &mp_impl->m_pc_def;
+}
+
+iface::import_pivot_cache_records* import_factory::create_pivot_cache_records(
+ orcus::spreadsheet::pivot_cache_id_t cache_id)
+{
+ pivot_collection& pcs = mp_impl->m_doc.get_pivot_collection();
+ pivot_cache* pc = pcs.get_cache(cache_id);
+ if (!pc)
+ return nullptr;
+
+ mp_impl->m_pc_records.set_cache(pc);
+ return &mp_impl->m_pc_records;
+}
+
+iface::import_sheet* import_factory::append_sheet(sheet_t sheet_index, std::string_view name)
+{
+ assert(sheet_index == static_cast<sheet_t>(mp_impl->m_doc.get_sheet_count()));
+
+ sheet* sh = mp_impl->m_doc.append_sheet(name);
+
+ if (!sh)
+ return nullptr;
+
+ sheet_view* sv = nullptr;
+ if (mp_impl->m_view)
+ sv = mp_impl->m_view->get_or_create_sheet_view(sheet_index);
+
+ mp_impl->m_sheets.push_back(
+ std::make_unique<import_sheet>(mp_impl->m_doc, *sh, sv));
+
+ import_sheet* p = mp_impl->m_sheets.back().get();
+ p->set_character_set(mp_impl->m_charset);
+ p->set_fill_missing_formula_results(!mp_impl->m_recalc_formula_cells);
+ p->set_formula_error_policy(mp_impl->m_error_policy);
+ return p;
+}
+
+iface::import_sheet* import_factory::get_sheet(std::string_view name)
+{
+ sheet_t si = mp_impl->m_doc.get_sheet_index(name);
+ if (si == ixion::invalid_sheet)
+ return nullptr;
+
+ return mp_impl->m_sheets.at(si).get();
+}
+
+iface::import_sheet* import_factory::get_sheet(sheet_t sheet_index)
+{
+ if (sheet_index < 0 || size_t(sheet_index) >= mp_impl->m_sheets.size())
+ return nullptr;
+
+ return mp_impl->m_sheets[sheet_index].get();
+}
+
+void import_factory::finalize()
+{
+ mp_impl->m_doc.finalize_import();
+
+ if (mp_impl->m_recalc_formula_cells)
+ mp_impl->m_doc.recalc_formula_cells();
+}
+
+void import_factory::set_config(const import_factory_config& config)
+{
+ // NB: update the object state.
+ *mp_impl->m_config = config;
+}
+
+void import_factory::set_default_row_size(row_t row_size)
+{
+ range_size_t ss = mp_impl->m_doc.get_sheet_size();
+ ss.rows = row_size;
+ mp_impl->m_doc.set_sheet_size(ss);
+}
+
+void import_factory::set_default_column_size(col_t col_size)
+{
+ range_size_t ss = mp_impl->m_doc.get_sheet_size();
+ ss.columns = col_size;
+ mp_impl->m_doc.set_sheet_size(ss);
+}
+
+void import_factory::set_character_set(character_set_t charset)
+{
+ mp_impl->m_charset = charset;
+
+ for (std::unique_ptr<import_sheet>& sheet : mp_impl->m_sheets)
+ sheet->set_character_set(charset);
+}
+
+character_set_t import_factory::get_character_set() const
+{
+ return mp_impl->m_charset;
+}
+
+void import_factory::set_recalc_formula_cells(bool b)
+{
+ mp_impl->m_recalc_formula_cells = b;
+}
+
+void import_factory::set_formula_error_policy(formula_error_policy_t policy)
+{
+ mp_impl->m_error_policy = policy;
+}
+
+struct export_factory::impl
+{
+ const document& m_doc;
+
+ std::vector<std::unique_ptr<export_sheet>> m_sheets;
+ std::unordered_map<std::string_view, sheet_t> m_sheet_index_map;
+
+ impl(const document& doc) : m_doc(doc) {}
+
+ export_sheet* get_sheet(std::string_view name)
+ {
+ auto it = m_sheet_index_map.find(name);
+ if (it != m_sheet_index_map.end())
+ {
+ // Instance for this sheet already exists.
+ sheet_t sheet_pos = it->second;
+ assert(size_t(sheet_pos) < m_sheets.size());
+ return m_sheets[sheet_pos].get();
+ }
+
+ const sheet* sh = m_doc.get_sheet(name);
+ if (!sh)
+ return nullptr;
+
+ sheet_t sheet_pos = m_sheets.size();
+ m_sheets.emplace_back(std::make_unique<export_sheet>(m_doc, *sh));
+
+ m_sheet_index_map.insert(
+ std::make_pair(name, sheet_pos));
+
+ return m_sheets[sheet_pos].get();
+ }
+};
+
+export_factory::export_factory(const document& doc) :
+ mp_impl(std::make_unique<impl>(doc)) {}
+
+export_factory::~export_factory() {}
+
+const iface::export_sheet* export_factory::get_sheet(std::string_view sheet_name) const
+{
+ return mp_impl->get_sheet(sheet_name);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_pivot.cpp b/src/spreadsheet/factory_pivot.cpp
new file mode 100644
index 0000000..2761da5
--- /dev/null
+++ b/src/spreadsheet/factory_pivot.cpp
@@ -0,0 +1,303 @@
+/* -*- 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 "factory_pivot.hpp"
+
+#include "orcus/string_pool.hpp"
+#include "orcus/exception.hpp"
+
+#include <sstream>
+#include <iostream>
+#include <cassert>
+
+namespace orcus { namespace spreadsheet {
+
+class import_pc_field_group : public iface::import_pivot_cache_field_group
+{
+ using range_grouping_type = pivot_cache_group_data_t::range_grouping_type;
+
+ document& m_doc;
+ pivot_cache_field_t& m_parent_field;
+ std::unique_ptr<pivot_cache_group_data_t> m_data;
+ pivot_cache_item_t m_current_field_item;
+
+private:
+ std::string_view intern(std::string_view s)
+ {
+ return m_doc.get_string_pool().intern(s).first;
+ }
+
+ range_grouping_type& get_range_grouping()
+ {
+ if (!m_data->range_grouping)
+ m_data->range_grouping = range_grouping_type();
+
+ return *m_data->range_grouping;
+ }
+
+public:
+ import_pc_field_group(document& doc, pivot_cache_field_t& parent, size_t base_index) :
+ m_doc(doc),
+ m_parent_field(parent),
+ m_data(std::make_unique<pivot_cache_group_data_t>(base_index)) {}
+
+ ~import_pc_field_group() override {}
+
+ void link_base_to_group_items(size_t group_item_index) override
+ {
+ pivot_cache_indices_t& b2g = m_data->base_to_group_indices;
+ b2g.push_back(group_item_index);
+ }
+
+ void set_field_item_string(std::string_view value) override
+ {
+ m_current_field_item.type = pivot_cache_item_t::item_type::character;
+ m_current_field_item.value = intern(value);
+ }
+
+ void set_field_item_numeric(double v) override
+ {
+ m_current_field_item.type = pivot_cache_item_t::item_type::numeric;
+ m_current_field_item.value = v;
+ }
+
+ void commit_field_item() override
+ {
+ m_data->items.push_back(std::move(m_current_field_item));
+ }
+
+ void set_range_grouping_type(pivot_cache_group_by_t group_by) override
+ {
+ get_range_grouping().group_by = group_by;
+ }
+
+ void set_range_auto_start(bool b) override
+ {
+ get_range_grouping().auto_start = b;
+ }
+
+ void set_range_auto_end(bool b) override
+ {
+ get_range_grouping().auto_end = b;
+ }
+
+ void set_range_start_number(double v) override
+ {
+ get_range_grouping().start = v;
+ }
+
+ void set_range_end_number(double v) override
+ {
+ get_range_grouping().end = v;
+ }
+
+ void set_range_start_date(const date_time_t& dt) override
+ {
+ get_range_grouping().start_date = dt;
+ }
+
+ void set_range_end_date(const date_time_t& dt) override
+ {
+ get_range_grouping().end_date = dt;
+ }
+
+ void set_range_interval(double v) override
+ {
+ get_range_grouping().interval = v;
+ }
+
+ void commit() override
+ {
+ m_parent_field.group_data = std::move(m_data);
+ }
+};
+
+std::string_view import_pivot_cache_def::intern(std::string_view s)
+{
+ return m_doc.get_string_pool().intern(s).first;
+}
+
+import_pivot_cache_def::import_pivot_cache_def(document& doc) : m_doc(doc) {}
+
+import_pivot_cache_def::~import_pivot_cache_def() {}
+
+void import_pivot_cache_def::create_cache(pivot_cache_id_t cache_id)
+{
+ m_src_type = unknown;
+ m_cache = std::make_unique<pivot_cache>(cache_id, m_doc.get_string_pool());
+}
+
+void import_pivot_cache_def::set_worksheet_source(std::string_view ref, std::string_view sheet_name)
+{
+ assert(m_cache);
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ assert(resolver);
+
+ m_src_type = worksheet;
+ m_src_sheet_name = intern(sheet_name);
+
+ ixion::formula_name_t fn = resolver->resolve(ref, ixion::abs_address_t(0,0,0));
+
+ if (fn.type != ixion::formula_name_t::range_reference)
+ {
+ std::ostringstream os;
+ os << "'" << ref << "' is not a valid range.";
+ throw xml_structure_error(os.str());
+ }
+
+ m_src_range = std::get<ixion::range_t>(fn.value).to_abs(ixion::abs_address_t(0,0,0));
+}
+
+void import_pivot_cache_def::set_worksheet_source(std::string_view table_name)
+{
+ assert(m_cache);
+
+ m_src_table_name = intern(table_name);
+}
+
+void import_pivot_cache_def::set_field_count(size_t n)
+{
+ m_current_fields.reserve(n);
+}
+
+void import_pivot_cache_def::set_field_name(std::string_view name)
+{
+ m_current_field.name = intern(name);
+}
+
+iface::import_pivot_cache_field_group* import_pivot_cache_def::start_field_group(size_t base_index)
+{
+ m_current_field_group =
+ std::make_unique<import_pc_field_group>(m_doc, m_current_field, base_index);
+
+ return m_current_field_group.get();
+}
+
+void import_pivot_cache_def::set_field_min_value(double v)
+{
+ m_current_field.min_value = v;
+}
+
+void import_pivot_cache_def::set_field_max_value(double v)
+{
+ m_current_field.max_value = v;
+}
+
+void import_pivot_cache_def::set_field_min_date(const date_time_t& dt)
+{
+ m_current_field.min_date = dt;
+}
+
+void import_pivot_cache_def::set_field_max_date(const date_time_t& dt)
+{
+ m_current_field.max_date = dt;
+}
+
+void import_pivot_cache_def::commit_field()
+{
+ m_current_fields.push_back(std::move(m_current_field));
+}
+
+void import_pivot_cache_def::set_field_item_string(std::string_view value)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::character;
+ m_current_field_item.value = intern(value);
+}
+
+void import_pivot_cache_def::set_field_item_numeric(double v)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::numeric;
+ m_current_field_item.value = v;
+}
+
+void import_pivot_cache_def::set_field_item_date_time(const date_time_t& dt)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::date_time;
+ m_current_field_item.value = dt;
+}
+
+void import_pivot_cache_def::set_field_item_error(error_value_t ev)
+{
+ m_current_field_item.type = pivot_cache_item_t::item_type::error;
+ m_current_field_item.value = ev;
+}
+
+void import_pivot_cache_def::commit_field_item()
+{
+ m_current_field.items.push_back(std::move(m_current_field_item));
+}
+
+void import_pivot_cache_def::commit()
+{
+ m_cache->insert_fields(std::move(m_current_fields));
+ assert(m_current_fields.empty());
+
+ if (!m_src_table_name.empty())
+ {
+ m_doc.get_pivot_collection().insert_worksheet_cache(
+ m_src_table_name, std::move(m_cache));
+ return;
+ }
+
+ m_doc.get_pivot_collection().insert_worksheet_cache(
+ m_src_sheet_name, m_src_range, std::move(m_cache));
+}
+
+import_pivot_cache_records::import_pivot_cache_records(document& doc) :
+ m_doc(doc), m_cache(nullptr) {}
+
+import_pivot_cache_records::~import_pivot_cache_records() {}
+
+void import_pivot_cache_records::set_cache(pivot_cache* p)
+{
+ m_cache = p;
+}
+
+void import_pivot_cache_records::set_record_count(size_t n)
+{
+ m_records.reserve(n);
+}
+
+void import_pivot_cache_records::append_record_value_numeric(double v)
+{
+ m_current_record.emplace_back(v);
+}
+
+void import_pivot_cache_records::append_record_value_character(std::string_view s)
+{
+ m_current_record.emplace_back(s);
+}
+
+void import_pivot_cache_records::append_record_value_shared_item(size_t index)
+{
+ m_current_record.emplace_back(index);
+}
+
+void import_pivot_cache_records::commit_record()
+{
+ if (!m_cache)
+ {
+ m_current_record.clear();
+ return;
+ }
+
+ m_records.push_back(std::move(m_current_record));
+}
+
+void import_pivot_cache_records::commit()
+{
+ if (!m_cache)
+ return;
+
+ m_cache->insert_records(std::move(m_records));
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_pivot.hpp b/src/spreadsheet/factory_pivot.hpp
new file mode 100644
index 0000000..465fef1
--- /dev/null
+++ b/src/spreadsheet/factory_pivot.hpp
@@ -0,0 +1,120 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FACTORY_PIVOT_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FACTORY_PIVOT_HPP
+
+#include "orcus/spreadsheet/pivot.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/import_interface_pivot.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class import_pc_field_group;
+
+/**
+ * Concrete implementation of the import_pivot_cache_definition interface.
+ */
+class import_pivot_cache_def : public iface::import_pivot_cache_definition
+{
+ enum source_type { unknown = 0, worksheet, external, consolidation, scenario };
+
+ document& m_doc;
+
+ pivot_cache_id_t m_cache_id = 0;
+
+ source_type m_src_type = unknown;
+ std::string_view m_src_sheet_name;
+ ixion::abs_range_t m_src_range;
+ std::string_view m_src_table_name;
+
+ std::unique_ptr<pivot_cache> m_cache;
+ pivot_cache::fields_type m_current_fields;
+ pivot_cache_field_t m_current_field;
+ pivot_cache_item_t m_current_field_item;
+
+ std::unique_ptr<import_pc_field_group> m_current_field_group;
+
+private:
+ std::string_view intern(std::string_view s);
+
+public:
+ import_pivot_cache_def(document& doc);
+ ~import_pivot_cache_def();
+
+ void create_cache(pivot_cache_id_t cache_id);
+
+ virtual void set_worksheet_source(std::string_view ref, std::string_view sheet_name) override;
+
+ virtual void set_worksheet_source(std::string_view table_name) override;
+
+ virtual void set_field_count(size_t n) override;
+
+ virtual void set_field_name(std::string_view name) override;
+
+ virtual iface::import_pivot_cache_field_group* start_field_group(size_t base_index) override;
+
+ virtual void set_field_min_value(double v) override;
+
+ virtual void set_field_max_value(double v) override;
+
+ virtual void set_field_min_date(const date_time_t& dt) override;
+
+ virtual void set_field_max_date(const date_time_t& dt) override;
+
+ virtual void commit_field() override;
+
+ virtual void set_field_item_string(std::string_view value) override;
+
+ virtual void set_field_item_numeric(double v) override;
+
+ virtual void set_field_item_date_time(const date_time_t& dt) override;
+
+ virtual void set_field_item_error(error_value_t ev) override;
+
+ virtual void commit_field_item() override;
+
+ virtual void commit() override;
+};
+
+/**
+ * Concrete implementation of the import_pivot_cache_records interface.
+ */
+class import_pivot_cache_records : public iface::import_pivot_cache_records
+{
+ document& m_doc;
+ pivot_cache* m_cache; //< cache to push the records to at the very end.
+
+ pivot_cache_record_t m_current_record;
+ pivot_cache::records_type m_records;
+
+public:
+ import_pivot_cache_records(document& doc);
+ ~import_pivot_cache_records();
+
+ void set_cache(pivot_cache* p);
+
+ virtual void set_record_count(size_t n) override;
+
+ virtual void append_record_value_numeric(double v) override;
+
+ virtual void append_record_value_character(std::string_view s) override;
+
+ virtual void append_record_value_shared_item(size_t index) override;
+
+ virtual void commit_record() override;
+
+ virtual void commit() override;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_shared_strings.cpp b/src/spreadsheet/factory_shared_strings.cpp
new file mode 100644
index 0000000..a8375c0
--- /dev/null
+++ b/src/spreadsheet/factory_shared_strings.cpp
@@ -0,0 +1,118 @@
+/* -*- 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 "factory_shared_strings.hpp"
+
+#include <orcus/spreadsheet/shared_strings.hpp>
+#include <orcus/spreadsheet/styles.hpp>
+#include <orcus/string_pool.hpp>
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+import_shared_strings::import_shared_strings(
+ string_pool& sp, ixion::model_context& cxt, styles& st, shared_strings& ss_store) :
+ m_string_pool(sp),
+ m_cxt(cxt),
+ m_styles(st),
+ m_ss_store(ss_store)
+{
+}
+
+import_shared_strings::~import_shared_strings() {}
+
+size_t import_shared_strings::append(std::string_view s)
+{
+ return m_cxt.append_string(s);
+}
+
+size_t import_shared_strings::add(std::string_view s)
+{
+ return m_cxt.add_string(s);
+}
+
+void import_shared_strings::set_segment_font(size_t font_index)
+{
+ const font_t* font_data = m_styles.get_font(font_index);
+ if (!font_data)
+ return;
+
+ m_cur_format.bold = font_data->bold ? *font_data->bold : false;
+ m_cur_format.italic = font_data->italic ? *font_data->italic : false;
+
+ if (font_data->name)
+ m_cur_format.font = *font_data->name; // font names are already interned when set.
+
+ if (font_data->size)
+ m_cur_format.font_size = *font_data->size;
+
+ if (font_data->color)
+ m_cur_format.color = *font_data->color;
+}
+
+void import_shared_strings::set_segment_bold(bool b)
+{
+ m_cur_format.bold = b;
+}
+
+void import_shared_strings::set_segment_italic(bool b)
+{
+ m_cur_format.italic = b;
+}
+
+void import_shared_strings::set_segment_font_name(std::string_view s)
+{
+ m_cur_format.font = m_string_pool.intern(s).first;
+}
+
+void import_shared_strings::set_segment_font_size(double point)
+{
+ m_cur_format.font_size = point;
+}
+
+void import_shared_strings::set_segment_font_color(
+ color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ m_cur_format.color = color_t(alpha, red, green, blue);
+}
+
+void import_shared_strings::append_segment(std::string_view s)
+{
+ if (s.empty())
+ return;
+
+ size_t start_pos = m_cur_segment_string.size();
+ m_cur_segment_string += s;
+
+ if (m_cur_format.formatted())
+ {
+ // This segment is formatted.
+ // Record the position and size of the format run.
+ m_cur_format.pos = start_pos;
+ m_cur_format.size = s.size();
+
+ if (!mp_cur_format_runs)
+ mp_cur_format_runs = std::make_unique<format_runs_t>();
+
+ mp_cur_format_runs->push_back(m_cur_format);
+ m_cur_format.reset();
+ }
+}
+
+size_t import_shared_strings::commit_segments()
+{
+ ixion::string_id_t sindex = m_cxt.append_string(m_cur_segment_string);
+ m_cur_segment_string.clear();
+ m_ss_store.set_format_runs(sindex, std::move(mp_cur_format_runs));
+ mp_cur_format_runs.reset();
+
+ return sindex;
+}
+
+}}} // namespace orcus::spreadsheet::detail
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_shared_strings.hpp b/src/spreadsheet/factory_shared_strings.hpp
new file mode 100644
index 0000000..b49d274
--- /dev/null
+++ b/src/spreadsheet/factory_shared_strings.hpp
@@ -0,0 +1,64 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/document_types.hpp>
+
+#include <memory>
+
+namespace ixion {
+
+class model_context;
+
+}
+
+namespace orcus {
+
+class string_pool;
+
+namespace spreadsheet {
+
+class styles;
+class shared_strings;
+
+namespace detail {
+
+class import_shared_strings : public iface::import_shared_strings
+{
+ orcus::string_pool& m_string_pool;
+ ixion::model_context& m_cxt;
+ styles& m_styles;
+ shared_strings& m_ss_store;
+
+ std::string m_cur_segment_string;
+ format_run m_cur_format;
+ std::unique_ptr<format_runs_t> mp_cur_format_runs;
+
+public:
+ import_shared_strings(
+ string_pool& sp, ixion::model_context& cxt, styles& st,
+ orcus::spreadsheet::shared_strings& ss_store);
+ virtual ~import_shared_strings() override;
+
+ virtual size_t append(std::string_view s) override;
+ virtual size_t add(std::string_view s) override;
+
+ virtual void set_segment_font(size_t font_index) override;
+ virtual void set_segment_bold(bool b) override;
+ virtual void set_segment_italic(bool b) override;
+ virtual void set_segment_font_name(std::string_view s) override;
+ virtual void set_segment_font_size(double point) override;
+ virtual void set_segment_font_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void append_segment(std::string_view s) override;
+ virtual size_t commit_segments() override;
+};
+
+}}} // namespace orcus::spreadsheet::detail
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_sheet.cpp b/src/spreadsheet/factory_sheet.cpp
new file mode 100644
index 0000000..dcc6639
--- /dev/null
+++ b/src/spreadsheet/factory_sheet.cpp
@@ -0,0 +1,640 @@
+/* -*- 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 "factory_sheet.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/view.hpp"
+#include "orcus/measurement.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "formula_global.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/formula.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+import_sheet_named_exp::import_sheet_named_exp(document& doc, sheet_t sheet_index) :
+ m_doc(doc), m_sheet_index(sheet_index), m_base(sheet_index, 0, 0) {}
+
+import_sheet_named_exp::~import_sheet_named_exp() {}
+
+void import_sheet_named_exp::define(
+ std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt)
+{
+ string_pool& sp = m_doc.get_string_pool();
+ m_name = sp.intern(name).first;
+
+ const ixion::formula_name_resolver* resolver = m_doc.get_formula_name_resolver(ref_cxt);
+ assert(resolver);
+
+ ixion::model_context& cxt = m_doc.get_model_context();
+ m_tokens = ixion::parse_formula_string(cxt, m_base, *resolver, expression);
+}
+
+void import_sheet_named_exp::set_base_position(const src_address_t& pos)
+{
+ m_base.sheet = pos.sheet;
+ m_base.row = pos.row;
+ m_base.column = pos.column;
+}
+
+void import_sheet_named_exp::set_named_expression(std::string_view name, std::string_view expression)
+{
+ define(name, expression, formula_ref_context_t::global);
+}
+
+void import_sheet_named_exp::set_named_range(std::string_view name, std::string_view range)
+{
+ define(name, range, formula_ref_context_t::named_range);
+}
+
+void import_sheet_named_exp::commit()
+{
+ ixion::model_context& cxt = m_doc.get_model_context();
+ cxt.set_named_expression(m_sheet_index, std::string{m_name}, m_base, std::move(m_tokens));
+
+ m_name = std::string_view{};
+ m_base.sheet = 0;
+ m_base.row = 0;
+ m_base.column = 0;
+}
+
+import_data_table::import_data_table(sheet& sh) : m_sheet(sh) {}
+import_data_table::~import_data_table() {}
+
+void import_data_table::reset()
+{
+}
+
+void import_data_table::set_type(data_table_type_t /*type*/)
+{
+}
+
+void import_data_table::set_range(const range_t& /*range*/)
+{
+}
+
+void import_data_table::set_first_reference(std::string_view /*ref*/, bool /*deleted*/)
+{
+}
+
+void import_data_table::set_second_reference(std::string_view /*ref*/, bool /*deleted*/)
+{
+}
+
+void import_data_table::commit()
+{
+}
+
+import_auto_filter::import_auto_filter(sheet& sh, string_pool& sp) :
+ m_sheet(sh),
+ m_string_pool(sp),
+ m_cur_col(-1) {}
+
+void import_auto_filter::reset()
+{
+ mp_data.reset(new auto_filter_t);
+ m_cur_col = -1;
+ m_cur_col_data.reset();
+}
+
+void import_auto_filter::set_range(const range_t& range)
+{
+ mp_data->range = to_abs_range(range, m_sheet.get_index());
+}
+
+void import_auto_filter::set_column(col_t col)
+{
+ m_cur_col = col;
+}
+
+void import_auto_filter::append_column_match_value(std::string_view value)
+{
+ // The string pool belongs to the document.
+ value = m_string_pool.intern(value).first;
+ m_cur_col_data.match_values.insert(value);
+}
+
+void import_auto_filter::commit_column()
+{
+ if (!mp_data)
+ return;
+
+ mp_data->commit_column(m_cur_col, m_cur_col_data);
+ m_cur_col_data.reset();
+}
+
+void import_auto_filter::commit()
+{
+ m_sheet.set_auto_filter_data(mp_data.release());
+}
+
+import_array_formula::import_array_formula(document& doc, sheet& sheet) :
+ m_doc(doc), m_sheet(sheet), m_missing_formula_result(), m_error_policy(formula_error_policy_t::fail)
+{
+ m_range.first.column = -1;
+ m_range.first.row = -1;
+ m_range.last = m_range.first;
+}
+
+import_array_formula::~import_array_formula()
+{
+}
+
+void import_array_formula::set_range(const range_t& range)
+{
+ m_range = range;
+
+ // Initialize the result matrix with the missing result value.
+ switch (m_missing_formula_result.get_type())
+ {
+ case ixion::formula_result::result_type::value:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_value());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ case ixion::formula_result::result_type::error:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_error());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ case ixion::formula_result::result_type::string:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1,
+ m_missing_formula_result.get_string());
+ m_result_mtx.swap(_mtx);
+ break;
+ }
+ default:
+ {
+ ixion::matrix _mtx(
+ m_range.last.row - m_range.first.row + 1,
+ m_range.last.column - m_range.first.column + 1);
+ m_result_mtx.swap(_mtx);
+ }
+ }
+}
+
+void import_array_formula::set_formula(formula_grammar_t /*grammar*/, std::string_view formula)
+{
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ // Tokenize the formula string and store it.
+ ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), m_range.first.row, m_range.first.column);
+
+ try
+ {
+ m_tokens = ixion::parse_formula_string(cxt, pos, *resolver, formula);
+ }
+ catch (const std::exception& e)
+ {
+ if (m_error_policy == formula_error_policy_t::fail)
+ throw;
+
+ std::string_view error_s = e.what();
+ m_tokens = ixion::create_formula_error_tokens(cxt, formula, error_s);
+ }
+}
+
+void import_array_formula::set_result_value(row_t row, col_t col, double value)
+{
+ m_result_mtx.set(row, col, value);
+}
+
+void import_array_formula::set_result_string(row_t /*row*/, col_t /*col*/, std::string_view /*value*/)
+{
+ // TODO : handle this
+}
+
+void import_array_formula::set_result_empty(row_t /*row*/, col_t /*col*/)
+{
+ // TODO : handle this
+}
+
+void import_array_formula::set_result_bool(row_t row, col_t col, bool value)
+{
+ m_result_mtx.set(row, col, value);
+}
+
+void import_array_formula::commit()
+{
+ ixion::formula_result cached_results(std::move(m_result_mtx));
+ m_sheet.set_grouped_formula(m_range, std::move(m_tokens), std::move(cached_results));
+}
+
+void import_array_formula::set_missing_formula_result(ixion::formula_result result)
+{
+ m_missing_formula_result = std::move(result);
+}
+
+void import_array_formula::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_error_policy = policy;
+}
+
+void import_array_formula::reset()
+{
+ m_tokens.clear();
+ m_result_mtx = ixion::matrix();
+ m_range.first.row = -1;
+ m_range.first.column = -1;
+ m_range.last.row = -1;
+ m_range.last.column = -1;
+}
+
+import_formula::import_formula(document& doc, sheet& sheet, shared_formula_pool& pool) :
+ m_doc(doc),
+ m_sheet(sheet),
+ m_shared_formula_pool(pool),
+ m_row(-1),
+ m_col(-1),
+ m_shared_index(0),
+ m_shared(false),
+ m_error_policy(formula_error_policy_t::fail) {}
+
+import_formula::~import_formula() {}
+
+void import_formula::set_position(row_t row, col_t col)
+{
+ m_row = row;
+ m_col = col;
+}
+
+void import_formula::set_formula(formula_grammar_t /*grammar*/, std::string_view formula)
+{
+ if (m_row < 0 || m_col < 0)
+ return;
+
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ if (!resolver)
+ return;
+
+ // Tokenize the formula string and store it.
+ ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), m_row, m_col);
+
+ ixion::formula_tokens_t tokens;
+ try
+ {
+ tokens = ixion::parse_formula_string(cxt, pos, *resolver, formula);
+ }
+ catch (const std::exception& e)
+ {
+ if (m_error_policy == formula_error_policy_t::fail)
+ throw;
+
+ std::string_view error_s = e.what();
+ tokens = ixion::create_formula_error_tokens(cxt, formula, error_s);
+ }
+
+ m_tokens_store = ixion::formula_tokens_store::create();
+ m_tokens_store->get() = std::move(tokens);
+}
+
+void import_formula::set_shared_formula_index(size_t index)
+{
+ m_shared = true;
+ m_shared_index = index;
+}
+
+void import_formula::set_result_value(double value)
+{
+ m_result = ixion::formula_result(value);
+}
+
+void import_formula::set_result_string(std::string_view value)
+{
+ m_result = ixion::formula_result(std::string{value});
+}
+
+void import_formula::set_result_empty() {}
+void import_formula::set_result_bool(bool /*value*/) {}
+
+void import_formula::commit()
+{
+ if (m_row < 0 || m_col < 0)
+ return;
+
+ if (m_shared)
+ {
+ if (m_tokens_store)
+ {
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, m_tokens_store, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, m_tokens_store);
+
+ m_shared_formula_pool.add(m_shared_index, m_tokens_store);
+ }
+ else
+ {
+ ixion::formula_tokens_store_ptr_t ts = m_shared_formula_pool.get(m_shared_index);
+ if (!ts)
+ return;
+
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, ts, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, ts);
+ }
+ return;
+ }
+
+ if (m_result)
+ m_sheet.set_formula(m_row, m_col, m_tokens_store, *m_result);
+ else
+ m_sheet.set_formula(m_row, m_col, m_tokens_store);
+}
+
+void import_formula::set_missing_formula_result(ixion::formula_result result)
+{
+ m_result = std::move(result);
+}
+
+void import_formula::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_error_policy = policy;
+}
+
+void import_formula::reset()
+{
+ m_tokens_store.reset();
+ m_result.reset();
+ m_row = -1;
+ m_col = -1;
+ m_shared_index = 0;
+ m_shared = false;
+}
+
+import_sheet::import_sheet(document& doc, sheet& sh, sheet_view* view) :
+ m_doc(doc),
+ m_sheet(sh),
+ m_formula(doc, sh, m_shared_formula_pool),
+ m_array_formula(doc, sh),
+ m_named_exp(doc, sh.get_index()),
+ m_sheet_properties(doc, sh),
+ m_data_table(sh),
+ m_auto_filter(sh, doc.get_string_pool()),
+ m_table(doc, sh),
+ m_charset(character_set_t::unspecified),
+ m_fill_missing_formula_results(false)
+{
+ if (view)
+ m_sheet_view = std::make_unique<import_sheet_view>(*view, sh.get_index());
+}
+
+import_sheet::~import_sheet() {}
+
+iface::import_sheet_view* import_sheet::get_sheet_view()
+{
+ return m_sheet_view.get();
+}
+
+iface::import_auto_filter* import_sheet::get_auto_filter()
+{
+ m_auto_filter.reset();
+ return &m_auto_filter;
+}
+
+iface::import_conditional_format* import_sheet::get_conditional_format()
+{
+ return nullptr;
+}
+
+iface::import_data_table* import_sheet::get_data_table()
+{
+ return &m_data_table;
+}
+
+iface::import_named_expression* import_sheet::get_named_expression()
+{
+ return &m_named_exp;
+}
+
+iface::import_sheet_properties* import_sheet::get_sheet_properties()
+{
+ return &m_sheet_properties;
+}
+
+iface::import_table* import_sheet::get_table()
+{
+ m_table.reset();
+ return &m_table;
+}
+
+iface::import_formula* import_sheet::get_formula()
+{
+ m_formula.reset();
+
+ if (m_fill_missing_formula_results)
+ {
+ m_formula.set_missing_formula_result(
+ ixion::formula_result(ixion::formula_error_t::no_result_error));
+ }
+
+ return &m_formula;
+}
+
+iface::import_array_formula* import_sheet::get_array_formula()
+{
+ m_array_formula.reset();
+
+ if (m_fill_missing_formula_results)
+ {
+ m_array_formula.set_missing_formula_result(
+ ixion::formula_result(ixion::formula_error_t::no_result_error));
+ }
+
+ return &m_array_formula;
+}
+
+void import_sheet::set_auto(row_t row, col_t col, std::string_view s)
+{
+ m_sheet.set_auto(row, col, s);
+}
+
+void import_sheet::set_bool(row_t row, col_t col, bool value)
+{
+ m_sheet.set_bool(row, col, value);
+}
+
+void import_sheet::set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second)
+{
+ m_sheet.set_date_time(row, col, year, month, day, hour, minute, second);
+}
+
+void import_sheet::set_format(row_t row, col_t col, size_t xf_index)
+{
+ m_sheet.set_format(row, col, xf_index);
+}
+
+void import_sheet::set_format(
+ row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t xf_index)
+{
+ m_sheet.set_format(row_start, col_start, row_end, col_end, xf_index);
+}
+
+void import_sheet::set_column_format(col_t col, col_t col_span, std::size_t xf_index)
+{
+ m_sheet.set_column_format(col, col_span, xf_index);
+}
+
+void import_sheet::set_row_format(row_t row, std::size_t xf_index)
+{
+ m_sheet.set_row_format(row, xf_index);
+}
+
+void import_sheet::set_string(row_t row, col_t col, string_id_t sindex)
+{
+ m_sheet.set_string(row, col, sindex);
+}
+
+void import_sheet::set_value(row_t row, col_t col, double value)
+{
+ m_sheet.set_value(row, col, value);
+}
+
+void import_sheet::fill_down_cells(row_t src_row, col_t src_col, row_t range_size)
+{
+ m_sheet.fill_down_cells(src_row, src_col, range_size);
+}
+
+range_size_t import_sheet::get_sheet_size() const
+{
+ return m_doc.get_sheet_size();
+}
+
+void import_sheet::set_character_set(character_set_t charset)
+{
+ m_charset = charset;
+}
+
+void import_sheet::set_fill_missing_formula_results(bool b)
+{
+ m_fill_missing_formula_results = b;
+}
+
+void import_sheet::set_formula_error_policy(formula_error_policy_t policy)
+{
+ m_formula.set_formula_error_policy(policy);
+ m_array_formula.set_formula_error_policy(policy);
+}
+
+import_sheet_view::import_sheet_view(sheet_view& view, sheet_t si) :
+ m_view(view), m_sheet_index(si) {}
+
+import_sheet_view::~import_sheet_view() {}
+
+void import_sheet_view::set_split_pane(
+ double hor_split, double ver_split,
+ const orcus::spreadsheet::address_t& top_left_cell,
+ orcus::spreadsheet::sheet_pane_t active_pane)
+{
+ m_view.set_split_pane(hor_split, ver_split, top_left_cell);
+ m_view.set_active_pane(active_pane);
+}
+
+void import_sheet_view::set_frozen_pane(
+ orcus::spreadsheet::col_t visible_columns,
+ orcus::spreadsheet::row_t visible_rows,
+ const orcus::spreadsheet::address_t& top_left_cell,
+ orcus::spreadsheet::sheet_pane_t active_pane)
+{
+ m_view.set_frozen_pane(visible_columns, visible_rows, top_left_cell);
+ m_view.set_active_pane(active_pane);
+}
+
+void import_sheet_view::set_selected_range(sheet_pane_t pane, range_t range)
+{
+ m_view.set_selection(pane, range);
+}
+
+void import_sheet_view::set_sheet_active()
+{
+ m_view.get_document_view().set_active_sheet(m_sheet_index);
+}
+
+import_sheet_properties::import_sheet_properties(document& doc, sheet& sh) :
+ m_doc(doc), m_sheet(sh) {}
+
+import_sheet_properties::~import_sheet_properties() {}
+
+void import_sheet_properties::set_column_width(col_t col, col_t col_span, double width, orcus::length_unit_t unit)
+{
+ col_width_t w = orcus::convert(width, unit, length_unit_t::twip);
+ m_sheet.set_col_width(col, col_span, w);
+}
+
+void import_sheet_properties::set_column_hidden(col_t col, col_t col_span, bool hidden)
+{
+ m_sheet.set_col_hidden(col, col_span, hidden);
+}
+
+void import_sheet_properties::set_row_height(row_t row, double height, orcus::length_unit_t unit)
+{
+ row_height_t h = orcus::convert(height, unit, length_unit_t::twip);
+ m_sheet.set_row_height(row, h);
+}
+
+void import_sheet_properties::set_row_hidden(row_t row, bool hidden)
+{
+ m_sheet.set_row_hidden(row, hidden);
+}
+
+void import_sheet_properties::set_merge_cell_range(const range_t& range)
+{
+ m_sheet.set_merge_cell_range(range);
+}
+
+export_sheet::export_sheet(const document& doc, const sheet& sh) : m_doc(doc), m_sheet(sh) {}
+export_sheet::~export_sheet() {}
+
+void export_sheet::write_string(std::ostream& os, row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ ixion::abs_address_t pos(m_sheet.get_index(), row, col);
+
+ switch (cxt.get_celltype(pos))
+ {
+ case ixion::celltype_t::string:
+ {
+ size_t str_id = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(str_id);
+ if (p)
+ os << *p;
+ }
+ break;
+ case ixion::celltype_t::numeric:
+ os << cxt.get_numeric_value(pos);
+ break;
+ default:
+ ;
+ }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/factory_sheet.hpp b/src/spreadsheet/factory_sheet.hpp
new file mode 100644
index 0000000..ded4d10
--- /dev/null
+++ b/src/spreadsheet/factory_sheet.hpp
@@ -0,0 +1,275 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FACTORY_SHEET_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FACTORY_SHEET_HPP
+
+#include <orcus/spreadsheet/import_interface.hpp>
+#include <orcus/spreadsheet/import_interface_view.hpp>
+#include <orcus/spreadsheet/auto_filter.hpp>
+
+#include <orcus/spreadsheet/export_interface.hpp>
+
+#include "factory_table.hpp"
+#include "shared_formula.hpp"
+
+#include <memory>
+#include <optional>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/matrix.hpp>
+
+namespace orcus {
+
+class string_pool;
+
+namespace spreadsheet {
+
+class document;
+class sheet_view;
+class sheet;
+class import_sheet_view;
+
+class import_sheet_named_exp : public iface::import_named_expression
+{
+ document& m_doc;
+ sheet_t m_sheet_index;
+ std::string_view m_name;
+ ixion::abs_address_t m_base;
+ ixion::formula_tokens_t m_tokens;
+
+ void define(std::string_view name, std::string_view expression, formula_ref_context_t ref_cxt);
+
+public:
+ import_sheet_named_exp(document& doc, sheet_t sheet_index);
+ virtual ~import_sheet_named_exp() override;
+
+ virtual void set_base_position(const src_address_t& pos) override;
+ virtual void set_named_expression(std::string_view name, std::string_view expression) override;
+ virtual void set_named_range(std::string_view name, std::string_view range) override;
+ virtual void commit();
+};
+
+/**
+ * Implement the sheet properties import interface, but the actual
+ * properties are stored in sheet.
+ */
+class import_sheet_properties : public iface::import_sheet_properties
+{
+ document& m_doc;
+ sheet& m_sheet;
+public:
+ import_sheet_properties(document& doc, sheet& sh);
+ ~import_sheet_properties();
+
+ virtual void set_column_width(col_t col, col_t col_span, double width, orcus::length_unit_t unit);
+ virtual void set_column_hidden(col_t col, col_t col_span, bool hidden);
+ virtual void set_row_height(row_t row, double height, orcus::length_unit_t unit);
+ virtual void set_row_hidden(row_t row, bool hidden);
+ virtual void set_merge_cell_range(const range_t& range);
+};
+
+class import_data_table : public iface::import_data_table
+{
+ sheet& m_sheet;
+public:
+ import_data_table(sheet& sh);
+ ~import_data_table();
+
+ void reset();
+
+ virtual void set_type(data_table_type_t type) override;
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_first_reference(std::string_view ref, bool deleted) override;
+
+ virtual void set_second_reference(std::string_view ref, bool deleted) override;
+
+ virtual void commit() override;
+};
+
+class import_auto_filter : public orcus::spreadsheet::iface::import_auto_filter
+{
+ sheet& m_sheet;
+ string_pool& m_string_pool;
+ std::unique_ptr<auto_filter_t> mp_data;
+ col_t m_cur_col;
+ auto_filter_column_t m_cur_col_data;
+
+public:
+ import_auto_filter(sheet& sh, string_pool& sp);
+
+ void reset();
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_column(col_t col) override;
+
+ virtual void append_column_match_value(std::string_view value) override;
+
+ virtual void commit_column() override;
+
+ virtual void commit() override;
+};
+
+class import_array_formula : public iface::import_array_formula
+{
+ document& m_doc;
+ sheet& m_sheet;
+
+ range_t m_range;
+ ixion::formula_tokens_t m_tokens;
+ ixion::formula_result m_missing_formula_result;
+ ixion::matrix m_result_mtx;
+ formula_error_policy_t m_error_policy;
+
+public:
+ import_array_formula(document& doc, sheet& sheet);
+ virtual ~import_array_formula() override;
+
+ virtual void set_range(const range_t& range) override;
+
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+
+ virtual void set_result_value(row_t row, col_t col, double value) override;
+
+ virtual void set_result_string(row_t row, col_t col, std::string_view value) override;
+
+ virtual void set_result_empty(row_t row, col_t col) override;
+
+ virtual void set_result_bool(row_t row, col_t col, bool value) override;
+
+ virtual void commit() override;
+
+ void set_missing_formula_result(ixion::formula_result result);
+
+ void set_formula_error_policy(formula_error_policy_t policy);
+
+ void reset();
+};
+
+class import_formula : public iface::import_formula
+{
+ document& m_doc;
+ sheet& m_sheet;
+ shared_formula_pool& m_shared_formula_pool;
+
+ row_t m_row;
+ col_t m_col;
+ size_t m_shared_index;
+ bool m_shared;
+
+ ixion::formula_tokens_store_ptr_t m_tokens_store;
+ std::optional<ixion::formula_result> m_result;
+ formula_error_policy_t m_error_policy;
+
+public:
+ import_formula(document& doc, sheet& sheet, shared_formula_pool& pool);
+ virtual ~import_formula() override;
+
+ virtual void set_position(row_t row, col_t col) override;
+ virtual void set_formula(formula_grammar_t grammar, std::string_view formula) override;
+ virtual void set_shared_formula_index(size_t index) override;
+ virtual void set_result_value(double value) override;
+ virtual void set_result_string(std::string_view value) override;
+ virtual void set_result_empty() override;
+ virtual void set_result_bool(bool value) override;
+ virtual void commit() override;
+
+ void set_missing_formula_result(ixion::formula_result result);
+ void set_formula_error_policy(formula_error_policy_t policy);
+
+ void reset();
+};
+
+class import_sheet : public iface::import_sheet
+{
+ document& m_doc;
+ sheet& m_sheet;
+ shared_formula_pool m_shared_formula_pool;
+ import_formula m_formula;
+ import_array_formula m_array_formula;
+ import_sheet_named_exp m_named_exp;
+ import_sheet_properties m_sheet_properties;
+ import_data_table m_data_table;
+ import_auto_filter m_auto_filter;
+ import_table m_table;
+ character_set_t m_charset;
+
+ std::unique_ptr<import_sheet_view> m_sheet_view;
+
+ bool m_fill_missing_formula_results;
+
+public:
+ import_sheet(document& doc, sheet& sh, sheet_view* view);
+ virtual ~import_sheet() override;
+
+ virtual iface::import_sheet_view* get_sheet_view() override;
+ virtual iface::import_auto_filter* get_auto_filter() override;
+ virtual iface::import_conditional_format* get_conditional_format() override;
+ virtual iface::import_data_table* get_data_table() override;
+ virtual iface::import_named_expression* get_named_expression() override;
+ virtual iface::import_sheet_properties* get_sheet_properties() override;
+ virtual iface::import_table* get_table() override;
+ virtual iface::import_formula* get_formula() override;
+ virtual iface::import_array_formula* get_array_formula() override;
+ virtual void set_auto(row_t row, col_t col, std::string_view s) override;
+ virtual void set_bool(row_t row, col_t col, bool value) override;
+ virtual void set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second) override;
+ virtual void set_format(row_t row, col_t col, size_t xf_index) override;
+ virtual void set_format(row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t xf_index) override;
+ virtual void set_column_format(col_t col, col_t col_span, std::size_t xf_index) override;
+ virtual void set_row_format(row_t row, std::size_t xf_index) override;
+ virtual void set_string(row_t row, col_t col, string_id_t sindex) override;
+ virtual void set_value(row_t row, col_t col, double value) override;
+ virtual void fill_down_cells(row_t src_row, col_t src_col, row_t range_size) override;
+ virtual range_size_t get_sheet_size() const override;
+
+ void set_character_set(character_set_t charset);
+ void set_fill_missing_formula_results(bool b);
+ void set_formula_error_policy(formula_error_policy_t policy);
+};
+
+class import_sheet_view : public iface::import_sheet_view
+{
+ sheet_view& m_view;
+ sheet_t m_sheet_index;
+public:
+ import_sheet_view(sheet_view& view, sheet_t si);
+ virtual ~import_sheet_view();
+ virtual void set_sheet_active() override;
+
+ virtual void set_split_pane(
+ double hor_split, double ver_split,
+ const address_t& top_left_cell,
+ sheet_pane_t active_pane) override;
+
+ virtual void set_frozen_pane(
+ col_t visible_columns, row_t visible_rows,
+ const address_t& top_left_cell,
+ sheet_pane_t active_pane) override;
+
+ virtual void set_selected_range(sheet_pane_t pane, range_t range) override;
+};
+
+class export_sheet : public iface::export_sheet
+{
+ const document& m_doc;
+ const sheet& m_sheet;
+public:
+ export_sheet(const document& doc, const sheet& sh);
+ ~export_sheet();
+
+ virtual void write_string(std::ostream& os, row_t row, col_t col) const override;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_styles.cpp b/src/spreadsheet/factory_styles.cpp
new file mode 100644
index 0000000..91c6844
--- /dev/null
+++ b/src/spreadsheet/factory_styles.cpp
@@ -0,0 +1,870 @@
+/* -*- 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 "orcus/spreadsheet/factory.hpp"
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class import_font_style : public iface::import_font_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_font_style() = delete;
+ import_font_style(styles& _styles_model, string_pool& sp);
+ import_font_style(std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp);
+ virtual ~import_font_style() override;
+
+ virtual void set_bold(bool b) override;
+ virtual void set_bold_asian(bool b) override;
+ virtual void set_bold_complex(bool b) override;
+
+ virtual void set_italic(bool b) override;
+ virtual void set_italic_asian(bool b) override;
+ virtual void set_italic_complex(bool b) override;
+
+ virtual void set_name(std::string_view s) override;
+ virtual void set_name_asian(std::string_view s) override;
+ virtual void set_name_complex(std::string_view s) override;
+
+ virtual void set_size(double point) override;
+ virtual void set_size_asian(double point) override;
+ virtual void set_size_complex(double point) override;
+
+ virtual void set_underline(underline_t e) override;
+ virtual void set_underline_width(underline_width_t e) override;
+ virtual void set_underline_mode(underline_mode_t e) override;
+ virtual void set_underline_type(underline_type_t e) override;
+ virtual void set_underline_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_strikethrough_style(strikethrough_style_t s) override;
+ virtual void set_strikethrough_type(strikethrough_type_t s) override;
+ virtual void set_strikethrough_width(strikethrough_width_t s) override;
+ virtual void set_strikethrough_text(strikethrough_text_t s) override;
+ virtual std::size_t commit() override;
+
+ void reset();
+};
+
+class import_fill_style : public iface::import_fill_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_fill_style() = delete;
+ import_fill_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_fill_style() override;
+
+ virtual void set_pattern_type(fill_pattern_t fp) override;
+ virtual void set_fg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_bg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_border_style : public iface::import_border_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_border_style() = delete;
+ import_border_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_border_style() override;
+
+ virtual void set_style(border_direction_t dir, border_style_t style) override;
+ virtual void set_color(
+ border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) override;
+ virtual void set_width(border_direction_t dir, double width, orcus::length_unit_t unit) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_cell_protection : public iface::import_cell_protection
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_cell_protection() = delete;
+ import_cell_protection(styles& _styles_model, string_pool& sp);
+ virtual ~import_cell_protection() override;
+
+ virtual void set_hidden(bool b) override;
+ virtual void set_locked(bool b) override;
+ virtual void set_print_content(bool b) override;
+ virtual void set_formula_hidden(bool b) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_number_format : public iface::import_number_format
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_number_format() = delete;
+ import_number_format(styles& _styles_model, string_pool& sp);
+ virtual ~import_number_format() override;
+
+ virtual void set_identifier(std::size_t id) override;
+ virtual void set_code(std::string_view s) override;
+ virtual size_t commit() override;
+
+ void reset();
+};
+
+class import_xf : public iface::import_xf
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_xf() = delete;
+ import_xf(styles& _styles_model, string_pool& sp);
+ virtual ~import_xf() override;
+
+ virtual void set_font(size_t index) override;
+ virtual void set_fill(size_t index) override;
+ virtual void set_border(size_t index) override;
+ virtual void set_protection(size_t index) override;
+ virtual void set_number_format(size_t index) override;
+ virtual void set_style_xf(size_t index) override;
+ virtual void set_apply_alignment(bool b) override;
+ virtual void set_horizontal_alignment(hor_alignment_t align) override;
+ virtual void set_vertical_alignment(ver_alignment_t align) override;
+ virtual void set_wrap_text(bool b) override;
+ virtual void set_shrink_to_fit(bool b) override;
+ virtual size_t commit() override;
+
+ void reset(xf_category_t cat);
+};
+
+class import_cell_style : public iface::import_cell_style
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_cell_style() = delete;
+ import_cell_style(styles& _styles_model, string_pool& sp);
+ virtual ~import_cell_style() override;
+
+ void set_name(std::string_view s) override;
+ void set_display_name(std::string_view s) override;
+ void set_xf(size_t index) override;
+ void set_builtin(size_t index) override;
+ void set_parent_name(std::string_view s) override;
+ void commit() override;
+
+ void reset();
+};
+
+struct import_font_style::impl
+{
+ std::shared_ptr<import_factory_config> config;
+ styles& styles_model;
+ string_pool& str_pool;
+
+ std::unordered_map<font_t, std::size_t, font_t::hash> font_cache;
+ font_t cur_font;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ config(std::make_shared<import_factory_config>()),
+ styles_model(_styles_model),
+ str_pool(sp) {}
+
+ impl(std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp) :
+ config(_config), styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_font_style::import_font_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_font_style::import_font_style(
+ std::shared_ptr<import_factory_config> _config, styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_config, _styles_model, sp))
+{
+}
+
+import_font_style::~import_font_style() = default;
+
+void import_font_style::set_bold(bool b)
+{
+ mp_impl->cur_font.bold = b;
+}
+
+void import_font_style::set_bold_asian(bool b)
+{
+ mp_impl->cur_font.bold_asian = b;
+}
+
+void import_font_style::set_bold_complex(bool b)
+{
+ mp_impl->cur_font.bold_complex = b;
+}
+
+void import_font_style::set_italic(bool b)
+{
+ mp_impl->cur_font.italic = b;
+}
+
+void import_font_style::set_italic_asian(bool b)
+{
+ mp_impl->cur_font.italic_asian = b;
+}
+
+void import_font_style::set_italic_complex(bool b)
+{
+ mp_impl->cur_font.italic_complex = b;
+}
+
+void import_font_style::set_name(std::string_view s)
+{
+ mp_impl->cur_font.name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_name_asian(std::string_view s)
+{
+ mp_impl->cur_font.name_asian = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_name_complex(std::string_view s)
+{
+ mp_impl->cur_font.name_complex = mp_impl->str_pool.intern(s).first;
+}
+
+void import_font_style::set_size(double point)
+{
+ mp_impl->cur_font.size = point;
+}
+
+void import_font_style::set_size_asian(double point)
+{
+ mp_impl->cur_font.size_asian = point;
+}
+
+void import_font_style::set_size_complex(double point)
+{
+ mp_impl->cur_font.size_complex = point;
+}
+
+void import_font_style::set_underline(underline_t e)
+{
+ mp_impl->cur_font.underline_style = e;
+}
+
+void import_font_style::set_underline_width(underline_width_t e)
+{
+ mp_impl->cur_font.underline_width = e;
+}
+
+void import_font_style::set_underline_mode(underline_mode_t e)
+{
+ mp_impl->cur_font.underline_mode = e;
+}
+
+void import_font_style::set_underline_type(underline_type_t e)
+{
+ mp_impl->cur_font.underline_type = e;
+}
+
+void import_font_style::set_underline_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_font.underline_color = color_t(alpha, red, green, blue);
+}
+
+void import_font_style::set_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_font.color = color_t(alpha, red, green, blue);
+}
+
+void import_font_style::set_strikethrough_style(strikethrough_style_t s)
+{
+ mp_impl->cur_font.strikethrough_style = s;
+}
+
+void import_font_style::set_strikethrough_type(strikethrough_type_t s)
+{
+ mp_impl->cur_font.strikethrough_type = s;
+}
+
+void import_font_style::set_strikethrough_width(strikethrough_width_t s)
+{
+ mp_impl->cur_font.strikethrough_width = s;
+}
+
+void import_font_style::set_strikethrough_text(strikethrough_text_t s)
+{
+ mp_impl->cur_font.strikethrough_text = s;
+}
+
+std::size_t import_font_style::commit()
+{
+ if (mp_impl->config->enable_font_cache)
+ {
+ auto it = mp_impl->font_cache.find(mp_impl->cur_font);
+ if (it != mp_impl->font_cache.end())
+ return it->second;
+ }
+
+ std::size_t font_id = mp_impl->styles_model.append_font(mp_impl->cur_font);
+ mp_impl->font_cache.insert({mp_impl->cur_font, font_id});
+ mp_impl->cur_font.reset();
+ return font_id;
+}
+
+void import_font_style::reset()
+{
+ mp_impl->cur_font.reset();
+}
+
+struct import_fill_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ fill_t cur_fill;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_fill_style::import_fill_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_fill_style::~import_fill_style()
+{
+}
+
+void import_fill_style::set_pattern_type(fill_pattern_t fp)
+{
+ mp_impl->cur_fill.pattern_type = fp;
+}
+
+void import_fill_style::set_fg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_fill.fg_color = color_t{alpha, red, green, blue};
+}
+
+void import_fill_style::set_bg_color(color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ mp_impl->cur_fill.bg_color = color_t{alpha, red, green, blue};
+}
+
+size_t import_fill_style::commit()
+{
+ size_t fill_id = mp_impl->styles_model.append_fill(mp_impl->cur_fill);
+ mp_impl->cur_fill.reset();
+ return fill_id;
+}
+
+void import_fill_style::reset()
+{
+ mp_impl->cur_fill.reset();
+}
+
+struct import_border_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ border_t cur_border;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+
+ border_attrs_t* get_border_attrs(border_direction_t dir)
+ {
+ switch (dir)
+ {
+ case border_direction_t::top:
+ return &cur_border.top;
+ case border_direction_t::bottom:
+ return &cur_border.bottom;
+ case border_direction_t::left:
+ return &cur_border.left;
+ case border_direction_t::right:
+ return &cur_border.right;
+ case border_direction_t::diagonal:
+ return &cur_border.diagonal;
+ case border_direction_t::diagonal_bl_tr:
+ return &cur_border.diagonal_bl_tr;
+ case border_direction_t::diagonal_tl_br:
+ return &cur_border.diagonal_tl_br;
+ case border_direction_t::unknown:
+ ;
+ }
+
+ return nullptr;
+ }
+};
+
+import_border_style::import_border_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_border_style::~import_border_style()
+{
+}
+
+void import_border_style::set_style(border_direction_t dir, border_style_t style)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ v->style = style;
+}
+
+void import_border_style::set_color(
+ border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ v->border_color = color_t(alpha, red, green, blue);
+}
+
+void import_border_style::set_width(border_direction_t dir, double width, orcus::length_unit_t unit)
+{
+ border_attrs_t* v = mp_impl->get_border_attrs(dir);
+ if (!v)
+ return;
+
+ length_t bw{unit, width};
+ v->border_width = bw;
+}
+
+size_t import_border_style::commit()
+{
+ size_t border_id = mp_impl->styles_model.append_border(mp_impl->cur_border);
+ mp_impl->cur_border.reset();
+ return border_id;
+}
+
+void import_border_style::reset()
+{
+ mp_impl->cur_border.reset();
+}
+
+struct import_cell_protection::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ protection_t cur_protection;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_cell_protection::import_cell_protection(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_cell_protection::~import_cell_protection()
+{
+}
+
+void import_cell_protection::set_hidden(bool b)
+{
+ mp_impl->cur_protection.hidden = b;
+}
+
+void import_cell_protection::set_locked(bool b)
+{
+ mp_impl->cur_protection.locked = b;
+}
+
+void import_cell_protection::set_print_content(bool b)
+{
+ mp_impl->cur_protection.print_content = b;
+}
+
+void import_cell_protection::set_formula_hidden(bool b)
+{
+ mp_impl->cur_protection.formula_hidden = b;
+}
+
+std::size_t import_cell_protection::commit()
+{
+ std::size_t cp_id = mp_impl->styles_model.append_protection(mp_impl->cur_protection);
+ mp_impl->cur_protection.reset();
+ return cp_id;
+}
+
+void import_cell_protection::reset()
+{
+ mp_impl->cur_protection.reset();
+}
+
+struct import_number_format::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ number_format_t cur_numfmt;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_number_format::import_number_format(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_number_format::~import_number_format()
+{
+}
+
+void import_number_format::set_identifier(std::size_t id)
+{
+ mp_impl->cur_numfmt.identifier = id;
+}
+
+void import_number_format::set_code(std::string_view s)
+{
+ mp_impl->cur_numfmt.format_string = s;
+}
+
+size_t import_number_format::commit()
+{
+ std::size_t fmt_id = mp_impl->styles_model.append_number_format(mp_impl->cur_numfmt);
+ mp_impl->cur_numfmt.reset();
+
+ return fmt_id;
+}
+
+void import_number_format::reset()
+{
+ mp_impl->cur_numfmt.reset();
+}
+
+struct import_xf::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ cell_format_t cur_cell_format;
+ xf_category_t xf_category = xf_category_t::unknown;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_xf::import_xf(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_xf::~import_xf()
+{
+}
+
+void import_xf::set_font(size_t index)
+{
+ mp_impl->cur_cell_format.font = index;
+}
+
+void import_xf::set_fill(size_t index)
+{
+ mp_impl->cur_cell_format.fill = index;
+}
+
+void import_xf::set_border(size_t index)
+{
+ mp_impl->cur_cell_format.border = index;
+
+ // TODO : we need to decide whether to have interface methods for these
+ // apply_foo attributes. For now there is only one, for alignment.
+ mp_impl->cur_cell_format.apply_border = index > 0;
+}
+
+void import_xf::set_protection(size_t index)
+{
+ mp_impl->cur_cell_format.protection = index;
+}
+
+void import_xf::set_number_format(size_t index)
+{
+ mp_impl->cur_cell_format.number_format = index;
+}
+
+void import_xf::set_style_xf(size_t index)
+{
+ mp_impl->cur_cell_format.style_xf = index;
+}
+
+void import_xf::set_apply_alignment(bool b)
+{
+ mp_impl->cur_cell_format.apply_alignment = b;
+}
+
+void import_xf::set_horizontal_alignment(hor_alignment_t align)
+{
+ mp_impl->cur_cell_format.hor_align = align;
+}
+
+void import_xf::set_vertical_alignment(ver_alignment_t align)
+{
+ mp_impl->cur_cell_format.ver_align = align;
+}
+
+void import_xf::set_wrap_text(bool b)
+{
+ mp_impl->cur_cell_format.wrap_text = b;
+}
+
+void import_xf::set_shrink_to_fit(bool b)
+{
+ mp_impl->cur_cell_format.shrink_to_fit = b;
+}
+
+
+size_t import_xf::commit()
+{
+ size_t xf_id = 0;
+
+ switch (mp_impl->xf_category)
+ {
+ case xf_category_t::cell:
+ xf_id = mp_impl->styles_model.append_cell_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::cell_style:
+ xf_id = mp_impl->styles_model.append_cell_style_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::differential:
+ xf_id = mp_impl->styles_model.append_diff_cell_format(mp_impl->cur_cell_format);
+ break;
+ case xf_category_t::unknown:
+ throw std::logic_error("unknown cell format category");
+ }
+
+ mp_impl->cur_cell_format.reset();
+ return xf_id;
+}
+
+void import_xf::reset(xf_category_t cat)
+{
+ if (cat == xf_category_t::unknown)
+ throw std::invalid_argument("The specified category is 'unknown'.");
+
+ mp_impl->cur_cell_format.reset();
+ mp_impl->xf_category = cat;
+}
+
+struct import_cell_style::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ cell_style_t cur_cell_style;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model), str_pool(sp) {}
+};
+
+import_cell_style::import_cell_style(styles& _styles_model, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(_styles_model, sp))
+{
+}
+
+import_cell_style::~import_cell_style() {}
+
+void import_cell_style::set_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::set_display_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.display_name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::set_xf(size_t index)
+{
+ mp_impl->cur_cell_style.xf = index;
+}
+
+void import_cell_style::set_builtin(size_t index)
+{
+ mp_impl->cur_cell_style.builtin = index;
+}
+
+void import_cell_style::set_parent_name(std::string_view s)
+{
+ mp_impl->cur_cell_style.parent_name = mp_impl->str_pool.intern(s).first;
+}
+
+void import_cell_style::commit()
+{
+ mp_impl->styles_model.append_cell_style(mp_impl->cur_cell_style);
+ mp_impl->cur_cell_style.reset();
+}
+
+void import_cell_style::reset()
+{
+ mp_impl->cur_cell_style.reset();
+}
+
+} // anonymous namespace
+
+struct import_styles::impl
+{
+ styles& styles_model;
+ string_pool& str_pool;
+
+ import_font_style font_style;
+ import_fill_style fill_style;
+ import_border_style border_style;
+ import_cell_protection cell_protection;
+ import_number_format number_format;
+ import_xf xf;
+ import_cell_style cell_style;
+
+ impl(styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model),
+ str_pool(sp),
+ font_style(_styles_model, sp),
+ fill_style(_styles_model, sp),
+ border_style(_styles_model, sp),
+ cell_protection(_styles_model, sp),
+ number_format(_styles_model, sp),
+ xf(_styles_model, sp),
+ cell_style(_styles_model, sp)
+ {}
+
+ impl(std::shared_ptr<import_factory_config> config, styles& _styles_model, string_pool& sp) :
+ styles_model(_styles_model),
+ str_pool(sp),
+ font_style(config, _styles_model, sp),
+ fill_style(_styles_model, sp),
+ border_style(_styles_model, sp),
+ cell_protection(_styles_model, sp),
+ number_format(_styles_model, sp),
+ xf(_styles_model, sp),
+ cell_style(_styles_model, sp)
+ {}
+};
+
+import_styles::import_styles(styles& styles_store, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(styles_store, sp)) {}
+
+import_styles::import_styles(std::shared_ptr<import_factory_config> config, styles& styles_store, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(config, styles_store, sp)) {}
+
+import_styles::~import_styles() = default;
+
+iface::import_font_style* import_styles::start_font_style()
+{
+ mp_impl->font_style.reset();
+ return &mp_impl->font_style;
+}
+
+iface::import_fill_style* import_styles::start_fill_style()
+{
+ mp_impl->fill_style.reset();
+ return &mp_impl->fill_style;
+}
+
+iface::import_border_style* import_styles::start_border_style()
+{
+ mp_impl->border_style.reset();
+ return &mp_impl->border_style;
+}
+
+iface::import_cell_protection* import_styles::start_cell_protection()
+{
+ mp_impl->cell_protection.reset();
+ return &mp_impl->cell_protection;
+}
+
+iface::import_number_format* import_styles::start_number_format()
+{
+ mp_impl->number_format.reset();
+ return &mp_impl->number_format;
+}
+
+iface::import_xf* import_styles::start_xf(xf_category_t cat)
+{
+ mp_impl->xf.reset(cat);
+ return &mp_impl->xf;
+}
+
+iface::import_cell_style* import_styles::start_cell_style()
+{
+ mp_impl->cell_style.reset();
+ return &mp_impl->cell_style;
+}
+
+void import_styles::set_font_count(size_t n)
+{
+ mp_impl->styles_model.reserve_font_store(n);
+}
+
+void import_styles::set_fill_count(size_t n)
+{
+ mp_impl->styles_model.reserve_fill_store(n);
+}
+
+void import_styles::set_border_count(size_t n)
+{
+ mp_impl->styles_model.reserve_border_store(n);
+}
+
+void import_styles::set_number_format_count(size_t n)
+{
+ mp_impl->styles_model.reserve_number_format_store(n);
+}
+
+void import_styles::set_xf_count(xf_category_t cat, size_t n)
+{
+ switch (cat)
+ {
+ case xf_category_t::cell:
+ mp_impl->styles_model.reserve_cell_format_store(n);
+ break;
+ case xf_category_t::cell_style:
+ mp_impl->styles_model.reserve_cell_style_format_store(n);
+ break;
+ case xf_category_t::differential:
+ mp_impl->styles_model.reserve_diff_cell_format_store(n);
+ break;
+ case xf_category_t::unknown:
+ break;
+ }
+}
+
+void import_styles::set_cell_style_count(size_t n)
+{
+ mp_impl->styles_model.reserve_cell_style_store(n);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_table.cpp b/src/spreadsheet/factory_table.cpp
new file mode 100644
index 0000000..a77b7af
--- /dev/null
+++ b/src/spreadsheet/factory_table.cpp
@@ -0,0 +1,213 @@
+/* -*- 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 "factory_table.hpp"
+#include "formula_global.hpp"
+
+#include "orcus/string_pool.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/auto_filter.hpp"
+
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+class table_auto_filter : public iface::import_auto_filter
+{
+ string_pool& m_pool;
+ sheet_t m_sheet_pos;
+ col_t m_cur_col;
+ auto_filter_column_t m_cur_col_data;
+ auto_filter_t m_filter_data;
+
+ auto_filter_t* mp_data;
+
+public:
+ table_auto_filter(document& doc, sheet& sh) :
+ m_pool(doc.get_string_pool()),
+ m_sheet_pos(sh.get_index()),
+ m_cur_col(-1),
+ mp_data(nullptr) {}
+
+ void reset(auto_filter_t* data)
+ {
+ mp_data = data;
+ m_cur_col = -1;
+ m_cur_col_data.reset();
+ m_filter_data.reset();
+ }
+
+ virtual void set_range(const range_t& range)
+ {
+ m_filter_data.range = to_abs_range(range, m_sheet_pos);
+ }
+
+ virtual void set_column(orcus::spreadsheet::col_t col)
+ {
+ m_cur_col = col;
+ }
+
+ virtual void append_column_match_value(std::string_view value)
+ {
+ // The string pool belongs to the document.
+ value = m_pool.intern(value).first;
+ m_cur_col_data.match_values.insert(value);
+ };
+
+ virtual void commit_column()
+ {
+ m_filter_data.commit_column(m_cur_col, m_cur_col_data);
+ m_cur_col_data.reset();
+ }
+
+ virtual void commit()
+ {
+ if (!mp_data)
+ return;
+
+ mp_data->swap(m_filter_data);
+ }
+};
+
+}
+
+struct import_table::impl
+{
+ document& m_doc;
+ sheet& m_sheet;
+
+ table_auto_filter m_auto_filter;
+
+ std::unique_ptr<table_t> mp_data;
+ table_column_t m_column;
+
+ impl(const impl&) = delete;
+ impl& operator=(const impl&) = delete;
+
+ impl(document& doc, sheet& sh) :
+ m_doc(doc), m_sheet(sh), m_auto_filter(doc, sh) {}
+};
+
+import_table::import_table(document& doc, sheet& sh) : mp_impl(std::make_unique<impl>(doc, sh)) {}
+
+import_table::~import_table() {}
+
+iface::import_auto_filter* import_table::get_auto_filter()
+{
+ mp_impl->m_auto_filter.reset(&mp_impl->mp_data->filter);
+ return &mp_impl->m_auto_filter;
+}
+
+void import_table::set_range(const range_t& range)
+{
+ mp_impl->mp_data->range = to_abs_range(range, mp_impl->m_sheet.get_index());
+}
+
+void import_table::set_identifier(size_t id)
+{
+ mp_impl->mp_data->identifier = id;
+}
+
+void import_table::set_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->mp_data->name = sp.intern(name).first;
+}
+
+void import_table::set_display_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->mp_data->display_name = sp.intern(name).first;
+}
+
+void import_table::set_totals_row_count(size_t row_count)
+{
+ mp_impl->mp_data->totals_row_count = row_count;
+}
+
+void import_table::set_column_count(size_t n)
+{
+ mp_impl->mp_data->columns.reserve(n);
+}
+
+void import_table::set_column_identifier(size_t id)
+{
+ mp_impl->m_column.identifier = id;
+}
+
+void import_table::set_column_name(std::string_view name)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->m_column.name = sp.intern(name).first;
+}
+
+void import_table::set_column_totals_row_label(std::string_view label)
+{
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ mp_impl->m_column.totals_row_label = sp.intern(label).first;
+}
+
+void import_table::set_column_totals_row_function(orcus::spreadsheet::totals_row_function_t func)
+{
+ mp_impl->m_column.totals_row_function = func;
+}
+
+void import_table::commit_column()
+{
+ mp_impl->mp_data->columns.push_back(mp_impl->m_column);
+ mp_impl->m_column.reset();
+}
+
+void import_table::set_style_name(std::string_view name)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ string_pool& sp = mp_impl->m_doc.get_string_pool();
+ style.name = sp.intern(name).first;
+}
+
+void import_table::set_style_show_first_column(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_first_column = b;
+}
+
+void import_table::set_style_show_last_column(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_last_column = b;
+}
+
+void import_table::set_style_show_row_stripes(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_row_stripes = b;
+}
+
+void import_table::set_style_show_column_stripes(bool b)
+{
+ table_style_t& style = mp_impl->mp_data->style;
+ style.show_column_stripes = b;
+}
+
+void import_table::commit()
+{
+ mp_impl->m_doc.insert_table(mp_impl->mp_data.release());
+ mp_impl->mp_data.reset(new table_t);
+}
+
+void import_table::reset()
+{
+ mp_impl->mp_data.reset(new table_t);
+ mp_impl->m_column.reset();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/factory_table.hpp b/src/spreadsheet/factory_table.hpp
new file mode 100644
index 0000000..0a274b4
--- /dev/null
+++ b/src/spreadsheet/factory_table.hpp
@@ -0,0 +1,60 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_TABLE_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_TABLE_HPP
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <memory>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class sheet;
+
+class import_table : public iface::import_table
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_table(document& doc, sheet& sh);
+ ~import_table();
+
+ virtual iface::import_auto_filter* get_auto_filter() override;
+
+ virtual void set_range(const range_t& range) override;
+ virtual void set_identifier(size_t id) override;
+ virtual void set_name(std::string_view name) override;
+ virtual void set_display_name(std::string_view name) override;
+ virtual void set_totals_row_count(size_t row_count) override;
+
+ virtual void set_column_count(size_t n) override;
+
+ virtual void set_column_identifier(size_t id) override;
+ virtual void set_column_name(std::string_view name) override;
+ virtual void set_column_totals_row_label(std::string_view label) override;
+ virtual void set_column_totals_row_function(orcus::spreadsheet::totals_row_function_t func) override;
+ virtual void commit_column() override;
+
+ virtual void set_style_name(std::string_view name) override;
+ virtual void set_style_show_first_column(bool b) override;
+ virtual void set_style_show_last_column(bool b) override;
+ virtual void set_style_show_row_stripes(bool b) override;
+ virtual void set_style_show_column_stripes(bool b) override;
+
+ virtual void commit() override;
+
+ void reset();
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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: */
diff --git a/src/spreadsheet/flat_dumper.hpp b/src/spreadsheet/flat_dumper.hpp
new file mode 100644
index 0000000..2a72938
--- /dev/null
+++ b/src/spreadsheet/flat_dumper.hpp
@@ -0,0 +1,36 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FLAT_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FLAT_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class flat_dumper
+{
+ const document& m_doc;
+
+public:
+ flat_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/formula_global.cpp b/src/spreadsheet/formula_global.cpp
new file mode 100644
index 0000000..a4d7c6d
--- /dev/null
+++ b/src/spreadsheet/formula_global.cpp
@@ -0,0 +1,56 @@
+/* -*- 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 "formula_global.hpp"
+
+#include <ixion/address.hpp>
+#include <ixion/formula_name_resolver.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+ixion::abs_range_t to_abs_range(
+ const ixion::formula_name_resolver& resolver, const char* p_ref, size_t n_ref)
+{
+ ixion::abs_range_t range(ixion::abs_range_t::invalid);
+ ixion::abs_address_t pos(0,0,0);
+
+ ixion::formula_name_t res = resolver.resolve({p_ref, n_ref}, pos);
+ switch (res.type)
+ {
+ case ixion::formula_name_t::cell_reference:
+ // Single cell reference.
+ range.first = std::get<ixion::address_t>(res.value).to_abs(pos);
+ range.last = range.first;
+ break;
+ case ixion::formula_name_t::range_reference:
+ // Range reference.
+ range = std::get<ixion::range_t>(res.value).to_abs(pos);
+ break;
+ default:
+ ; // Unsupported range. Leave it invalid.
+ }
+
+ return range;
+}
+
+ixion::abs_range_t to_abs_range(const range_t& range, sheet_t sheet_pos)
+{
+ ixion::abs_range_t ret;
+ ret.first.column = range.first.column;
+ ret.first.row = range.first.row;
+ ret.first.sheet = sheet_pos;
+
+ ret.last.column = range.last.column;
+ ret.last.row = range.last.row;
+ ret.last.sheet = sheet_pos;
+
+ return ret;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/formula_global.hpp b/src/spreadsheet/formula_global.hpp
new file mode 100644
index 0000000..9f43a65
--- /dev/null
+++ b/src/spreadsheet/formula_global.hpp
@@ -0,0 +1,48 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_FORMULA_GLOBAL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_FORMULA_GLOBAL_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <cstdlib>
+
+namespace ixion {
+
+struct abs_range_t;
+class formula_name_resolver;
+
+}
+
+namespace orcus { namespace spreadsheet {
+
+struct range_t;
+
+/**
+ * Parse a string representing a 2-dimensional range using the passed name
+ * resolver, and return an absolute range object. The sheet index will be
+ * unconditionally set to 0. It returns an invalid range object in case the
+ * parsing fails.
+ *
+ * @param resolver name resolver to use to resolve the range string.
+ * @param p_ref pointer to the first character of the range string.
+ * @param n_ref length of the range string.
+ *
+ * @return absolute range object, which may be set invalid in case the
+ * parsing is unsuccessful.
+ */
+ixion::abs_range_t to_abs_range(
+ const ixion::formula_name_resolver& resolver, const char* p_ref, size_t n_ref);
+
+ixion::abs_range_t to_abs_range(const range_t& range, sheet_t sheet_pos);
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/global_settings.cpp b/src/spreadsheet/global_settings.cpp
new file mode 100644
index 0000000..71778bd
--- /dev/null
+++ b/src/spreadsheet/global_settings.cpp
@@ -0,0 +1,50 @@
+/* -*- 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 "global_settings.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/factory.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+struct import_global_settings::impl
+{
+ import_factory& m_factory;
+ document& m_doc;
+
+ impl(import_factory& factory, document& doc) :
+ m_factory(factory), m_doc(doc) {}
+};
+
+import_global_settings::import_global_settings(import_factory& factory, document& doc) :
+ mp_impl(std::make_unique<impl>(factory, doc)) {}
+
+import_global_settings::~import_global_settings() {}
+
+void import_global_settings::set_origin_date(int year, int month, int day)
+{
+ mp_impl->m_doc.set_origin_date(year, month, day);
+}
+
+void import_global_settings::set_default_formula_grammar(formula_grammar_t grammar)
+{
+ mp_impl->m_doc.set_formula_grammar(grammar);
+}
+
+formula_grammar_t import_global_settings::get_default_formula_grammar() const
+{
+ return mp_impl->m_doc.get_formula_grammar();
+}
+
+void import_global_settings::set_character_set(character_set_t charset)
+{
+ mp_impl->m_factory.set_character_set(charset);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/global_settings.hpp b/src/spreadsheet/global_settings.hpp
new file mode 100644
index 0000000..8213833
--- /dev/null
+++ b/src/spreadsheet/global_settings.hpp
@@ -0,0 +1,41 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_GLOBAL_SETTINGS_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_GLOBAL_SETTINGS_HPP
+
+#include "orcus/spreadsheet/import_interface.hpp"
+
+#include <memory>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class import_factory;
+
+class import_global_settings : public spreadsheet::iface::import_global_settings
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ import_global_settings(import_factory& factory, document& doc);
+ virtual ~import_global_settings() override;
+
+ virtual void set_origin_date(int year, int month, int day) override;
+
+ virtual void set_default_formula_grammar(orcus::spreadsheet::formula_grammar_t grammar) override;
+
+ virtual orcus::spreadsheet::formula_grammar_t get_default_formula_grammar() const override;
+
+ virtual void set_character_set(character_set_t charset) override;
+};
+
+}}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/html_dumper.cpp b/src/spreadsheet/html_dumper.cpp
new file mode 100644
index 0000000..cdf04de
--- /dev/null
+++ b/src/spreadsheet/html_dumper.cpp
@@ -0,0 +1,695 @@
+/* -*- 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 "html_dumper.hpp"
+#include "impl_types.hpp"
+#include "number_format.hpp"
+
+#include "orcus/spreadsheet/styles.hpp"
+#include "orcus/spreadsheet/shared_strings.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/spreadsheet/sheet.hpp"
+
+#include <ixion/address.hpp>
+#include <ixion/model_context.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/formula_result.hpp>
+#include <ixion/cell.hpp>
+
+#include <sstream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+namespace {
+
+void build_rgb_color(std::ostringstream& os, const color_t& color_value)
+{
+ // Special colors.
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 0 && color_value.blue == 0)
+ {
+ os << "black";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 255 && color_value.green == 0 && color_value.blue == 0)
+ {
+ os << "red";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 255 && color_value.blue == 0)
+ {
+ os << "green";
+ return;
+ }
+
+ if (color_value.alpha == 255 && color_value.red == 0 && color_value.green == 0 && color_value.blue == 255)
+ {
+ os << "blue";
+ return;
+ }
+
+ os << "rgb("
+ << static_cast<short>(color_value.red) << ","
+ << static_cast<short>(color_value.green) << ","
+ << static_cast<short>(color_value.blue) << ")";
+}
+
+const char* css_style_global =
+"table, td { "
+ "border-collapse : collapse; "
+"}\n"
+
+"table { "
+ "border-spacing : 0px; "
+"}\n"
+
+"td { "
+ "width : 1in; border: 1px solid lightgray; "
+"}\n"
+
+"td.empty { "
+ "color : white; "
+"}\n";
+
+class html_elem
+{
+public:
+ struct attr
+ {
+ std::string name;
+ std::string value;
+
+ attr(const std::string& _name, const std::string& _value) : name(_name), value(_value) {}
+ };
+
+ typedef std::vector<attr> attrs_type;
+
+ html_elem(std::ostream& strm, const char* name, const char* style = nullptr, const char* style_class = nullptr) :
+ m_strm(strm), m_name(name)
+ {
+ m_strm << '<' << m_name;
+
+ if (style)
+ m_strm << " style=\"" << style << "\"";
+
+ if (style_class)
+ m_strm << " class=\"" << style_class << "\"";
+
+ m_strm << '>';
+ }
+
+ html_elem(std::ostream& strm, const char* name, const attrs_type& attrs) :
+ m_strm(strm), m_name(name)
+ {
+ m_strm << '<' << m_name;
+
+ attrs_type::const_iterator it = attrs.begin(), it_end = attrs.end();
+ for (; it != it_end; ++it)
+ m_strm << " " << it->name << "=\"" << it->value << "\"";
+
+ m_strm << '>';
+ }
+
+ ~html_elem()
+ {
+ m_strm << "</" << m_name << '>';
+ }
+
+private:
+ std::ostream& m_strm;
+ const char* m_name;
+};
+
+void print_formatted_text(std::ostream& strm, const std::string& text, const format_runs_t& formats)
+{
+ typedef html_elem elem;
+
+ const char* p_span = "span";
+
+ size_t pos = 0;
+ format_runs_t::const_iterator itr = formats.begin(), itr_end = formats.end();
+ for (; itr != itr_end; ++itr)
+ {
+ const format_run& run = *itr;
+ if (pos < run.pos)
+ {
+ // flush unformatted text.
+ strm << std::string(&text[pos], run.pos-pos);
+ pos = run.pos;
+ }
+
+ if (!run.size)
+ continue;
+
+ std::string style = "";
+ if (run.bold)
+ style += "font-weight: bold;";
+ else
+ style += "font-weight: normal;";
+
+ if (run.italic)
+ style += "font-style: italic;";
+ else
+ style += "font-style: normal;";
+
+ if (!run.font.empty())
+ {
+ style += "font-family: ";
+ style += run.font;
+ style += ";";
+ }
+
+ if (run.font_size)
+ {
+ std::ostringstream os;
+ os << "font-size: " << run.font_size << "pt;";
+ style += os.str();
+ }
+
+ const color_t& col = run.color;
+ if (col.red || col.green || col.blue)
+ {
+ std::ostringstream os;
+ os << "color: ";
+ build_rgb_color(os, col);
+ os << ";";
+ style += os.str();
+ }
+
+ if (style.empty())
+ strm << std::string(&text[pos], run.size);
+ else
+ {
+ elem span(strm, p_span, style.c_str());
+ strm << std::string(&text[pos], run.size);
+ }
+
+ pos += run.size;
+ }
+
+ if (pos < text.size())
+ {
+ // flush the remaining unformatted text.
+ strm << std::string(&text[pos], text.size() - pos);
+ }
+}
+
+void build_border_style(std::ostringstream& os, const char* style_name, const border_attrs_t& attrs)
+{
+ if (!attrs.style || *attrs.style == border_style_t::none)
+ return;
+
+ os << style_name << ": ";
+ switch (*attrs.style)
+ {
+ case border_style_t::thin:
+ {
+ os << "solid 1px ";
+ break;
+ }
+ case border_style_t::medium:
+ {
+ os << "solid 2px ";
+ break;
+ }
+ case border_style_t::thick:
+ {
+ os << "solid 3px ";
+ break;
+ }
+ case border_style_t::hair:
+ {
+ os << "solid 0.5px ";
+ break;
+ }
+ case border_style_t::dotted:
+ {
+ os << "dotted 1px ";
+ break;
+ }
+ case border_style_t::dashed:
+ {
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::double_border:
+ {
+ os << "3px double ";
+ break;
+ }
+ case border_style_t::dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::dash_dot_dot:
+ {
+ // CSS doesn't support dash-dot-dot.
+ os << "dashed 1px ";
+ break;
+ }
+ case border_style_t::medium_dashed:
+ {
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::medium_dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::medium_dash_dot_dot:
+ {
+ // CSS doesn't support dash-dot-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ case border_style_t::slant_dash_dot:
+ {
+ // CSS doesn't support dash-dot.
+ os << "dashed 2px ";
+ break;
+ }
+ default:;
+ }
+
+ build_rgb_color(os, *attrs.border_color);
+ os << "; ";
+}
+
+void build_style_string(std::string& str, const styles& styles, const cell_format_t& fmt)
+{
+ std::ostringstream os;
+
+ {
+ const font_t* p = styles.get_font(fmt.font);
+ if (p)
+ {
+ if (p->name && !p->name.value().empty())
+ os << "font-family: " << *p->name << ";";
+ if (p->size)
+ os << "font-size: " << *p->size << "pt;";
+ if (p->bold && *p->bold)
+ os << "font-weight: bold;";
+ if (p->italic && *p->italic)
+ os << "font-style: italic;";
+
+ if (p->color)
+ {
+ const color_t& r = *p->color;
+ if (r.red || r.green || r.blue)
+ {
+ os << "color: ";
+ build_rgb_color(os, r);
+ os << ";";
+ }
+ }
+ }
+ }
+
+ {
+ const fill_t* p = styles.get_fill(fmt.fill);
+ if (p)
+ {
+ if (p->pattern_type && *p->pattern_type == fill_pattern_t::solid && p->fg_color)
+ {
+ const color_t& r = *p->fg_color;
+ os << "background-color: ";
+ build_rgb_color(os, r);
+ os << ";";
+ }
+ }
+ }
+
+ {
+ const border_t* p = styles.get_border(fmt.border);
+ if (p)
+ {
+ build_border_style(os, "border-top", p->top);
+ build_border_style(os, "border-bottom", p->bottom);
+ build_border_style(os, "border-left", p->left);
+ build_border_style(os, "border-right", p->right);
+ }
+ }
+
+ if (fmt.apply_alignment)
+ {
+ if (fmt.hor_align != hor_alignment_t::unknown)
+ {
+ os << "text-align: ";
+ switch (fmt.hor_align)
+ {
+ case hor_alignment_t::left:
+ os << "left";
+ break;
+ case hor_alignment_t::center:
+ os << "center";
+ break;
+ case hor_alignment_t::right:
+ os << "right";
+ break;
+ default:
+ ;
+ }
+ os << ";";
+ }
+
+ if (fmt.ver_align != ver_alignment_t::unknown)
+ {
+ os << "vertical-align: ";
+ switch (fmt.ver_align)
+ {
+ case ver_alignment_t::top:
+ os << "top";
+ break;
+ case ver_alignment_t::middle:
+ os << "middle";
+ break;
+ case ver_alignment_t::bottom:
+ os << "bottom";
+ break;
+ default:
+ ;
+ }
+ os << ";";
+ }
+ }
+
+ str += os.str();
+}
+
+void dump_html_head(std::ostream& os)
+{
+ typedef html_elem elem;
+
+ const char* p_head = "head";
+ const char* p_style = "style";
+
+ elem elem_head(os, p_head);
+ {
+ elem elem_style(os, p_style);
+ os << css_style_global;
+ }
+}
+
+void build_html_elem_attributes(html_elem::attrs_type& attrs, const std::string& style, const merge_size* p_merge_size)
+{
+ attrs.push_back(html_elem::attr("style", style));
+ if (p_merge_size)
+ {
+ if (p_merge_size->width > 1)
+ {
+ std::ostringstream os2;
+ os2 << p_merge_size->width;
+ attrs.push_back(html_elem::attr("colspan", os2.str()));
+ }
+
+ if (p_merge_size->height > 1)
+ {
+ std::ostringstream os2;
+ os2 << p_merge_size->height;
+ attrs.push_back(html_elem::attr("rowspan", os2.str()));
+ }
+ }
+}
+
+}
+
+html_dumper::html_dumper(
+ const document& doc,
+ const col_merge_size_type& merge_ranges,
+ sheet_t sheet_id) :
+ m_doc(doc),
+ m_merge_ranges(merge_ranges),
+ m_sheet_id(sheet_id)
+{
+ build_overlapped_ranges();
+}
+
+void html_dumper::dump(std::ostream& os) const
+{
+ const sheet* sh = m_doc.get_sheet(m_sheet_id);
+ if (!sh)
+ return;
+
+ typedef html_elem elem;
+
+ const char* p_html = "html";
+ const char* p_body = "body";
+ const char* p_table = "table";
+ const char* p_tr = "tr";
+ const char* p_td = "td";
+
+ ixion::abs_range_t range = sh->get_data_range();
+
+ elem root(os, p_html);
+ dump_html_head(os);
+
+ {
+ elem elem_body(os, p_body);
+
+ if (!range.valid())
+ // Sheet is empty. Nothing to print.
+ return;
+
+ const ixion::model_context& cxt = m_doc.get_model_context();
+ const ixion::formula_name_resolver* resolver =
+ m_doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global);
+ const shared_strings& sstrings = m_doc.get_shared_strings();
+
+ elem table(os, p_table);
+
+ row_t row_count = range.last.row + 1;
+ col_t col_count = range.last.column + 1;
+ for (row_t row = 0; row < row_count; ++row)
+ {
+ // Set the row height.
+ std::string row_style;
+ row_height_t rh = sh->get_row_height(row, nullptr, nullptr);
+
+ // Convert height from twip to inches.
+ if (rh != get_default_row_height())
+ {
+ std::string style;
+ double val = orcus::convert(rh, length_unit_t::twip, length_unit_t::inch);
+ std::ostringstream os_style;
+ os_style << "height: " << val << "in;";
+ row_style += os_style.str();
+ }
+
+ const char* style_str = nullptr;
+ if (!row_style.empty())
+ style_str = row_style.c_str();
+ elem tr(os, p_tr, style_str);
+
+ const detail::overlapped_col_index_type* p_overlapped = get_overlapped_ranges(row);
+
+ for (col_t col = 0; col < col_count; ++col)
+ {
+ ixion::abs_address_t pos(m_sheet_id, row, col);
+
+ const merge_size* p_merge_size = get_merge_size(row, col);
+ if (!p_merge_size && p_overlapped)
+ {
+ // Check if this cell is overlapped by a merged cell.
+ col_t overlapped_origin = -1;
+ col_t last_col = -1;
+ if (p_overlapped->search_tree(col, overlapped_origin, nullptr, &last_col).second && overlapped_origin >= 0)
+ {
+ // Skip all overlapped cells on this row.
+ col = last_col - 1;
+ continue;
+ }
+ }
+ size_t xf_id = sh->get_cell_format(row, col);
+ std::string style;
+
+ if (row == 0)
+ {
+ // Set the column width.
+ col_width_t cw = sh->get_col_width(col, nullptr, nullptr);
+
+ // Convert width from twip to inches.
+ if (cw != get_default_column_width())
+ {
+ double val = orcus::convert(cw, length_unit_t::twip, length_unit_t::inch);
+ std::ostringstream os_style;
+ os_style << "width: " << val << "in;";
+ style += os_style.str();
+ }
+ }
+
+ {
+ // Apply cell format.
+ const styles& styles = m_doc.get_styles();
+ const cell_format_t* fmt = styles.get_cell_format(xf_id);
+ if (fmt)
+ build_style_string(style, styles, *fmt);
+ }
+
+ ixion::celltype_t ct = cxt.get_celltype(pos);
+ if (ct == ixion::celltype_t::empty)
+ {
+ html_elem::attrs_type attrs;
+ build_html_elem_attributes(attrs, style, p_merge_size);
+ attrs.push_back(html_elem::attr("class", "empty"));
+ elem td(os, p_td, attrs);
+ os << '-'; // empty cell.
+ continue;
+ }
+
+ html_elem::attrs_type attrs;
+ build_html_elem_attributes(attrs, style, p_merge_size);
+ elem td(os, p_td, attrs);
+
+ switch (ct)
+ {
+ case ixion::celltype_t::string:
+ {
+ size_t sindex = cxt.get_string_identifier(pos);
+ const std::string* p = cxt.get_string(sindex);
+ assert(p);
+ const format_runs_t* pformat = sstrings.get_format_runs(sindex);
+ if (pformat)
+ print_formatted_text(os, *p, *pformat);
+ else
+ os << *p;
+
+ break;
+ }
+ case ixion::celltype_t::numeric:
+ format_to_file_output(os, cxt.get_numeric_value(pos));
+ break;
+ case ixion::celltype_t::boolean:
+ os << (cxt.get_boolean_value(pos) ? "true" : "false");
+ break;
+ case ixion::celltype_t::formula:
+ {
+ // print the formula and the formula result.
+ const ixion::formula_cell* cell = cxt.get_formula_cell(pos);
+ assert(cell);
+ const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts)
+ {
+ const ixion::formula_tokens_t& tokens = ts->get();
+
+ std::string formula;
+ if (resolver)
+ {
+ pos = cell->get_parent_position(pos);
+ formula = ixion::print_formula_tokens(
+ m_doc.get_model_context(), pos, *resolver, tokens);
+ }
+ else
+ formula = "???";
+
+ ixion::formula_group_t fg = cell->get_group_properties();
+
+ if (fg.grouped)
+ os << '{' << formula << '}';
+ else
+ os << formula;
+
+ try
+ {
+ ixion::formula_result res = cell->get_result_cache(
+ ixion::formula_result_wait_policy_t::throw_exception);
+ os << " (" << res.str(m_doc.get_model_context()) << ")";
+ }
+ catch (const std::exception&)
+ {
+ os << " (#RES!)";
+ }
+ }
+
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+ }
+}
+
+const overlapped_col_index_type* html_dumper::get_overlapped_ranges(row_t row) const
+{
+ overlapped_cells_type::const_iterator it = m_overlapped_ranges.find(row);
+ if (it == m_overlapped_ranges.end())
+ return nullptr;
+
+ return it->second.get();
+}
+
+const merge_size* html_dumper::get_merge_size(row_t row, col_t col) const
+{
+ col_merge_size_type::const_iterator it_col = m_merge_ranges.find(col);
+ if (it_col == m_merge_ranges.end())
+ return nullptr;
+
+ merge_size_type& col_merge_sizes = *it_col->second;
+ merge_size_type::const_iterator it_row = col_merge_sizes.find(row);
+ if (it_row == col_merge_sizes.end())
+ return nullptr;
+
+ return &it_row->second;
+}
+
+void html_dumper::build_overlapped_ranges()
+{
+ const sheet* sh = m_doc.get_sheet(m_sheet_id);
+ if (!sh)
+ return;
+
+ range_size_t sheet_size = m_doc.get_sheet_size();
+
+ detail::col_merge_size_type::const_iterator it_col = m_merge_ranges.begin(), it_col_end = m_merge_ranges.end();
+ for (; it_col != it_col_end; ++it_col)
+ {
+ col_t col = it_col->first;
+ const detail::merge_size_type& data = *it_col->second;
+ detail::merge_size_type::const_iterator it = data.begin(), it_end = data.end();
+ for (; it != it_end; ++it)
+ {
+ row_t row = it->first;
+ const detail::merge_size& item = it->second;
+ for (row_t i = 0; i < item.height; ++i, ++row)
+ {
+ // Get the container for this row.
+ detail::overlapped_cells_type::iterator it_cont = m_overlapped_ranges.find(row);
+ if (it_cont == m_overlapped_ranges.end())
+ {
+ auto p = std::make_unique<detail::overlapped_col_index_type>(0, sheet_size.columns, -1);
+ std::pair<detail::overlapped_cells_type::iterator, bool> r =
+ m_overlapped_ranges.insert(detail::overlapped_cells_type::value_type(row, std::move(p)));
+
+ if (!r.second)
+ {
+ // Insertion failed.
+ return;
+ }
+
+ it_cont = r.first;
+ }
+
+ detail::overlapped_col_index_type& cont = *it_cont->second;
+ cont.insert_back(col, col+item.width, col);
+ }
+ }
+ }
+
+ // Build trees.
+ for (auto& range : m_overlapped_ranges)
+ range.second->build_tree();
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/html_dumper.hpp b/src/spreadsheet/html_dumper.hpp
new file mode 100644
index 0000000..4e66809
--- /dev/null
+++ b/src/spreadsheet/html_dumper.hpp
@@ -0,0 +1,49 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_HTML_DUMPER_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_HTML_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+#include <ixion/types.hpp>
+
+#include "impl_types.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class html_dumper
+{
+ const document& m_doc;
+ overlapped_cells_type m_overlapped_ranges;
+ const col_merge_size_type& m_merge_ranges;
+ sheet_t m_sheet_id;
+
+ const overlapped_col_index_type* get_overlapped_ranges(row_t row) const;
+ const merge_size* get_merge_size(row_t row, col_t col) const;
+
+ void build_overlapped_ranges();
+
+public:
+ html_dumper(
+ const document& doc,
+ const col_merge_size_type& merge_ranges,
+ sheet_t sheet_id);
+
+ void dump(std::ostream& os) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/src/spreadsheet/impl_types.hpp b/src/spreadsheet/impl_types.hpp
new file mode 100644
index 0000000..bed30db
--- /dev/null
+++ b/src/spreadsheet/impl_types.hpp
@@ -0,0 +1,40 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_DETAIL_IMPL_TYPES_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_DETAIL_IMPL_TYPES_HPP
+
+#include "orcus/spreadsheet/types.hpp"
+
+#include <mdds/flat_segment_tree.hpp>
+#include <unordered_map>
+#include <memory>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+struct merge_size
+{
+ col_t width;
+ row_t height;
+
+ merge_size(col_t _width, row_t _height) :
+ width(_width), height(_height) {}
+};
+
+// Merged cell data stored in sheet.
+typedef std::unordered_map<row_t, detail::merge_size> merge_size_type;
+typedef std::unordered_map<col_t, std::unique_ptr<merge_size_type>> col_merge_size_type;
+
+// Overlapped cells per row, used when rendering sheet content.
+typedef mdds::flat_segment_tree<col_t, col_t> overlapped_col_index_type;
+typedef std::unordered_map<row_t, std::unique_ptr<overlapped_col_index_type>> overlapped_cells_type;
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/json_dumper.cpp b/src/spreadsheet/json_dumper.cpp
new file mode 100644
index 0000000..3fe6184
--- /dev/null
+++ b/src/spreadsheet/json_dumper.cpp
@@ -0,0 +1,95 @@
+/* -*- 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 "json_dumper.hpp"
+#include "dumper_global.hpp"
+
+#include "orcus/json_global.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+#include <ixion/formula_name_resolver.hpp>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+json_dumper::json_dumper(const document& doc) : m_doc(doc) {}
+
+void json_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 data_range = cxt.get_data_range(sheet_id);
+ if (!data_range.valid())
+ return;
+
+ ixion::abs_rc_range_t iter_range;
+ iter_range.first.column = 0;
+ iter_range.first.row = 0;
+ iter_range.last.column = data_range.last.column;
+ iter_range.last.row = data_range.last.row;
+
+ auto iter = cxt.get_model_iterator(
+ sheet_id, ixion::rc_direction_t::horizontal, iter_range);
+
+ std::vector<std::string> column_labels;
+ column_labels.reserve(data_range.last.column+1);
+
+ // Get the column labels.
+ auto resolver = ixion::formula_name_resolver::get(ixion::formula_name_resolver_t::excel_a1, &cxt);
+ for (ixion::col_t i = 0; i <= data_range.last.column; ++i)
+ column_labels.emplace_back(resolver->get_column_name(i));
+
+ os << "[" << std::endl;
+
+ ixion::row_t row = iter.get().row;
+ ixion::col_t col = iter.get().col;
+ assert(row == 0);
+ assert(col == 0);
+
+ os << " {";
+ os << "\"" << column_labels[col] << "\": ";
+
+ func_str_handler str_handler = [](std::ostream& _os, const std::string& s)
+ {
+ _os << '"' << json::escape_string(s) << '"';
+ };
+
+ func_empty_handler empty_handler = [](std::ostream& _os) { _os << "null"; };
+
+ dump_cell_value(os, cxt, iter.get(), str_handler, empty_handler);
+
+ ixion::row_t last_row = row;
+
+ for (iter.next(); iter.has(); iter.next())
+ {
+ const auto& cell = iter.get();
+ ixion::row_t this_row = cell.row;
+ ixion::col_t this_col = cell.col;
+
+ if (this_row > last_row)
+ os << "}," << std::endl;
+
+ if (this_col == 0)
+ os << " {";
+ else
+ os << ", ";
+
+ os << "\"" << column_labels.at(this_col) << "\": ";
+
+ dump_cell_value(os, cxt, cell, str_handler, empty_handler);
+ last_row = this_row;
+ }
+
+ os << "}" << std::endl << "]" << std::endl;
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/json_dumper.hpp b/src/spreadsheet/json_dumper.hpp
new file mode 100644
index 0000000..a695091
--- /dev/null
+++ b/src/spreadsheet/json_dumper.hpp
@@ -0,0 +1,36 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_JSON_DUMPER_HPP
+#define INCLUDED_ORCUS_JSON_DUMPER_HPP
+
+#include <string>
+#include <ostream>
+
+#include <ixion/types.hpp>
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+
+namespace detail {
+
+class json_dumper
+{
+ const document& m_doc;
+
+public:
+ json_dumper(const document& doc);
+
+ void dump(std::ostream& os, ixion::sheet_t sheet_id) const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/number_format.cpp b/src/spreadsheet/number_format.cpp
new file mode 100644
index 0000000..1823ef0
--- /dev/null
+++ b/src/spreadsheet/number_format.cpp
@@ -0,0 +1,25 @@
+/* -*- 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 "number_format.hpp"
+#include "ostream_utils.hpp"
+
+#include <ostream>
+#include <iomanip>
+#include <limits>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+void format_to_file_output(std::ostream& os, double v)
+{
+ ::orcus::detail::ostream_format_guard guard(os);
+ os << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v;
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/number_format.hpp b/src/spreadsheet/number_format.hpp
new file mode 100644
index 0000000..ea18847
--- /dev/null
+++ b/src/spreadsheet/number_format.hpp
@@ -0,0 +1,28 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_NUMBER_FORMAT_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_NUMBER_FORMAT_HPP
+
+#include <iosfwd>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+/**
+ * Format a numeric value to a lossless string representation appripriate
+ * for file output.
+ *
+ * @param os output stream to add the string representation to.
+ * @param v source numeric value to format.
+ */
+void format_to_file_output(std::ostream& os, double v);
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/pivot.cpp b/src/spreadsheet/pivot.cpp
new file mode 100644
index 0000000..4bc21ee
--- /dev/null
+++ b/src/spreadsheet/pivot.cpp
@@ -0,0 +1,371 @@
+/* -*- 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 "orcus/spreadsheet/pivot.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/string_pool.hpp"
+
+#include <ixion/address.hpp>
+
+#include <unordered_map>
+#include <cassert>
+#include <sstream>
+
+namespace orcus { namespace spreadsheet {
+
+pivot_cache_record_value_t::pivot_cache_record_value_t() :
+ type(record_type::unknown), value(false) {}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(std::string_view s) :
+ type(record_type::character), value(s)
+{
+}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(double v) :
+ type(record_type::numeric), value(v)
+{
+}
+
+pivot_cache_record_value_t::pivot_cache_record_value_t(size_t index) :
+ type(record_type::shared_item_index), value(index)
+{
+}
+
+bool pivot_cache_record_value_t::operator== (const pivot_cache_record_value_t& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool pivot_cache_record_value_t::operator!= (const pivot_cache_record_value_t& other) const
+{
+ return !operator==(other);
+}
+
+pivot_cache_item_t::pivot_cache_item_t() : type(item_type::unknown) {}
+
+pivot_cache_item_t::pivot_cache_item_t(std::string_view s) :
+ type(item_type::character), value(s)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(double numeric) :
+ type(item_type::numeric), value(numeric)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(bool boolean) :
+ type(item_type::boolean), value(boolean)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(const date_time_t& date_time) :
+ type(item_type::date_time), value(date_time)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(error_value_t error) :
+ type(item_type::error), value(error)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(const pivot_cache_item_t& other) :
+ type(other.type), value(other.value)
+{
+}
+
+pivot_cache_item_t::pivot_cache_item_t(pivot_cache_item_t&& other) :
+ type(other.type), value(std::move(other.value))
+{
+ other.type = item_type::unknown;
+ other.value = false;
+}
+
+bool pivot_cache_item_t::operator< (const pivot_cache_item_t& other) const
+{
+ if (type != other.type)
+ return type < other.type;
+
+ return value < other.value;
+}
+
+bool pivot_cache_item_t::operator== (const pivot_cache_item_t& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+pivot_cache_item_t& pivot_cache_item_t::operator= (pivot_cache_item_t other)
+{
+ swap(other);
+ return *this;
+}
+
+void pivot_cache_item_t::swap(pivot_cache_item_t& other)
+{
+ std::swap(type, other.type);
+ std::swap(value, other.value);
+}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(size_t _base_field) :
+ base_field(_base_field) {}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(const pivot_cache_group_data_t& other) :
+ base_to_group_indices(other.base_to_group_indices),
+ range_grouping(other.range_grouping),
+ items(other.items),
+ base_field(other.base_field) {}
+
+pivot_cache_group_data_t::pivot_cache_group_data_t(pivot_cache_group_data_t&& other) :
+ base_to_group_indices(std::move(other.base_to_group_indices)),
+ range_grouping(std::move(other.range_grouping)),
+ items(std::move(other.items)),
+ base_field(other.base_field) {}
+
+pivot_cache_field_t::pivot_cache_field_t() {}
+
+pivot_cache_field_t::pivot_cache_field_t(std::string_view _name) : name(_name) {}
+
+pivot_cache_field_t::pivot_cache_field_t(const pivot_cache_field_t& other) :
+ name(other.name),
+ items(other.items),
+ min_value(other.min_value),
+ max_value(other.max_value),
+ min_date(other.min_date),
+ max_date(other.max_date),
+ group_data(std::make_unique<pivot_cache_group_data_t>(*other.group_data)) {}
+
+pivot_cache_field_t::pivot_cache_field_t(pivot_cache_field_t&& other) :
+ name(other.name),
+ items(std::move(other.items)),
+ min_value(std::move(other.min_value)),
+ max_value(std::move(other.max_value)),
+ min_date(std::move(other.min_date)),
+ max_date(std::move(other.max_date)),
+ group_data(std::move(other.group_data))
+{
+ other.name = std::string_view{};
+}
+
+struct pivot_cache::impl
+{
+ pivot_cache_id_t m_cache_id;
+
+ string_pool& m_string_pool;
+
+ std::string_view m_src_sheet_name;
+
+ pivot_cache::fields_type m_fields;
+
+ pivot_cache::records_type m_records;
+
+ impl(pivot_cache_id_t cache_id, string_pool& sp) :
+ m_cache_id(cache_id), m_string_pool(sp) {}
+};
+
+pivot_cache::pivot_cache(pivot_cache_id_t cache_id, string_pool& sp) :
+ mp_impl(std::make_unique<impl>(cache_id, sp)) {}
+
+pivot_cache::~pivot_cache() {}
+
+void pivot_cache::insert_fields(fields_type fields)
+{
+ mp_impl->m_fields = std::move(fields);
+}
+
+void pivot_cache::insert_records(records_type records)
+{
+ mp_impl->m_records = std::move(records);
+}
+
+size_t pivot_cache::get_field_count() const
+{
+ return mp_impl->m_fields.size();
+}
+
+const pivot_cache_field_t* pivot_cache::get_field(size_t index) const
+{
+ return index < mp_impl->m_fields.size() ? &mp_impl->m_fields[index] : nullptr;
+}
+
+pivot_cache_id_t pivot_cache::get_id() const
+{
+ return mp_impl->m_cache_id;
+}
+
+const pivot_cache::records_type& pivot_cache::get_all_records() const
+{
+ return mp_impl->m_records;
+}
+
+namespace {
+
+constexpr const ixion::sheet_t ignored_sheet = -1;
+
+struct worksheet_range
+{
+ std::string_view sheet; /// it must be an interned string with the document.
+ ixion::abs_range_t range; /// sheet indices are ignored.
+
+ worksheet_range(std::string_view _sheet, ixion::abs_range_t _range) :
+ sheet(std::move(_sheet)), range(std::move(_range))
+ {
+ range.first.sheet = ignored_sheet;
+ range.last.sheet = ignored_sheet;
+ }
+
+ bool operator== (const worksheet_range& other) const
+ {
+ return sheet == other.sheet && range == other.range;
+ }
+
+ struct hash
+ {
+ std::hash<std::string_view> ps_hasher;
+ ixion::abs_range_t::hash range_hasher;
+
+ size_t operator() (const worksheet_range& v) const
+ {
+ assert(v.range.first.sheet == ignored_sheet);
+ assert(v.range.last.sheet == ignored_sheet);
+
+ size_t n = ps_hasher(v.sheet);
+ n ^= range_hasher(v.range);
+ return n;
+ }
+ };
+};
+
+using range_map_type = std::unordered_map<worksheet_range, std::unordered_set<pivot_cache_id_t>, worksheet_range::hash>;
+using name_map_type = std::unordered_map<std::string_view, std::unordered_set<pivot_cache_id_t>>;
+
+using caches_type = std::unordered_map<pivot_cache_id_t, std::unique_ptr<pivot_cache>>;
+
+}
+
+struct pivot_collection::impl
+{
+ document& m_doc;
+
+ range_map_type m_worksheet_range_map; /// mapping of sheet name & range pair to cache ID.
+ name_map_type m_table_map; /// mapping of table name to cache ID.
+
+ caches_type m_caches;
+
+ impl(document& doc) : m_doc(doc) {}
+
+ void ensure_unique_cache(pivot_cache_id_t cache_id)
+ {
+ if (m_caches.count(cache_id) > 0)
+ {
+ std::ostringstream os;
+ os << "Pivot cache with the ID of " << cache_id << " already exists.";
+ throw std::invalid_argument(os.str());
+ }
+ }
+};
+
+pivot_collection::pivot_collection(document& doc) : mp_impl(std::make_unique<impl>(doc)) {}
+
+pivot_collection::~pivot_collection() {}
+
+void pivot_collection::insert_worksheet_cache(
+ std::string_view sheet_name, const ixion::abs_range_t& range,
+ std::unique_ptr<pivot_cache>&& cache)
+{
+ // First, ensure that no caches exist for the cache ID.
+ pivot_cache_id_t cache_id = cache->get_id();
+ mp_impl->ensure_unique_cache(cache_id);
+
+ // Check and see if there is already a cache for this location. If yes,
+ // overwrite the existing cache.
+ mp_impl->m_caches[cache_id] = std::move(cache);
+
+ worksheet_range key(sheet_name, range);
+
+ range_map_type& range_map = mp_impl->m_worksheet_range_map;
+ auto it = range_map.find(key);
+
+ if (it == range_map.end())
+ {
+ // sheet name must be interned with the document it belongs to.
+ key.sheet = mp_impl->m_doc.get_string_pool().intern(key.sheet).first;
+ range_map.insert(range_map_type::value_type(std::move(key), {cache_id}));
+ return;
+ }
+
+ auto& id_set = it->second;
+ id_set.insert(cache_id);
+}
+
+void pivot_collection::insert_worksheet_cache(
+ std::string_view table_name, std::unique_ptr<pivot_cache>&& cache)
+{
+ // First, ensure that no caches exist for the cache ID.
+ pivot_cache_id_t cache_id = cache->get_id();
+ mp_impl->ensure_unique_cache(cache_id);
+
+ mp_impl->m_caches[cache_id] = std::move(cache);
+
+ name_map_type& name_map = mp_impl->m_table_map;
+ auto it = name_map.find(table_name);
+
+ if (it == name_map.end())
+ {
+ // First cache to be associated with this name.
+ std::string_view table_name_interned =
+ mp_impl->m_doc.get_string_pool().intern(table_name).first;
+ name_map.insert(name_map_type::value_type(table_name_interned, {cache_id}));
+ return;
+ }
+
+ auto& id_set = it->second;
+ id_set.insert(cache_id);
+}
+
+size_t pivot_collection::get_cache_count() const
+{
+ return mp_impl->m_caches.size();
+}
+
+const pivot_cache* pivot_collection::get_cache(
+ std::string_view sheet_name, const ixion::abs_range_t& range) const
+{
+ worksheet_range wr(sheet_name, range);
+
+ auto it = mp_impl->m_worksheet_range_map.find(wr);
+ if (it == mp_impl->m_worksheet_range_map.end())
+ return nullptr;
+
+ // Pick the first cache ID.
+ assert(!it->second.empty());
+ pivot_cache_id_t cache_id = *it->second.cbegin();
+ return mp_impl->m_caches[cache_id].get();
+}
+
+namespace {
+
+template<typename _CachesT, typename _CacheT>
+_CacheT* get_cache_impl(_CachesT& caches, pivot_cache_id_t cache_id)
+{
+ auto it = caches.find(cache_id);
+ return it == caches.end() ? nullptr : it->second.get();
+}
+
+}
+
+pivot_cache* pivot_collection::get_cache(pivot_cache_id_t cache_id)
+{
+ return get_cache_impl<caches_type, pivot_cache>(mp_impl->m_caches, cache_id);
+}
+
+const pivot_cache* pivot_collection::get_cache(pivot_cache_id_t cache_id) const
+{
+ return get_cache_impl<const caches_type, const pivot_cache>(mp_impl->m_caches, cache_id);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_formula.cpp b/src/spreadsheet/shared_formula.cpp
new file mode 100644
index 0000000..e17a0ee
--- /dev/null
+++ b/src/spreadsheet/shared_formula.cpp
@@ -0,0 +1,32 @@
+/* -*- 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 "shared_formula.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+shared_formula_pool::shared_formula_pool() {}
+shared_formula_pool::~shared_formula_pool() {}
+
+void shared_formula_pool::add(
+ size_t sf_index, const ixion::formula_tokens_store_ptr_t& sf_tokens)
+{
+ m_store.emplace(sf_index, sf_tokens);
+}
+
+ixion::formula_tokens_store_ptr_t shared_formula_pool::get(size_t sf_index) const
+{
+ auto it = m_store.find(sf_index);
+ if (it == m_store.end())
+ return ixion::formula_tokens_store_ptr_t();
+
+ return it->second;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_formula.hpp b/src/spreadsheet/shared_formula.hpp
new file mode 100644
index 0000000..a72c9f3
--- /dev/null
+++ b/src/spreadsheet/shared_formula.hpp
@@ -0,0 +1,36 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_SHARED_FORMULA_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_SHARED_FORMULA_HPP
+
+#include <ixion/formula_tokens.hpp>
+
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+class shared_formula_pool
+{
+ using store_type = std::unordered_map<size_t, ixion::formula_tokens_store_ptr_t>;
+
+ store_type m_store;
+
+public:
+ shared_formula_pool();
+ ~shared_formula_pool();
+
+ void add(size_t sf_index, const ixion::formula_tokens_store_ptr_t& sf_tokens);
+
+ ixion::formula_tokens_store_ptr_t get(size_t sf_index) const;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/shared_strings.cpp b/src/spreadsheet/shared_strings.cpp
new file mode 100644
index 0000000..f133e50
--- /dev/null
+++ b/src/spreadsheet/shared_strings.cpp
@@ -0,0 +1,61 @@
+/* -*- 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 <orcus/spreadsheet/shared_strings.hpp>
+#include <ixion/model_context.hpp>
+
+#include <iostream>
+#include <algorithm>
+#include <unordered_map>
+
+namespace orcus { namespace spreadsheet {
+
+// format runs for all shared strings, mapped by string IDs.
+using format_runs_map_type = std::unordered_map<size_t, std::unique_ptr<format_runs_t>>;
+
+struct shared_strings::impl
+{
+ ixion::model_context& context;
+
+ /**
+ * Container for all format runs of all formatted strings. Format runs
+ * are mapped with the string IDs.
+ */
+ format_runs_map_type formats;
+
+ impl(ixion::model_context& cxt) : context(cxt) {}
+};
+
+shared_strings::shared_strings(ixion::model_context& cxt) : mp_impl(std::make_unique<impl>(cxt)) {}
+
+shared_strings::~shared_strings() = default;
+
+void shared_strings::set_format_runs(std::size_t sindex, std::unique_ptr<format_runs_t> runs)
+{
+ mp_impl->formats.insert_or_assign(sindex, std::move(runs));
+}
+
+const format_runs_t* shared_strings::get_format_runs(std::size_t index) const
+{
+ auto it = mp_impl->formats.find(index);
+ if (it != mp_impl->formats.end())
+ return it->second.get();
+ return nullptr;
+}
+
+const std::string* shared_strings::get_string(std::size_t index) const
+{
+ return mp_impl->context.get_string(index);
+}
+
+void shared_strings::dump(std::ostream& os) const
+{
+ os << "number of shared strings: " << mp_impl->context.get_string_count() << std::endl;
+}
+
+}}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet.cpp b/src/spreadsheet/sheet.cpp
new file mode 100644
index 0000000..4ffa8df
--- /dev/null
+++ b/src/spreadsheet/sheet.cpp
@@ -0,0 +1,555 @@
+/* -*- 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 "orcus/spreadsheet/sheet.hpp"
+#include "orcus/spreadsheet/document.hpp"
+#include "orcus/exception.hpp"
+
+#include "json_dumper.hpp"
+#include "check_dumper.hpp"
+#include "csv_dumper.hpp"
+#include "flat_dumper.hpp"
+#include "html_dumper.hpp"
+#include "sheet_impl.hpp"
+#include "debug_state_dumper.hpp"
+
+#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <cassert>
+#include <cstdlib>
+
+#include <ixion/exceptions.hpp>
+#include <ixion/formula.hpp>
+#include <ixion/model_context.hpp>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/gregorian/greg_date.hpp>
+
+#include "filesystem_env.hpp"
+
+#define ORCUS_DEBUG_SHEET 0
+
+using namespace std;
+namespace gregorian = boost::gregorian;
+namespace posix_time = boost::posix_time;
+
+namespace orcus { namespace spreadsheet {
+
+namespace {
+
+ixion::abs_range_t to_ixion_range(sheet_t sheet, const range_t& range)
+{
+ ixion::abs_range_t pos;
+
+ pos.first.sheet = sheet;
+ pos.first.row = range.first.row;
+ pos.first.column = range.first.column;
+ pos.last.sheet = sheet;
+ pos.last.row = range.last.row;
+ pos.last.column = range.last.column;
+
+ return pos;
+}
+
+}
+
+const row_t sheet::max_row_limit = 1048575;
+const col_t sheet::max_col_limit = 1023;
+
+sheet::sheet(document& doc, sheet_t sheet_index) :
+ mp_impl(std::make_unique<detail::sheet_impl>(doc, *this, sheet_index)) {}
+
+sheet::~sheet() noexcept
+{
+}
+
+void sheet::set_auto(row_t row, col_t col, std::string_view s)
+{
+ if (s.empty())
+ return;
+
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ // First, see if this can be parsed as a number.
+ char* endptr = nullptr;
+ double val = strtod(s.data(), &endptr);
+ const char* endptr_check = s.data() + s.size();
+ if (endptr == endptr_check)
+ // Treat this as a numeric value.
+ cxt.set_numeric_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), val);
+ else
+ // Treat this as a string value.
+ cxt.set_string_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), s);
+}
+
+void sheet::set_string(row_t row, col_t col, string_id_t sindex)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_string_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), sindex);
+
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_string: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; si=" << sindex << endl;
+#endif
+}
+
+void sheet::set_value(row_t row, col_t col, double value)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_numeric_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), value);
+}
+
+void sheet::set_bool(row_t row, col_t col, bool value)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ cxt.set_boolean_cell(ixion::abs_address_t(mp_impl->sheet_id,row,col), value);
+}
+
+void sheet::set_date_time(row_t row, col_t col, int year, int month, int day, int hour, int minute, double second)
+{
+ // Convert this to a double value representing days since epoch.
+
+ date_time_t dt_origin = mp_impl->doc.get_origin_date();
+
+ gregorian::date origin(dt_origin.year, dt_origin.month, dt_origin.day);
+ gregorian::date d(year, month, day);
+
+ double days_since_epoch = (d - origin).days();
+
+ long ms = second * 1000000.0;
+
+ posix_time::time_duration t(
+ posix_time::hours(hour) +
+ posix_time::minutes(minute) +
+ posix_time::microseconds(ms)
+ );
+
+ double time_as_day = t.total_microseconds();
+ time_as_day /= 1000000.0; // microseconds to seconds
+ time_as_day /= 60.0 * 60.0 * 24.0; // seconds to day
+
+ set_value(row, col, days_since_epoch + time_as_day);
+}
+
+void sheet::set_format(row_t row, col_t col, size_t index)
+{
+ set_format(row, col, row, col, index);
+}
+
+void sheet::set_format(row_t row_start, col_t col_start, row_t row_end, col_t col_end, size_t index)
+{
+ for (col_t col = col_start; col <= col_end; ++col)
+ {
+ auto itr = mp_impl->cell_formats.find(col);
+ if (itr == mp_impl->cell_formats.end())
+ {
+ auto p = std::make_unique<detail::segment_row_index_type>(0, mp_impl->doc.get_sheet_size().rows, 0);
+ auto r = mp_impl->cell_formats.emplace(col, std::move(p));
+
+ if (!r.second)
+ {
+ cerr << "insertion of new cell format container failed!" << endl;
+ return;
+ }
+
+ itr = r.first;
+ }
+
+ detail::segment_row_index_type& con = *itr->second;
+ con.insert_back(row_start, row_end+1, index);
+ }
+}
+
+void sheet::set_column_format(col_t col, col_t col_span, std::size_t index)
+{
+ if (col_span > 0)
+ mp_impl->column_formats.insert_back(col, col + col_span, index);
+}
+
+void sheet::set_row_format(row_t row, std::size_t index)
+{
+ mp_impl->row_formats.insert_back(row, row+1, index);
+}
+
+void sheet::set_formula(row_t row, col_t col, const ixion::formula_tokens_store_ptr_t& tokens)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t pos(mp_impl->sheet_id, row, col);
+
+ cxt.set_formula_cell(pos, tokens);
+ try
+ {
+ ixion::register_formula_cell(cxt, pos);
+ mp_impl->doc.insert_dirty_cell(pos);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_formula(
+ row_t row, col_t col, const ixion::formula_tokens_store_ptr_t& tokens,
+ ixion::formula_result result)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t pos(mp_impl->sheet_id, row, col);
+
+ cxt.set_formula_cell(pos, tokens, result);
+
+ try
+ {
+ ixion::register_formula_cell(cxt, pos);
+ mp_impl->doc.insert_dirty_cell(pos);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; row=" << row << "; col=" << col << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_grouped_formula(const range_t& range, ixion::formula_tokens_t tokens)
+{
+ ixion::abs_range_t pos = to_ixion_range(mp_impl->sheet_id, range);
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ cxt.set_grouped_formula_cells(pos, std::move(tokens));
+ try
+ {
+ ixion::register_formula_cell(cxt, pos.first);
+ mp_impl->doc.insert_dirty_cell(pos.first);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; range=" << range << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_grouped_formula(const range_t& range, ixion::formula_tokens_t tokens, ixion::formula_result result)
+{
+ ixion::abs_range_t pos = to_ixion_range(mp_impl->sheet_id, range);
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ cxt.set_grouped_formula_cells(pos, std::move(tokens), std::move(result));
+ try
+ {
+ ixion::register_formula_cell(cxt, pos.first);
+ mp_impl->doc.insert_dirty_cell(pos.first);
+ }
+ catch ([[maybe_unused]] const ixion::formula_registration_error& e)
+ {
+#if ORCUS_DEBUG_SHEET
+ cout << "sheet::set_formula: sheet=" << mp_impl->sheet_id << "; range=" << range << "; e=" << e.what() << endl;
+#endif
+ }
+}
+
+void sheet::set_col_width(col_t col, col_t col_span, col_width_t width)
+{
+ mp_impl->col_width_pos =
+ mp_impl->col_widths.insert(mp_impl->col_width_pos, col, col+col_span, width).first;
+}
+
+col_width_t sheet::get_col_width(col_t col, col_t* col_start, col_t* col_end) const
+{
+ detail::col_widths_store_type& col_widths = mp_impl->col_widths;
+ if (!col_widths.is_tree_valid())
+ col_widths.build_tree();
+
+ col_width_t ret = 0;
+ if (!col_widths.search_tree(col, ret, col_start, col_end).second)
+ throw orcus::general_error("sheet::get_col_width: failed to search tree.");
+
+ return ret;
+}
+
+void sheet::set_col_hidden(col_t col, col_t col_span, bool hidden)
+{
+ mp_impl->col_hidden_pos =
+ mp_impl->col_hidden.insert(mp_impl->col_hidden_pos, col, col+col_span, hidden).first;
+}
+
+bool sheet::is_col_hidden(col_t col, col_t* col_start, col_t* col_end) const
+{
+ detail::col_hidden_store_type& col_hidden = mp_impl->col_hidden;
+ if (!col_hidden.is_tree_valid())
+ col_hidden.build_tree();
+
+ bool hidden = false;
+ if (!col_hidden.search_tree(col, hidden, col_start, col_end).second)
+ throw orcus::general_error("sheet::is_col_hidden: failed to search tree.");
+
+ return hidden;
+}
+
+void sheet::set_row_height(row_t row, row_height_t height)
+{
+ mp_impl->row_height_pos =
+ mp_impl->row_heights.insert(mp_impl->row_height_pos, row, row+1, height).first;
+}
+
+row_height_t sheet::get_row_height(row_t row, row_t* row_start, row_t* row_end) const
+{
+ detail::row_heights_store_type& row_heights = mp_impl->row_heights;
+ if (!row_heights.is_tree_valid())
+ row_heights.build_tree();
+
+ row_height_t ret = 0;
+ if (!row_heights.search_tree(row, ret, row_start, row_end).second)
+ throw orcus::general_error("sheet::get_row_height: failed to search tree.");
+
+ return ret;
+}
+
+void sheet::set_row_hidden(row_t row, bool hidden)
+{
+ mp_impl->row_hidden_pos =
+ mp_impl->row_hidden.insert(mp_impl->row_hidden_pos, row, row+1, hidden).first;
+}
+
+bool sheet::is_row_hidden(row_t row, row_t* row_start, row_t* row_end) const
+{
+ detail::row_hidden_store_type& row_hidden = mp_impl->row_hidden;
+ if (!row_hidden.is_tree_valid())
+ row_hidden.build_tree();
+
+ bool hidden = false;
+ if (!row_hidden.search_tree(row, hidden, row_start, row_end).second)
+ throw orcus::general_error("sheet::is_row_hidden: failed to search tree.");
+
+ return hidden;
+}
+
+void sheet::set_merge_cell_range(const range_t& range)
+{
+ detail::col_merge_size_type::iterator it_col = mp_impl->merge_ranges.find(range.first.column);
+ if (it_col == mp_impl->merge_ranges.end())
+ {
+ auto p = std::make_unique<detail::merge_size_type>();
+ pair<detail::col_merge_size_type::iterator, bool> r =
+ mp_impl->merge_ranges.insert(
+ detail::col_merge_size_type::value_type(range.first.column, std::move(p)));
+
+ if (!r.second)
+ // Insertion failed.
+ return;
+
+ it_col = r.first;
+ }
+
+ detail::merge_size_type& col_data = *it_col->second;
+ detail::merge_size sz(range.last.column-range.first.column+1, range.last.row-range.first.row+1);
+ col_data.insert(
+ detail::merge_size_type::value_type(range.first.row, sz));
+}
+
+void sheet::fill_down_cells(row_t src_row, col_t src_col, row_t range_size)
+{
+ ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ ixion::abs_address_t src_pos(mp_impl->sheet_id, src_row, src_col);
+ cxt.fill_down_cells(src_pos, range_size);
+}
+
+range_t sheet::get_merge_cell_range(row_t row, col_t col) const
+{
+ range_t ret;
+ ret.first.column = col;
+ ret.first.row = row;
+ ret.last.column = col;
+ ret.last.row = row;
+
+ detail::col_merge_size_type::const_iterator it_col = mp_impl->merge_ranges.find(col);
+ if (it_col == mp_impl->merge_ranges.end())
+ return ret; // not a merged cell
+
+ const detail::merge_size_type& col_data = *it_col->second;
+ detail::merge_size_type::const_iterator it = col_data.find(row);
+ if (it == col_data.end())
+ return ret; // not a merged cell
+
+ const detail::merge_size& ms = it->second;
+ ret.last.column += ms.width - 1;
+ ret.last.row += ms.height - 1;
+
+ return ret;
+}
+
+size_t sheet::get_string_identifier(row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = mp_impl->doc.get_model_context();
+ return cxt.get_string_identifier(ixion::abs_address_t(mp_impl->sheet_id, row, col));
+}
+
+auto_filter_t* sheet::get_auto_filter_data()
+{
+ return mp_impl->auto_filter_data.get();
+}
+
+const auto_filter_t* sheet::get_auto_filter_data() const
+{
+ return mp_impl->auto_filter_data.get();
+}
+
+void sheet::set_auto_filter_data(auto_filter_t* p)
+{
+ mp_impl->auto_filter_data.reset(p);
+}
+
+ixion::abs_range_t sheet::get_data_range() const
+{
+ return mp_impl->get_data_range();
+}
+
+sheet_t sheet::get_index() const
+{
+ return mp_impl->sheet_id;
+}
+
+date_time_t sheet::get_date_time(row_t row, col_t col) const
+{
+ const ixion::model_context& cxt = mp_impl->doc.get_model_context();
+
+ // raw value as days since epoch.
+ double dt_raw = cxt.get_numeric_value(
+ ixion::abs_address_t(mp_impl->sheet_id, row, col));
+
+ double days_since_epoch = std::floor(dt_raw);
+ double time_fraction = dt_raw - days_since_epoch;
+
+ date_time_t dt_origin = mp_impl->doc.get_origin_date();
+
+ posix_time::ptime origin(
+ gregorian::date(
+ gregorian::greg_year(dt_origin.year),
+ gregorian::greg_month(dt_origin.month),
+ gregorian::greg_day(dt_origin.day)
+ )
+ );
+
+ posix_time::ptime date_part = origin + gregorian::days(days_since_epoch);
+
+ long hours = 0;
+ long minutes = 0;
+ double seconds = 0.0;
+
+ if (time_fraction)
+ {
+ // Convert a fraction day to microseconds.
+ long long ms = time_fraction * 24.0 * 60.0 * 60.0 * 1000000.0;
+ posix_time::time_duration td = posix_time::microsec(ms);
+
+ hours = td.hours();
+ minutes = td.minutes();
+ seconds = td.seconds(); // long to double
+
+ td -= posix_time::hours(hours);
+ td -= posix_time::minutes(minutes);
+ td -= posix_time::seconds((long)seconds);
+
+ ms = td.total_microseconds(); // remaining microseconds.
+
+ seconds += ms / 1000000.0;
+ }
+
+ gregorian::date d = date_part.date();
+
+ return date_time_t(d.year(), d.month(), d.day(), hours, minutes, seconds);
+}
+
+void sheet::finalize_import()
+{
+ mp_impl->col_widths.build_tree();
+ mp_impl->row_heights.build_tree();
+}
+
+void sheet::dump_flat(std::ostream& os) const
+{
+ detail::flat_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_check(ostream& os, std::string_view sheet_name) const
+{
+ detail::check_dumper dumper(*mp_impl, sheet_name);
+ dumper.dump(os);
+}
+
+void sheet::dump_html(std::ostream& os) const
+{
+ if (!mp_impl->col_widths.is_tree_valid())
+ mp_impl->col_widths.build_tree();
+
+ if (!mp_impl->row_heights.is_tree_valid())
+ mp_impl->row_heights.build_tree();
+
+ detail::html_dumper dumper(mp_impl->doc, mp_impl->merge_ranges, mp_impl->sheet_id);
+ dumper.dump(os);
+}
+
+void sheet::dump_json(std::ostream& os) const
+{
+ detail::json_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_csv(std::ostream& os) const
+{
+ detail::csv_dumper dumper(mp_impl->doc);
+ dumper.dump(os, mp_impl->sheet_id);
+}
+
+void sheet::dump_debug_state(const std::string& output_dir, std::string_view sheet_name) const
+{
+ fs::path outdir{output_dir};
+ detail::sheet_debug_state_dumper dumper(*mp_impl, sheet_name);
+ dumper.dump(outdir);
+}
+
+size_t sheet::get_cell_format(row_t row, col_t col) const
+{
+ // Check the cell format store first
+ auto it = mp_impl->cell_formats.find(col);
+ if (it != mp_impl->cell_formats.end())
+ {
+ detail::segment_row_index_type& con = *it->second;
+ if (!con.is_tree_valid())
+ con.build_tree();
+
+ // Return only if the index is not a default index
+ std::size_t index;
+ if (con.search_tree(row, index).second && index)
+ return index;
+ }
+
+ // Not found in the cell format store. Check the row store.
+ if (!mp_impl->row_formats.is_tree_valid())
+ mp_impl->row_formats.build_tree();
+
+ std::size_t index;
+ if (mp_impl->row_formats.search_tree(row, index).second && index)
+ return index;
+
+ // Not found in the row store. Check the column store.
+ if (!mp_impl->column_formats.is_tree_valid())
+ mp_impl->column_formats.build_tree();
+
+ if (mp_impl->column_formats.search_tree(col, index).second && index)
+ return index;
+
+ // Not found. Return the default format index.
+ return 0;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet_impl.cpp b/src/spreadsheet/sheet_impl.cpp
new file mode 100644
index 0000000..1364e25
--- /dev/null
+++ b/src/spreadsheet/sheet_impl.cpp
@@ -0,0 +1,53 @@
+/* -*- 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 "sheet_impl.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <ixion/model_context.hpp>
+
+namespace orcus { namespace spreadsheet { namespace detail {
+
+sheet_impl::sheet_impl(document& _doc, sheet& /*sh*/, sheet_t sheet_index) :
+ doc(_doc),
+ col_widths(0, doc.get_sheet_size().columns, get_default_column_width()),
+ row_heights(0, doc.get_sheet_size().rows, get_default_row_height()),
+ col_width_pos(col_widths.begin()),
+ row_height_pos(row_heights.begin()),
+ col_hidden(0, doc.get_sheet_size().columns, false),
+ row_hidden(0, doc.get_sheet_size().rows, false),
+ col_hidden_pos(col_hidden.begin()),
+ row_hidden_pos(row_hidden.begin()),
+ column_formats(0, doc.get_sheet_size().columns, 0),
+ row_formats(0, doc.get_sheet_size().rows, 0),
+ sheet_id(sheet_index) {}
+
+sheet_impl::~sheet_impl() {}
+
+const detail::merge_size* sheet_impl::get_merge_size(row_t row, col_t col) const
+{
+ detail::col_merge_size_type::const_iterator it_col = merge_ranges.find(col);
+ if (it_col == merge_ranges.end())
+ return nullptr;
+
+ detail::merge_size_type& col_merge_sizes = *it_col->second;
+ detail::merge_size_type::const_iterator it_row = col_merge_sizes.find(row);
+ if (it_row == col_merge_sizes.end())
+ return nullptr;
+
+ return &it_row->second;
+}
+
+ixion::abs_range_t sheet_impl::get_data_range() const
+{
+ const ixion::model_context& cxt = doc.get_model_context();
+ return cxt.get_data_range(sheet_id);
+}
+
+}}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/sheet_impl.hpp b/src/spreadsheet/sheet_impl.hpp
new file mode 100644
index 0000000..11f691a
--- /dev/null
+++ b/src/spreadsheet/sheet_impl.hpp
@@ -0,0 +1,72 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_ORCUS_SPREADSHEET_SHEET_IMPL_HPP
+#define INCLUDED_ORCUS_SPREADSHEET_SHEET_IMPL_HPP
+
+#include "impl_types.hpp"
+#include "orcus/spreadsheet/auto_filter.hpp"
+
+namespace orcus { namespace spreadsheet {
+
+class document;
+class sheet;
+
+namespace detail {
+
+using segment_row_index_type = mdds::flat_segment_tree<row_t, std::size_t>;
+using segment_col_index_type = mdds::flat_segment_tree<col_t, std::size_t>;
+typedef std::unordered_map<col_t, std::unique_ptr<segment_row_index_type>> cell_format_type;
+
+// Widths and heights are stored in twips.
+typedef mdds::flat_segment_tree<col_t, col_width_t> col_widths_store_type;
+typedef mdds::flat_segment_tree<row_t, row_height_t> row_heights_store_type;
+
+// hidden information
+typedef mdds::flat_segment_tree<col_t, bool> col_hidden_store_type;
+typedef mdds::flat_segment_tree<row_t, bool> row_hidden_store_type;
+
+struct sheet_impl
+{
+ document& doc;
+
+ mutable col_widths_store_type col_widths;
+ mutable row_heights_store_type row_heights;
+ col_widths_store_type::const_iterator col_width_pos;
+ row_heights_store_type::const_iterator row_height_pos;
+
+ mutable col_hidden_store_type col_hidden;
+ mutable row_hidden_store_type row_hidden;
+ col_hidden_store_type::const_iterator col_hidden_pos;
+ row_hidden_store_type::const_iterator row_hidden_pos;
+
+ detail::col_merge_size_type merge_ranges; /// 2-dimensional merged cell ranges.
+
+ std::unique_ptr<auto_filter_t> auto_filter_data;
+
+ cell_format_type cell_formats;
+ segment_col_index_type column_formats;
+ segment_row_index_type row_formats;
+ const sheet_t sheet_id;
+
+ sheet_impl() = delete;
+ sheet_impl(const sheet_impl&) = delete;
+ sheet_impl& operator=(const sheet_impl&) = delete;
+
+ sheet_impl(document& _doc, sheet& sh, sheet_t sheet_index);
+ ~sheet_impl();
+
+ const detail::merge_size* get_merge_size(row_t row, col_t col) const;
+
+ ixion::abs_range_t get_data_range() const;
+};
+
+}}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/styles.cpp b/src/spreadsheet/styles.cpp
new file mode 100644
index 0000000..328814e
--- /dev/null
+++ b/src/spreadsheet/styles.cpp
@@ -0,0 +1,485 @@
+/* -*- 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 "orcus/spreadsheet/styles.hpp"
+#include "orcus/string_pool.hpp"
+
+#include "ostream_utils.hpp"
+
+#include <functional>
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+#include <vector>
+#include <map>
+
+namespace orcus { namespace spreadsheet {
+
+font_t::font_t() = default;
+font_t::font_t(const font_t& other) = default;
+font_t::~font_t() = default;
+
+font_t& font_t::operator=(const font_t& other) = default;
+
+bool font_t::operator==(const font_t& other) const
+{
+ if (name != other.name)
+ return false;
+
+ if (name_asian != other.name_asian)
+ return false;
+
+ if (name_complex != other.name_complex)
+ return false;
+
+ if (size != other.size)
+ return false;
+
+ if (size_asian != other.size_asian)
+ return false;
+
+ if (size_complex != other.size_complex)
+ return false;
+
+ if (bold != other.bold)
+ return false;
+
+ if (bold_asian != other.bold_asian)
+ return false;
+
+ if (bold_complex != other.bold_complex)
+ return false;
+
+ if (italic != other.italic)
+ return false;
+
+ if (italic_asian != other.italic_asian)
+ return false;
+
+ if (italic_complex != other.italic_complex)
+ return false;
+
+ if (underline_style != other.underline_style)
+ return false;
+
+ if (underline_width != other.underline_width)
+ return false;
+
+ if (underline_mode != other.underline_mode)
+ return false;
+
+ if (underline_type != other.underline_type)
+ return false;
+
+ if (underline_color != other.underline_color)
+ return false;
+
+ if (color != other.color)
+ return false;
+
+ if (strikethrough_style != other.strikethrough_style)
+ return false;
+
+ if (strikethrough_width != other.strikethrough_width)
+ return false;
+
+ if (strikethrough_type != other.strikethrough_type)
+ return false;
+
+ if (strikethrough_text != other.strikethrough_text)
+ return false;
+
+ return true;
+}
+
+bool font_t::operator!=(const font_t& other) const
+{
+ return !operator==(other);
+}
+
+void font_t::reset()
+{
+ *this = font_t();
+}
+
+std::size_t font_t::hash::operator()(const font_t& v) const
+{
+ std::size_t hash_value = 0u;
+
+ if (v.name)
+ hash_value |= std::hash<std::string_view>{}(*v.name);
+
+ if (v.size)
+ hash_value |= std::hash<double>{}(*v.size);
+
+ if (v.bold)
+ hash_value |= std::hash<bool>{}(*v.bold);
+
+ if (v.italic)
+ hash_value |= std::hash<bool>{}(*v.italic);
+
+ return hash_value;
+}
+
+fill_t::fill_t() = default;
+
+void fill_t::reset()
+{
+ *this = fill_t();
+}
+
+border_attrs_t::border_attrs_t() = default;
+
+void border_attrs_t::reset()
+{
+ *this = border_attrs_t();
+}
+
+border_t::border_t() = default;
+
+void border_t::reset()
+{
+ *this = border_t();
+}
+
+protection_t::protection_t() = default;
+
+void protection_t::reset()
+{
+ *this = protection_t();
+}
+
+number_format_t::number_format_t() = default;
+
+void number_format_t::reset()
+{
+ *this = number_format_t();
+}
+
+bool number_format_t::operator== (const number_format_t& other) const noexcept
+{
+ return identifier == other.identifier && format_string == other.format_string;
+}
+
+bool number_format_t::operator!= (const number_format_t& other) const noexcept
+{
+ return !operator== (other);
+}
+
+cell_format_t::cell_format_t() :
+ font(0),
+ fill(0),
+ border(0),
+ protection(0),
+ number_format(0),
+ style_xf(0),
+ hor_align(hor_alignment_t::unknown),
+ ver_align(ver_alignment_t::unknown),
+ apply_num_format(false),
+ apply_font(false),
+ apply_fill(false),
+ apply_border(false),
+ apply_alignment(false),
+ apply_protection(false)
+{
+}
+
+void cell_format_t::reset()
+{
+ *this = cell_format_t();
+}
+
+cell_style_t::cell_style_t() :
+ xf(0), builtin(0)
+{
+}
+
+void cell_style_t::reset()
+{
+ *this = cell_style_t();
+}
+
+std::ostream& operator<< (std::ostream& os, const color_t& c)
+{
+ ::orcus::detail::ostream_format_guard ifs(os);
+
+ os << std::uppercase;
+
+ os << "(ARGB:"
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.alpha & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.red & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.green & 0xFF)
+ << ' ' << std::hex << std::setfill('0') << std::setw(2) << int(c.blue & 0xFF)
+ << ")";
+
+ return os;
+}
+
+struct styles::impl
+{
+ std::vector<font_t> fonts;
+ std::vector<fill_t> fills;
+ std::vector<border_t> borders;
+ std::vector<protection_t> protections;
+ std::vector<number_format_t> number_formats;
+ std::vector<cell_format_t> cell_style_formats;
+ std::vector<cell_format_t> cell_formats;
+ std::vector<cell_format_t> dxf_formats;
+ std::vector<cell_style_t> cell_styles;
+ std::map<std::size_t, std::size_t> cell_styles_map; // style xf to style position in `cell_styles`
+
+ string_pool str_pool;
+};
+
+styles::styles() : mp_impl(std::make_unique<impl>()) {}
+styles::~styles() {}
+
+void styles::reserve_font_store(size_t n)
+{
+ mp_impl->fonts.reserve(n);
+}
+
+std::size_t styles::append_font(const font_t& font)
+{
+ mp_impl->fonts.emplace_back(font);
+ return mp_impl->fonts.size() - 1;
+}
+
+void styles::reserve_fill_store(size_t n)
+{
+ mp_impl->fills.reserve(n);
+}
+
+std::size_t styles::append_fill(const fill_t& fill)
+{
+ mp_impl->fills.emplace_back(fill);
+ return mp_impl->fills.size() - 1;
+}
+
+void styles::reserve_border_store(size_t n)
+{
+ mp_impl->borders.reserve(n);
+}
+
+std::size_t styles::append_border(const border_t& border)
+{
+ mp_impl->borders.emplace_back(border);
+ return mp_impl->borders.size() - 1;
+}
+
+std::size_t styles::append_protection(const protection_t& protection)
+{
+ mp_impl->protections.emplace_back(protection);
+ return mp_impl->protections.size() - 1;
+}
+
+void styles::reserve_number_format_store(size_t n)
+{
+ mp_impl->number_formats.reserve(n);
+}
+
+std::size_t styles::append_number_format(const number_format_t& nf)
+{
+ if (nf.format_string)
+ {
+ number_format_t copied = nf;
+ copied.format_string = mp_impl->str_pool.intern(*nf.format_string).first;
+ mp_impl->number_formats.emplace_back(copied);
+ }
+ else
+ mp_impl->number_formats.emplace_back(nf);
+
+ return mp_impl->number_formats.size() - 1;
+}
+
+void styles::reserve_cell_style_format_store(size_t n)
+{
+ mp_impl->cell_style_formats.reserve(n);
+}
+
+size_t styles::append_cell_style_format(const cell_format_t& cf)
+{
+ mp_impl->cell_style_formats.push_back(cf);
+ return mp_impl->cell_style_formats.size() - 1;
+}
+
+void styles::reserve_cell_format_store(size_t n)
+{
+ mp_impl->cell_formats.reserve(n);
+}
+
+size_t styles::append_cell_format(const cell_format_t& cf)
+{
+ mp_impl->cell_formats.push_back(cf);
+ return mp_impl->cell_formats.size() - 1;
+}
+
+void styles::reserve_diff_cell_format_store(size_t n)
+{
+ mp_impl->dxf_formats.reserve(n);
+}
+
+size_t styles::append_diff_cell_format(const cell_format_t& cf)
+{
+ mp_impl->dxf_formats.push_back(cf);
+ return mp_impl->dxf_formats.size() - 1;
+}
+
+void styles::reserve_cell_style_store(size_t n)
+{
+ mp_impl->cell_styles.reserve(n);
+}
+
+void styles::append_cell_style(const cell_style_t& cs)
+{
+ mp_impl->cell_styles.push_back(cs);
+}
+
+const font_t* styles::get_font(size_t index) const
+{
+ if (index >= mp_impl->fonts.size())
+ return nullptr;
+
+ return &mp_impl->fonts[index];
+}
+
+const cell_format_t* styles::get_cell_format(size_t index) const
+{
+ if (index >= mp_impl->cell_formats.size())
+ return nullptr;
+
+ return &mp_impl->cell_formats[index];
+}
+
+const fill_t* styles::get_fill(size_t index) const
+{
+ if (index >= mp_impl->fills.size())
+ return nullptr;
+
+ return &mp_impl->fills[index];
+}
+
+const border_t* styles::get_border(size_t index) const
+{
+ if (index >= mp_impl->borders.size())
+ return nullptr;
+
+ return &mp_impl->borders[index];
+}
+
+const protection_t* styles::get_protection(size_t index) const
+{
+ if (index >= mp_impl->protections.size())
+ return nullptr;
+
+ return &mp_impl->protections[index];
+}
+
+const number_format_t* styles::get_number_format(size_t index) const
+{
+ if (index >= mp_impl->number_formats.size())
+ return nullptr;
+
+ return &mp_impl->number_formats[index];
+}
+
+const cell_format_t* styles::get_cell_style_format(size_t index) const
+{
+ if (index >= mp_impl->cell_style_formats.size())
+ return nullptr;
+
+ return &mp_impl->cell_style_formats[index];
+}
+
+const cell_format_t* styles::get_dxf_format(size_t index) const
+{
+ if (index >= mp_impl->dxf_formats.size())
+ return nullptr;
+
+ return &mp_impl->dxf_formats[index];
+}
+
+const cell_style_t* styles::get_cell_style(size_t index) const
+{
+ if (index >= mp_impl->cell_styles.size())
+ return nullptr;
+
+ return &mp_impl->cell_styles[index];
+}
+
+const cell_style_t* styles::get_cell_style_by_xf(size_t xfid) const
+{
+ auto it = mp_impl->cell_styles_map.find(xfid);
+ if (it == mp_impl->cell_styles_map.end())
+ return nullptr;
+
+ auto index = it->second;
+ return &mp_impl->cell_styles[index];
+}
+
+size_t styles::get_font_count() const
+{
+ return mp_impl->fonts.size();
+}
+
+size_t styles::get_fill_count() const
+{
+ return mp_impl->fills.size();
+}
+
+size_t styles::get_border_count() const
+{
+ return mp_impl->borders.size();
+}
+
+size_t styles::get_protection_count() const
+{
+ return mp_impl->protections.size();
+}
+
+size_t styles::get_number_format_count() const
+{
+ return mp_impl->number_formats.size();
+}
+
+size_t styles::get_cell_formats_count() const
+{
+ return mp_impl->cell_formats.size();
+}
+
+size_t styles::get_cell_style_formats_count() const
+{
+ return mp_impl->cell_style_formats.size();
+}
+
+size_t styles::get_dxf_count() const
+{
+ return mp_impl->dxf_formats.size();
+}
+
+size_t styles::get_cell_styles_count() const
+{
+ return mp_impl->cell_styles.size();
+}
+
+void styles::clear()
+{
+ mp_impl = std::make_unique<impl>();
+}
+
+void styles::finalize_import()
+{
+ for (std::size_t i = 0; i < mp_impl->cell_styles.size(); ++i)
+ {
+ const auto& entry = mp_impl->cell_styles[i];
+ mp_impl->cell_styles_map.insert_or_assign(entry.xf, i);
+ }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/spreadsheet/view.cpp b/src/spreadsheet/view.cpp
new file mode 100644
index 0000000..7e21fff
--- /dev/null
+++ b/src/spreadsheet/view.cpp
@@ -0,0 +1,201 @@
+/* -*- 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 "orcus/spreadsheet/view.hpp"
+#include "orcus/spreadsheet/document.hpp"
+
+#include <cassert>
+#include <iostream>
+
+namespace orcus { namespace spreadsheet {
+
+struct view::impl
+{
+ document& m_doc;
+
+ std::vector<std::unique_ptr<sheet_view>> m_sheet_views;
+ sheet_t m_active_sheet;
+
+ impl(document& doc) : m_doc(doc), m_active_sheet(0) {}
+};
+
+view::view(document& doc) : mp_impl(std::make_unique<impl>(doc)) {}
+view::~view() {}
+
+sheet_view* view::get_or_create_sheet_view(sheet_t sheet)
+{
+ if (sheet < 0)
+ return nullptr;
+
+ sheet_t n = mp_impl->m_doc.get_sheet_count();
+ if (sheet >= n)
+ return nullptr;
+
+ // Make sure the container is large enough for the requested sheet view index.
+ n = mp_impl->m_sheet_views.size();
+ if (sheet >= n)
+ mp_impl->m_sheet_views.resize(sheet+1);
+
+ if (!mp_impl->m_sheet_views[sheet])
+ mp_impl->m_sheet_views[sheet] = std::make_unique<sheet_view>(*this);
+
+ return mp_impl->m_sheet_views[sheet].get();
+}
+
+const sheet_view* view::get_sheet_view(sheet_t sheet) const
+{
+ if (sheet < 0)
+ return nullptr;
+
+ sheet_t n = mp_impl->m_doc.get_sheet_count();
+ if (sheet >= n)
+ return nullptr;
+
+ n = mp_impl->m_sheet_views.size();
+ if (sheet >= n)
+ return nullptr;
+
+ assert(mp_impl->m_sheet_views[sheet]);
+ return mp_impl->m_sheet_views[sheet].get();
+}
+
+void view::set_active_sheet(sheet_t sheet)
+{
+ mp_impl->m_active_sheet = sheet;
+}
+
+sheet_t view::get_active_sheet() const
+{
+ return mp_impl->m_active_sheet;
+}
+
+namespace {
+
+/**
+ * Stores all data for a single sheet pane.
+ */
+struct sheet_pane_data
+{
+ range_t m_selection;
+
+ sheet_pane_data()
+ {
+ m_selection.first.row = -1;
+ m_selection.first.column = -1;
+ m_selection.last = m_selection.first;
+ }
+};
+
+size_t to_pane_index(sheet_pane_t pos)
+{
+ switch (pos)
+ {
+ case sheet_pane_t::top_left:
+ return 0;
+ case sheet_pane_t::top_right:
+ return 1;
+ case sheet_pane_t::bottom_left:
+ return 2;
+ case sheet_pane_t::bottom_right:
+ return 3;
+ case sheet_pane_t::unspecified:
+ default:
+ throw std::runtime_error("invalid sheet pane.");
+ }
+}
+
+} // anonymous namespace
+
+struct sheet_view::impl
+{
+ view& m_doc_view;
+ sheet_pane_data m_panes[4];
+ sheet_pane_t m_active_pane;
+ split_pane_t m_split_pane;
+ frozen_pane_t m_frozen_pane;
+
+ sheet_pane_data& get_pane(sheet_pane_t pos)
+ {
+ return m_panes[to_pane_index(pos)];
+ }
+
+ const sheet_pane_data& get_pane(sheet_pane_t pos) const
+ {
+ return m_panes[to_pane_index(pos)];
+ }
+
+ impl(view& doc_view) : m_doc_view(doc_view), m_active_pane(sheet_pane_t::top_left)
+ {
+ m_split_pane.hor_split = 0.0;
+ m_split_pane.ver_split = 0.0;
+ m_split_pane.top_left_cell.row = -1;
+ m_split_pane.top_left_cell.column = -1;
+ m_frozen_pane.visible_columns = 0;
+ m_frozen_pane.visible_rows = 0;
+ m_frozen_pane.top_left_cell.row = -1;
+ m_frozen_pane.top_left_cell.column = -1;
+ }
+};
+
+sheet_view::sheet_view(view& doc_view) : mp_impl(std::make_unique<impl>(doc_view)) {}
+sheet_view::~sheet_view() {}
+
+const range_t& sheet_view::get_selection(sheet_pane_t pos) const
+{
+ const sheet_pane_data& pd = mp_impl->get_pane(pos);
+ return pd.m_selection;
+}
+
+void sheet_view::set_selection(sheet_pane_t pos, const range_t& range)
+{
+ sheet_pane_data& pd = mp_impl->get_pane(pos);
+ pd.m_selection = range;
+}
+
+void sheet_view::set_active_pane(sheet_pane_t pos)
+{
+ mp_impl->m_active_pane = pos;
+}
+
+sheet_pane_t sheet_view::get_active_pane() const
+{
+ return mp_impl->m_active_pane;
+}
+
+void sheet_view::set_split_pane(
+ double hor_split, double ver_split, const address_t& top_left_cell)
+{
+ mp_impl->m_split_pane.hor_split = hor_split;
+ mp_impl->m_split_pane.ver_split = ver_split;
+ mp_impl->m_split_pane.top_left_cell = top_left_cell;
+}
+
+const split_pane_t& sheet_view::get_split_pane() const
+{
+ return mp_impl->m_split_pane;
+}
+
+void sheet_view::set_frozen_pane(col_t visible_cols, row_t visible_rows, const address_t& top_left_cell)
+{
+ mp_impl->m_frozen_pane.visible_columns = visible_cols;
+ mp_impl->m_frozen_pane.visible_rows = visible_rows;
+ mp_impl->m_frozen_pane.top_left_cell = top_left_cell;
+}
+
+const frozen_pane_t& sheet_view::get_frozen_pane() const
+{
+ return mp_impl->m_frozen_pane;
+}
+
+view& sheet_view::get_document_view()
+{
+ return mp_impl->m_doc_view;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */