Skip to content

Commit

Permalink
Bumped to version 1.4.0 : added row-styling (font/colour)
Browse files Browse the repository at this point in the history
  • Loading branch information
mjul committed Jul 20, 2010
1 parent 9e051bb commit ceb48f6
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 12 deletions.
2 changes: 1 addition & 1 deletion project.clj
@@ -1,4 +1,4 @@
(defproject dk.ative/docjure "1.3.1"
(defproject dk.ative/docjure "1.4.0"
:description "Easily read and write Office documents from Clojure."
:url "http://github.com/ative/docjure"
:dependencies [[org.clojure/clojure "1.1.0"]
Expand Down
102 changes: 93 additions & 9 deletions src/dk/ative/docjure/spreadsheet.clj
Expand Up @@ -3,7 +3,8 @@
(java.io FileOutputStream FileInputStream)
(java.util Date Calendar)
(org.apache.poi.xssf.usermodel XSSFWorkbook)
(org.apache.poi.ss.usermodel Workbook Sheet Cell Row WorkbookFactory DateUtil)
(org.apache.poi.ss.usermodel Workbook Sheet Cell Row WorkbookFactory DateUtil
IndexedColors CellStyle Font)
(org.apache.poi.ss.util CellReference)))

(defmacro assert-type [value expected-type]
Expand Down Expand Up @@ -58,18 +59,30 @@
first))

(defn row-seq
"Return a sequence of the rows in a sheet."
"Return a lazy sequence of the rows in a sheet."
[#^Sheet sheet]
(assert-type sheet Sheet)
(iterator-seq (.iterator sheet)))

(defn cell-seq
"Return a seq of the cells in one or more sheets, ordered by row and column."
[#^Sheet sheet-or-coll]
(for [sheet (if (seq? sheet-or-coll) sheet-or-coll (list sheet-or-coll))
row (row-seq sheet)
cell (iterator-seq (.iterator row))]
cell))
(defn- cell-seq-dispatch [x]
(cond
(isa? (class x) Row) :row
(isa? (class x) Sheet) :sheet
(seq? x) :coll
:else :default))

(defmulti cell-seq
"Return a seq of the cells in the input which can be a sheet, a row, or a collection
of one of these. The seq is ordered ordered by sheet, row and column."
cell-seq-dispatch)
(defmethod cell-seq :row [row] (iterator-seq (.iterator row)))
(defmethod cell-seq :sheet [sheet] (for [row (row-seq sheet)
cell (cell-seq row)]
cell))
(defmethod cell-seq :coll [coll] (for [x coll,
cell (cell-seq x)]
cell))


(defn into-seq
[sheet-or-row]
Expand Down Expand Up @@ -164,3 +177,74 @@
(add-rows! sheet data)
workbook))

(defn create-font!
"Create a new font in the workbook.
Options are
:bold true/false bold or normal font
Example:
(create-font! wb {:bold true})
"
[#^Workbook workbook options]
(let [defaults {:bold false}
cfg (merge defaults options)]
(assert-type workbook Workbook)
(let [f (.createFont workbook)]
(doto f
(.setBoldweight (if (:bold cfg) Font/BOLDWEIGHT_BOLD Font/BOLDWEIGHT_NORMAL)))
f)))


(defn create-cell-style!
"Create a new cell-style.
Options is a map with the cell style configuration:
:background the name of the background colour (as keyword)
Valid keywords are the colour names defined in
org.apache.ss.usermodel.IndexedColors as lowercase keywords, eg.
:black, :white, :red, :blue, :green, :yellow, ...
Example:
(create-cell-style! wb {:background :yellow})
"
([#^Workbook workbook] (create-cell-style! workbook {}))

([#^Workbook workbook styles]
(assert-type workbook Workbook)
(let [cs (.createCellStyle workbook)
{background :background, font-style :font} styles
font (create-font! workbook font-style)]
(do
(.setFont cs font)
(when background
(let [bg-idx (.getIndex (IndexedColors/valueOf
(.toUpperCase (name background))))]
(.setFillForegroundColor cs bg-idx)
(.setFillPattern cs CellStyle/SOLID_FOREGROUND)))
cs))))

(defn set-cell-style!
"Apply a style to a cell.
See also: create-cell-style!.
"
[#^Cell cell #^CellStyle style]
(assert-type cell Cell)
(assert-type style CellStyle)
(.setCellStyle cell style)
cell)

(defn set-row-style!
"Apply a style to all the cells in a row.
Returns the row."
[#^Row row #^CellStyle style]
(assert-type row Row)
(assert-type style CellStyle)
(dorun (map #(.setCellStyle % style) (cell-seq row)))
row)

96 changes: 94 additions & 2 deletions test/dk/ative/docjure/spreadsheet_test.clj
@@ -1,7 +1,7 @@
(ns dk.ative.docjure.spreadsheet-test
(:use [dk.ative.docjure.spreadsheet] :reload-all)
(:use [clojure.test])
(:import (org.apache.poi.ss.usermodel Workbook Sheet Cell Row)
(:import (org.apache.poi.ss.usermodel Workbook Sheet Cell Row CellStyle IndexedColors Font)
(org.apache.poi.xssf.usermodel XSSFWorkbook)
(java.util Date)))

Expand Down Expand Up @@ -92,6 +92,42 @@
(testing "Should fail on invalid type"
(is (thrown-with-msg? IllegalArgumentException #"workbook.*" (sheet-seq "not-a-workbook"))))))

(deftest row-seq-test
(let [sheet-name "Sheet 1"
sheet-data [["A1" "B1"] ["A2" "B2"]]
workbook (create-workbook sheet-name sheet-data)
sheet (select-sheet sheet-name workbook)]
(testing "Sheet"
(let [actual (row-seq sheet)]
(is (= 2 (count actual)))))))

(deftest cell-seq-test
(let [sheet-name "Sheet 1"
sheet-data [["A1" "B1"] ["A2" "B2"]]
workbook (create-workbook sheet-name sheet-data)
sheet (select-sheet sheet-name workbook)]
(testing "for sheet"
(let [actual (cell-seq sheet)]
(is (= 4 (count actual)))))
(testing "for row"
(let [actual (cell-seq (first (row-seq sheet)))]
(is (= 2 (count actual)) "Expected correct number of cells.")
(is (= "A1" (read-cell (first actual))))
(is (= "B1" (read-cell (second actual))))))
(testing "for row collection"
(let [actual (cell-seq (row-seq sheet))]
(is (= 4 (count actual)) "Expected to get all cells.")
(is (= ["A1" "B1" "A2" "B2"] (map read-cell actual)))))
(testing "for sheet collection"
(let [sheet2 (add-sheet! workbook "Sheet 2")]
(do (add-rows! sheet2 [["S2/A1" "S2/B1"] ["S2/A2" "S2/B2"]]))
(let [actual (cell-seq (sheet-seq workbook))]
(is (= ["A1" "B1"
"A2" "B2"
"S2/A1" "S2/B1"
"S2/A2" "S2/B2"] (map read-cell actual))))))))


(deftest sheet-name-test
(let [name "Sheet 1"
data [["foo" "bar"]]
Expand Down Expand Up @@ -146,11 +182,66 @@
(testing "Should fail on invalid parameter types."
(is (thrown-with-msg? IllegalArgumentException #"sheet.*" (row-seq "not-a-sheet")))))


(deftest save-workbook!-test
(testing "Should fail on invalid parameter types."
(is (thrown-with-msg? IllegalArgumentException #"workbook.*" (save-workbook! "filename.xlsx" "not-a-workbook")))))

(deftest create-cell-style!-test
(testing "Should create a cell style based on the options"
(testing ":background"
(let [wb (create-workbook "Dummy" [["foo"]])]
(let [cs (create-cell-style! wb)]
(is (= CellStyle/NO_FILL (.getFillPattern cs)))
(is (= Font/BOLDWEIGHT_NORMAL (.. cs getFont getBoldweight))))
(let [cs (create-cell-style! wb {:background :yellow})]
(is (= CellStyle/SOLID_FOREGROUND (.getFillPattern cs)))
(is (= (.getIndex IndexedColors/YELLOW) (.getFillForegroundColor cs))))))
(testing ":font"
(let [wb (create-workbook "Dummy" [["fonts"]])
cs (create-cell-style! wb {:font {:bold true}})]
(is (= Font/BOLDWEIGHT_BOLD (.. cs getFont getBoldweight)))))))

(deftest create-font!-test
(let [wb (create-workbook "Dummy" [["foo"]])]
(testing "Should create font based on options."
(let [f-default (create-font! wb {})
f-not-bold (create-font! wb {:bold false})
f-bold (create-font! wb {:bold true})]
(is (= Font/BOLDWEIGHT_NORMAL (.getBoldweight f-default)))
(is (= Font/BOLDWEIGHT_NORMAL (.getBoldweight f-not-bold)))
(is (= Font/BOLDWEIGHT_BOLD (.getBoldweight f-bold)))))
(is (thrown-with-msg? IllegalArgumentException #"^workbook.*"
(create-font! "not-a-workbook" {})))))


(deftest set-cell-style!-test
(testing "Should apply style to cell."
(let [wb (create-workbook "Dummy" [["foo"]])
cs (create-cell-style! wb {:background :yellow})
cell (-> (sheet-seq wb) first cell-seq first)]
(do
(is (= cell (set-cell-style! cell cs)))
(is (= (.getCellStyle cell) cs))))))


(deftest set-row-style!-test
(testing "Should apply style to all cells in row."
(let [wb (create-workbook "Dummy" [["foo" "bar"] ["data b" "data b"]])
cs (create-cell-style! wb {:background :yellow})
rs (row-seq (select-sheet "Dummy" wb))
[header-row, data-row] rs
[a1, b1] (cell-seq header-row)
[a2, b2] (cell-seq data-row)]
(do (set-row-style! header-row cs))
(is (= (.getIndex IndexedColors/YELLOW) (.. a1 getCellStyle getFillForegroundColor)))
(is (= (.getIndex IndexedColors/YELLOW) (.. b1 getCellStyle getFillForegroundColor)))
(is (not= (.getIndex IndexedColors/YELLOW) (.. a2 getCellStyle getFillForegroundColor)))
(is (not= (.getIndex IndexedColors/YELLOW) (.. b2 getCellStyle getFillForegroundColor)))
)))

;; ----------------------------------------------------------------
;; Integration tests
;; ----------------------------------------------------------------

(deftest load-workbook-integration-test
(let [file (config :datatypes-file)
Expand Down Expand Up @@ -187,3 +278,4 @@
(is (every? number? (datatypes-data file :fraction)))
(is (every? number? (datatypes-data file :scientific))))))


0 comments on commit ceb48f6

Please sign in to comment.