diff --git a/lib/elixlsx/compiler.ex b/lib/elixlsx/compiler.ex index 397059b..f523b47 100644 --- a/lib/elixlsx/compiler.ex +++ b/lib/elixlsx/compiler.ex @@ -52,6 +52,21 @@ defmodule Elixlsx.Compiler do end end + def compinfo_col_pass_style(wci, %{width: w} = props) when props == %{width: w}, do: wci + + def compinfo_col_pass_style wci, props do + update_in wci.cellstyledb, + &CellStyleDB.register_style(&1, + Elixlsx.Style.CellStyle.from_props(props)) + end + + @spec compinfo_from_cols(WorkbookCompInfo.t, list(list(any()))) :: WorkbookCompInfo.t + def compinfo_from_cols wci, cols do + Enum.sort(cols) + |> List.foldl(wci, fn ({_, props}, wci) -> + compinfo_col_pass_style(wci, props) + end) + end @spec compinfo_from_rows(WorkbookCompInfo.t, list(list(any()))) :: WorkbookCompInfo.t def compinfo_from_rows wci, rows do @@ -65,7 +80,9 @@ defmodule Elixlsx.Compiler do @spec compinfo_from_sheets(WorkbookCompInfo.t, list(Sheet.t)) :: WorkbookCompInfo.t def compinfo_from_sheets wci, sheets do List.foldl sheets, wci, fn (sheet, wci) -> - compinfo_from_rows wci, sheet.rows + wci + |> compinfo_from_rows(sheet.rows) + |> compinfo_from_cols(sheet.cols) end end diff --git a/lib/elixlsx/sheet.ex b/lib/elixlsx/sheet.ex index f0b265b..1a683ea 100644 --- a/lib/elixlsx/sheet.ex +++ b/lib/elixlsx/sheet.ex @@ -16,11 +16,11 @@ defmodule Elixlsx.Sheet do The property list describes formatting options for that cell. See Font.from_props/1 for a list of options. """ - defstruct name: "", rows: [], col_widths: %{}, row_heights: %{}, merge_cells: [], pane_freeze: nil, show_grid_lines: true + defstruct name: "", rows: [], cols: %{}, row_heights: %{}, merge_cells: [], pane_freeze: nil, show_grid_lines: true @type t :: %Sheet { name: String.t, rows: list(list(any())), - col_widths: %{pos_integer => number}, + cols: %{pos_integer => map}, row_heights: %{pos_integer => number}, merge_cells: [], pane_freeze: {number, number} | nil, @@ -121,14 +121,35 @@ defmodule Elixlsx.Sheet do end end + @spec set_col(Sheet.t, String.t, Keyword.t) :: Sheet.t + @doc ~S""" + Set various attributes for a given column. Column is indexed by + name ("A", ...) + """ + def set_col(sheet, column, [{k, v}]) do + index = Util.decode_col(column) + cols = Map.update(sheet.cols, index, %{k => v}, (&Map.put &1, k, v)) + Map.put(sheet, :cols, cols) + end + + def set_col(sheet, column, opts) do + index = Util.decode_col(column) + + cols = + Enum.reduce(opts, sheet.cols, fn {k, v}, acc -> + Map.update(acc, index, %{k => v}, &Map.put(&1, k, v)) + end) + + Map.put(sheet, :cols, cols) + end + @spec set_col_width(Sheet.t, String.t, number) :: Sheet.t @doc ~S""" Set the column width for a given column. Column is indexed by name ("A", ...) """ def set_col_width(sheet, column, width) do - update_in sheet.col_widths, - &(Map.put &1, Util.decode_col(column), width) + set_col(sheet, column, width: width) end @spec set_row_height(Sheet.t, number, number) :: Sheet.t diff --git a/lib/elixlsx/xml_templates.ex b/lib/elixlsx/xml_templates.ex index 79c59eb..7156566 100644 --- a/lib/elixlsx/xml_templates.ex +++ b/lib/elixlsx/xml_templates.ex @@ -272,20 +272,44 @@ defmodule Elixlsx.XMLTemplates do end end - defp make_col_width({k, v}) do - '' - end - - defp make_col_widths(sheet) do - if Kernel.map_size(sheet.col_widths) != 0 do - cols = Map.to_list(sheet.col_widths) - |> Enum.sort - |> Enum.map_join(&make_col_width/1) - - "#{cols}" - else - "" - end + defp make_col_range(key) do + key_str = Integer.to_string(key) + [" min=\"", key_str, "\" max=\"", key_str, "\""] + end + + defp make_col_style(props, _) when props == %{}, do: [] + defp make_col_style(%{width: w} = props, _) when props == %{width: w}, do: [] + defp make_col_style(props, wci) do + style_id = CellStyleDB.get_id(wci.cellstyledb, CellStyle.from_props(props)) + [" style=\"", Integer.to_string(style_id), "\""] + end + + defp make_col_width(%{width: width}) when is_integer(width) do + [" width=\"", Integer.to_string(width), "\" customWidth=\"1\""] + end + defp make_col_width(%{width: width}) when is_float(width) do + [" width=\"", Float.to_string(width), "\" customWidth=\"1\""] + end + defp make_col_width(_), do: [] + + defp make_cols(%{cols: cols}, _) when cols == %{}, do: "" + defp make_cols(%{cols: cols}, wci) do + [ + "", + Map.to_list(cols) + |> Enum.sort() + |> Enum.map(fn {key, props} -> [ + "" + ] + end), + "" + ] + # remove to output as iolist instead of string + |> Enum.join() end @spec make_sheet(Sheet.t, WorkbookCompInfo.t) :: String.t @@ -313,7 +337,7 @@ defmodule Elixlsx.XMLTemplates do """ - <> make_col_widths(sheet) <> + <> make_cols(sheet, wci) <> """ """ diff --git a/test/sheet_test.exs b/test/sheet_test.exs new file mode 100644 index 0000000..010278f --- /dev/null +++ b/test/sheet_test.exs @@ -0,0 +1,22 @@ +defmodule Elixlsx.SheetTest do + use ExUnit.Case, async: false + use ExCheck + + alias Elixlsx.Sheet + + property :sheet_name do + for_all x in binary() do + Sheet.with_name(x).name == x + end + end + + property :sheet_cols do + for_all x in choose(65,90) do + sheet = + %Sheet{} + |> Sheet.set_col_width(<>, 10) + |> Sheet.set_col(<>, bg_color: "#FFFF00", num_format: "mmm-yyyy") + sheet.cols[x - 64] == %{bg_color: "#FFFF00", num_format: "mmm-yyyy", width: 10} + end + end +end diff --git a/test/xml_templates_test.exs b/test/xml_templates_test.exs new file mode 100644 index 0000000..b123ea9 --- /dev/null +++ b/test/xml_templates_test.exs @@ -0,0 +1,25 @@ +defmodule Elixlsx.XMLTemplatesTest do + use ExUnit.Case + + alias Elixlsx.{Compiler, Compiler.WorkbookCompInfo, Sheet, Workbook, XMLTemplates} + + describe("make_sheet") do + setup do + [sheet: Sheet.with_name("Sheet1"), wci: %WorkbookCompInfo{}, workbook: %Workbook{}] + end + + test "with default values", %{sheet: sheet, wci: wci} do + assert XMLTemplates.make_sheet(sheet, wci) =~ "" + end + + test "with column attrs set", %{sheet: sheet, workbook: workbook} do + sheet = sheet + |> Sheet.set_col_width("A", 10) + |> Sheet.set_col("B", bg_color: "#FFFF00", num_format: "mmm-yyyy", width: 12) + wci = Compiler.make_workbook_comp_info(Workbook.insert_sheet(workbook, sheet)) + xml = XMLTemplates.make_sheet(sheet, wci) + assert xml =~ "" + assert xml =~ "" + end + end +end