OpenDocument writer: New table cell support with row and column spans (#6682)

Unit tests only verify column spans at this point.

Co-authored-by: Nils Carlson <nils.carlson@ludd.ltu.se>
This commit is contained in:
Nils Carlson 2020-09-24 16:31:47 +00:00 committed by GitHub
parent 1f707da40f
commit 4f13c0e25e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 213 additions and 26 deletions

View file

@ -32,11 +32,12 @@ import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.DocLayout
import Text.Pandoc.Shared (linesToPara, tshow)
import Text.Pandoc.Shared (linesToPara, tshow, blocksToInlines)
import Text.Pandoc.Templates (renderTemplate)
import qualified Text.Pandoc.Translations as Term (Term(Figure, Table))
import Text.Pandoc.Writers.Math
import Text.Pandoc.Writers.Shared
import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
import Text.Pandoc.XML
import Text.Printf (printf)
@ -371,9 +372,7 @@ blockToOpenDocument o bs
| BulletList b <- bs = setFirstPara >> bulletListToOpenDocument o b
| OrderedList a b <- bs = setFirstPara >> orderedList a b
| CodeBlock _ s <- bs = setFirstPara >> preformatted s
| Table _ bc s th tb tf
<- bs = let (c, a, w, h, r) = toLegacyTable bc s th tb tf
in setFirstPara >> table c a w h r
| Table a bc s th tb tf <- bs = setFirstPara >> table (Ann.toTable a bc s th tb tf)
| HorizontalRule <- bs = setFirstPara >> return (selfClosingTag "text:p"
[ ("text:style-name", "Horizontal_20_Line") ])
| RawBlock f s <- bs = if f == Format "opendocument"
@ -396,29 +395,32 @@ blockToOpenDocument o bs
orderedList a b = do (ln,pn) <- newOrderedListStyle (isTightList b) a
inTags True "text:list" [ ("text:style-name", "L" <> tshow ln)]
<$> orderedListToOpenDocument o pn b
table c a w h r = do
table :: PandocMonad m => Ann.Table -> OD m (Doc Text)
table (Ann.Table _ (Caption _ c) colspecs thead tbodies _) = do
tn <- length <$> gets stTableStyles
pn <- length <$> gets stParaStyles
let genIds = map chr [65..]
name = "Table" <> tshow (tn + 1)
columnIds = zip genIds w
(aligns, mwidths) = unzip colspecs
fromWidth (ColWidth w) | w > 0 = w
fromWidth _ = 0
widths = map fromWidth mwidths
columnIds = zip genIds widths
mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name <> "." <> T.singleton (fst n))]
columns = map mkColumn columnIds
paraHStyles = paraTableStyles "Heading" pn a
paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) a
paraHStyles = paraTableStyles "Heading" pn aligns
paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) aligns
newPara = map snd . filter (not . isEmpty . snd)
addTableStyle $ tableStyle tn columnIds
mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
captionDoc <- if null c
then return empty
else inlinesToOpenDocument o c >>=
else inlinesToOpenDocument o (blocksToInlines c) >>=
if isEnabled Ext_native_numbering o
then numberedTableCaption
else unNumberedCaption "TableCaption"
th <- if all null h
then return empty
else colHeadsToOpenDocument o (map fst paraHStyles) h
tr <- mapM (tableRowToOpenDocument o (map fst paraStyles)) r
th <- colHeadsToOpenDocument o (map fst paraHStyles) thead
tr <- mapM (tableBodyToOpenDocument o (map fst paraStyles)) tbodies
let tableDoc = inTags True "table:table" [
("table:name" , name)
, ("table:style-name", name)
@ -464,26 +466,54 @@ unNumberedCaption :: Monad m => Text -> Doc Text -> OD m (Doc Text)
unNumberedCaption style caption = return $ inParagraphTagsWithStyle style caption
colHeadsToOpenDocument :: PandocMonad m
=> WriterOptions -> [Text] -> [[Block]]
=> WriterOptions -> [Text] -> Ann.TableHead
-> OD m (Doc Text)
colHeadsToOpenDocument o ns hs =
inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns hs)
colHeadsToOpenDocument o ns (Ann.TableHead _ hs) =
case hs of
[] -> return empty
(x:_) ->
let (Ann.HeaderRow _ _ c) = x
in inTagsIndented "table:table-header-rows" .
inTagsIndented "table:table-row" .
vcat <$> mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns c)
tableBodyToOpenDocument:: PandocMonad m
=> WriterOptions -> [Text] -> Ann.TableBody
-> OD m (Doc Text)
tableBodyToOpenDocument o ns tb =
let (Ann.TableBody _ _ _ r) = tb
in vcat <$> mapM (tableRowToOpenDocument o ns) r
tableRowToOpenDocument :: PandocMonad m
=> WriterOptions -> [Text] -> [[Block]]
=> WriterOptions -> [Text] -> Ann.BodyRow
-> OD m (Doc Text)
tableRowToOpenDocument o ns cs =
inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o "TableRowCell") (zip ns cs)
tableRowToOpenDocument o ns r =
let (Ann.BodyRow _ _ _ c ) = r
in inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o "TableRowCell") (zip ns c)
colspanAttrib :: ColSpan -> [(Text, Text)]
colspanAttrib cs =
case cs of
ColSpan 1 -> mempty
ColSpan n -> [("table:number-columns-spanned", tshow n)]
rowspanAttrib :: RowSpan -> [(Text, Text)]
rowspanAttrib rs =
case rs of
RowSpan 1 -> mempty
RowSpan n -> [("table:number-rows-spanned", tshow n)]
tableItemToOpenDocument :: PandocMonad m
=> WriterOptions -> Text -> (Text,[Block])
=> WriterOptions -> Text -> (Text,Ann.Cell)
-> OD m (Doc Text)
tableItemToOpenDocument o s (n,i) =
let a = [ ("table:style-name" , s )
, ("office:value-type", "string" )
]
tableItemToOpenDocument o s (n,c) =
let (Ann.Cell _colspecs _colnum (Cell _ _ rs cs i) ) = c
csa = colspanAttrib cs
rsa = rowspanAttrib rs
a = [ ("table:style-name" , s )
, ("office:value-type", "string" ) ] ++ csa ++ rsa
in inTags True "table:table-cell" a <$>
withParagraphStyle o n (map plainToPara i)

View file

@ -117,3 +117,160 @@
(TableFoot ("",[],[])
[])]
```
```
% pandoc -f native -t opendocument --quiet
[Table ("",[],[]) (Caption Nothing
[])
[(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)
,(AlignDefault,ColWidth 6.25e-2)]
(TableHead ("",[],[])
[])
[(TableBody ("",[],[]) (RowHeadColumns 0)
[]
[Row ("",[],[])
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
[Para [Strong [Str "Octet",Space,Str "no.",Space,Str "1"]]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
[Para [Strong [Str "Octet",Space,Str "no.",Space,Str "2"]]]]
,Row ("",[],[])
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "16"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "15"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "14"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "13"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "12"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "11"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "10"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "9"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "8"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "7"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "6"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "5"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "4"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "3"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "2"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
[Para [Str "1"]]]
,Row ("",[],[])
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
[Para [Str "Code",Space,Str "A"]]
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
[Para [Str "Code",Space,Str "B"]]]])]
(TableFoot ("",[],[])
[])]
^D
<table:table table:name="Table1" table:style-name="Table1">
<table:table-column table:style-name="Table1.A" />
<table:table-column table:style-name="Table1.B" />
<table:table-column table:style-name="Table1.C" />
<table:table-column table:style-name="Table1.D" />
<table:table-column table:style-name="Table1.E" />
<table:table-column table:style-name="Table1.F" />
<table:table-column table:style-name="Table1.G" />
<table:table-column table:style-name="Table1.H" />
<table:table-column table:style-name="Table1.I" />
<table:table-column table:style-name="Table1.J" />
<table:table-column table:style-name="Table1.K" />
<table:table-column table:style-name="Table1.L" />
<table:table-column table:style-name="Table1.M" />
<table:table-column table:style-name="Table1.N" />
<table:table-column table:style-name="Table1.O" />
<table:table-column table:style-name="Table1.P" />
<table:table-row>
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
<text:p text:style-name="Table_20_Contents"><text:span text:style-name="T1">Octet
no. 1</text:span></text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
<text:p text:style-name="Table_20_Contents"><text:span text:style-name="T1">Octet
no. 2</text:span></text:p>
</table:table-cell>
</table:table-row>
<table:table-row>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">16</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">15</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">14</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">13</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">12</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">11</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">10</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">9</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">8</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">7</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">6</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">5</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">4</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">3</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">2</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
<text:p text:style-name="Table_20_Contents">1</text:p>
</table:table-cell>
</table:table-row>
<table:table-row>
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
<text:p text:style-name="Table_20_Contents">Code A</text:p>
</table:table-cell>
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
<text:p text:style-name="Table_20_Contents">Code B</text:p>
</table:table-cell>
</table:table-row>
</table:table>
```